diff --git a/DEPS b/DEPS
index c8ba4e1..b6687daf 100644
--- a/DEPS
+++ b/DEPS
@@ -209,7 +209,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'cc6492ba9cb4acac75d60bc6eb6c7f3bc58e41e1',
+  'skia_revision': 'e14d72500fc74a2de02571759898c71ca03957fe',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -221,7 +221,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '7093777bceb168c5e7bd5565d628cefd94925214',
+  'angle_revision': '81401be2a035471e394cd2014ba90791c1102cf0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -280,7 +280,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'ab687ea7be643e0f78176a60f3797aae7fbbae46',
+  'catapult_revision': '8680ff0509220fb0a4b85d0878fd6f80eae3ae8d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -288,7 +288,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '124fb1d9e61c41066b850acafe77e899225d56ec',
+  'devtools_frontend_revision': '9646971c47066c84b2fa6254a94838bdfe786bc6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -328,7 +328,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'edb79bafba1f894a2f342df85a5da3b4bd40af58',
+  'dawn_revision': 'faea7f78414e21abe84cc072409f358d02a47ee6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -727,7 +727,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'elLOzilYbu3vB2mpMZzZsC0i9QukqoU9miZ_PUmpeE8C',
+          'version': 'DkjJyAndtE7UV7h5rNQdFWztxKvMiWIhS0cXGk4pS-UC',
       },
     ],
     'condition': 'checkout_android',
@@ -943,7 +943,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'e7d7f088b0a6f015e03e7ba135171a63a1286941',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '0baac7b5ee9766e19979bf724e9289dca4fd3188',
       'condition': 'checkout_chromeos',
   },
 
@@ -1335,7 +1335,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '9511660f9320b7dea169f39d88d81f4457886325',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '1b78913ea7b1a4c3a3447f6b183e4be62a01e7e3',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1413,7 +1413,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': '_EJXYI9PIL6jmQi9nGYfsMiQZf2CFqi_hE7uUCqpScAC'
+              'version': '3LqGeo5KWUbxoMWPc5T6Gs_Iql4roUq5CBjDHf82hwQC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1549,7 +1549,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'c8e9a0e3d56fb25793de46c02c30b748c167e031',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '10aaa3f1e7fed9ece132673f61d92c1f9838afbb',
+    Var('webrtc_git') + '/src.git' + '@' + '5051693ada61bc7b78855c6fb3fa87a0394fa813',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1621,7 +1621,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@10eb4056e2fb2cafdf7cd6720058c93c07505c13',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@5bc06e467a66812bbe8e87ad7dd6cded028f631f',
     'condition': 'checkout_src_internal',
   },
 
@@ -1640,7 +1640,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'f8V001Y0t2VUHcXIylrAFBib_E_7X3JDt7o3Bw7sEv0C',
+        'version': 'BLuvlt1JfirI7_Tx00r05lvHul5c__hlkLLdYF_HRpEC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1651,7 +1651,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'v_9io-HYlF1rrJWGZC8BtQCp4SY3XVu6KN719WOy8DoC',
+        'version': 'SM47MrZkSW-FTfUynase6ItgAbs7qswfBHp680hNf64C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/utility/layer_util_unittest.cc b/ash/utility/layer_util_unittest.cc
index 6aa21a02..a88204f 100644
--- a/ash/utility/layer_util_unittest.cc
+++ b/ash/utility/layer_util_unittest.cc
@@ -86,7 +86,7 @@
     CopyLayerContentToLayer(&layer1, cancelable.callback());
 
     GenerateOneFrame();
-    Advance(base::TimeDelta::FromMilliseconds(16));
+    Advance(base::TimeDelta::FromMilliseconds(1000));
     EXPECT_TRUE(called);
   }
 
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc
index 881ec95..4c6d650 100644
--- a/base/json/json_writer.cc
+++ b/base/json/json_writer.cc
@@ -11,6 +11,7 @@
 
 #include "base/json/string_escape.h"
 #include "base/logging.h"
+#include "base/notreached.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -192,15 +193,9 @@
       // Successful only if we're allowed to omit it.
       DLOG_IF(ERROR, !omit_binary_values_) << "Cannot serialize binary value.";
       return omit_binary_values_;
-
-    // TODO(crbug.com/859477): Remove after root cause is found.
-    case Value::Type::DEAD:
-      CHECK(false);
-      return false;
   }
 
-  // TODO(crbug.com/859477): Revert to NOTREACHED() after root cause is found.
-  CHECK(false);
+  NOTREACHED();
   return false;
 }
 
diff --git a/base/message_loop/message_pump_fuchsia.cc b/base/message_loop/message_pump_fuchsia.cc
index d8bda87..5e08189 100644
--- a/base/message_loop/message_pump_fuchsia.cc
+++ b/base/message_loop/message_pump_fuchsia.cc
@@ -9,8 +9,7 @@
 #include <lib/fdio/io.h>
 #include <lib/fdio/unsafe.h>
 #include <lib/zx/time.h>
-#include <zircon/status.h>
-#include <zircon/syscalls.h>
+#include <zircon/errors.h>
 
 #include "base/auto_reset.h"
 #include "base/fuchsia/fuchsia_logging.h"
diff --git a/base/message_loop/message_pump_fuchsia.h b/base/message_loop/message_pump_fuchsia.h
index d494a4f0..ca3bfcf 100644
--- a/base/message_loop/message_pump_fuchsia.h
+++ b/base/message_loop/message_pump_fuchsia.h
@@ -32,7 +32,7 @@
                                      zx_signals_t signals) = 0;
 
    protected:
-    virtual ~ZxHandleWatcher() {}
+    virtual ~ZxHandleWatcher() = default;
   };
 
   // Manages an active watch on an zx_handle_t.
diff --git a/base/power_monitor/power_monitor_unittest.cc b/base/power_monitor/power_monitor_unittest.cc
index f668001..b932748 100644
--- a/base/power_monitor/power_monitor_unittest.cc
+++ b/base/power_monitor/power_monitor_unittest.cc
@@ -5,6 +5,7 @@
 #include "base/power_monitor/power_monitor.h"
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "base/test/power_monitor_test_base.h"
 #include "base/test/task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -15,19 +16,15 @@
  protected:
   PowerMonitorTest() = default;
 
-  void TearDown() override { PowerMonitor::ShutdownForTesting(); }
+  void PowerMonitorInitialize() { power_monitor_source_.emplace(); }
 
-  void PowerMonitorInitialize() {
-    power_monitor_source_ = new PowerMonitorTestSource();
-    PowerMonitor::Initialize(
-        std::unique_ptr<PowerMonitorSource>(power_monitor_source_));
+  test::ScopedPowerMonitorTestSource& source() {
+    return power_monitor_source_.value();
   }
 
-  PowerMonitorTestSource* source() { return power_monitor_source_; }
-
  private:
   test::TaskEnvironment task_environment_;
-  PowerMonitorTestSource* power_monitor_source_;
+  base::Optional<test::ScopedPowerMonitorTestSource> power_monitor_source_;
 
   DISALLOW_COPY_AND_ASSIGN(PowerMonitorTest);
 };
@@ -47,61 +44,61 @@
   }
 
   // Sending resume when not suspended should have no effect.
-  source()->GenerateResumeEvent();
+  source().GenerateResumeEvent();
   EXPECT_EQ(observers[0].resumes(), 0);
 
   // Pretend we suspended.
-  source()->GenerateSuspendEvent();
+  source().GenerateSuspendEvent();
   // Ensure all observers were notified of the event
   for (const auto& index : observers)
     EXPECT_EQ(index.suspends(), 1);
 
   // Send a second suspend notification.  This should be suppressed.
-  source()->GenerateSuspendEvent();
+  source().GenerateSuspendEvent();
   EXPECT_EQ(observers[0].suspends(), 1);
 
   // Pretend we were awakened.
-  source()->GenerateResumeEvent();
+  source().GenerateResumeEvent();
   EXPECT_EQ(observers[0].resumes(), 1);
 
   // Send a duplicate resume notification.  This should be suppressed.
-  source()->GenerateResumeEvent();
+  source().GenerateResumeEvent();
   EXPECT_EQ(observers[0].resumes(), 1);
 
   // Pretend the device has gone on battery power
-  source()->GeneratePowerStateEvent(true);
+  source().GeneratePowerStateEvent(true);
   EXPECT_EQ(observers[0].power_state_changes(), 1);
   EXPECT_EQ(observers[0].last_power_state(), true);
 
   // Repeated indications the device is on battery power should be suppressed.
-  source()->GeneratePowerStateEvent(true);
+  source().GeneratePowerStateEvent(true);
   EXPECT_EQ(observers[0].power_state_changes(), 1);
 
   // Pretend the device has gone off battery power
-  source()->GeneratePowerStateEvent(false);
+  source().GeneratePowerStateEvent(false);
   EXPECT_EQ(observers[0].power_state_changes(), 2);
   EXPECT_EQ(observers[0].last_power_state(), false);
 
   // Repeated indications the device is off battery power should be suppressed.
-  source()->GeneratePowerStateEvent(false);
+  source().GeneratePowerStateEvent(false);
   EXPECT_EQ(observers[0].power_state_changes(), 2);
 
   EXPECT_EQ(observers[0].thermal_state_changes(), 0);
 
   // Send a power thermal change notification.
-  source()->GenerateThermalThrottlingEvent(
+  source().GenerateThermalThrottlingEvent(
       PowerThermalObserver::DeviceThermalState::kNominal);
   EXPECT_EQ(observers[0].thermal_state_changes(), 1);
   EXPECT_EQ(observers[0].last_thermal_state(),
             PowerThermalObserver::DeviceThermalState::kNominal);
 
   // Send a duplicate power thermal notification.  This should be suppressed.
-  source()->GenerateThermalThrottlingEvent(
+  source().GenerateThermalThrottlingEvent(
       PowerThermalObserver::DeviceThermalState::kNominal);
   EXPECT_EQ(observers[0].thermal_state_changes(), 1);
 
   // Send a different power thermal change notification.
-  source()->GenerateThermalThrottlingEvent(
+  source().GenerateThermalThrottlingEvent(
       PowerThermalObserver::DeviceThermalState::kFair);
   EXPECT_EQ(observers[0].thermal_state_changes(), 2);
   EXPECT_EQ(observers[0].last_thermal_state(),
@@ -128,8 +125,8 @@
       PowerThermalObserver::DeviceThermalState::kCritical};
 
   for (const auto state : kThermalStates) {
-    source()->GenerateThermalThrottlingEvent(state);
-    EXPECT_EQ(state, source()->GetCurrentThermalState());
+    source().GenerateThermalThrottlingEvent(state);
+    EXPECT_EQ(state, source().GetCurrentThermalState());
     EXPECT_EQ(observer.last_thermal_state(), state);
   }
 
@@ -149,13 +146,13 @@
   PowerMonitor::AddPowerSuspendObserver(&observer2);
 
   // Simulate suspend/resume notifications.
-  source()->GenerateSuspendEvent();
+  source().GenerateSuspendEvent();
   EXPECT_EQ(observer1.suspends(), 1);
   EXPECT_EQ(observer2.suspends(), 1);
   EXPECT_EQ(observer1.resumes(), 0);
   EXPECT_EQ(observer2.resumes(), 0);
 
-  source()->GenerateResumeEvent();
+  source().GenerateResumeEvent();
   EXPECT_EQ(observer1.resumes(), 1);
   EXPECT_EQ(observer2.resumes(), 1);
 
@@ -178,10 +175,10 @@
   // Simulate power state transitions (e.g. battery on/off).
   EXPECT_EQ(observer1.power_state_changes(), 0);
   EXPECT_EQ(observer2.power_state_changes(), 0);
-  source()->GeneratePowerStateEvent(true);
+  source().GeneratePowerStateEvent(true);
   EXPECT_EQ(observer1.power_state_changes(), 1);
   EXPECT_EQ(observer2.power_state_changes(), 1);
-  source()->GeneratePowerStateEvent(false);
+  source().GeneratePowerStateEvent(false);
   EXPECT_EQ(observer1.power_state_changes(), 2);
   EXPECT_EQ(observer2.power_state_changes(), 2);
 
@@ -198,7 +195,7 @@
   EXPECT_FALSE(
       PowerMonitor::AddPowerSuspendObserverAndReturnSuspendedState(&observer1));
 
-  source()->GenerateSuspendEvent();
+  source().GenerateSuspendEvent();
 
   EXPECT_TRUE(
       PowerMonitor::AddPowerSuspendObserverAndReturnSuspendedState(&observer2));
@@ -222,7 +219,7 @@
   EXPECT_FALSE(
       PowerMonitor::AddPowerStateObserverAndReturnOnBatteryState(&observer1));
 
-  source()->GeneratePowerStateEvent(true);
+  source().GeneratePowerStateEvent(true);
 
   // An observer is added after the on-battery notification.
   EXPECT_TRUE(
diff --git a/base/test/power_monitor_test_base.cc b/base/test/power_monitor_test_base.cc
index fcb34e66..dc078246 100644
--- a/base/test/power_monitor_test_base.cc
+++ b/base/test/power_monitor_test_base.cc
@@ -22,6 +22,11 @@
   base::PowerMonitor::ShutdownForTesting();
 }
 
+PowerThermalObserver::DeviceThermalState
+ScopedPowerMonitorTestSource::GetCurrentThermalState() {
+  return power_monitor_test_source_->GetCurrentThermalState();
+}
+
 bool ScopedPowerMonitorTestSource::IsOnBatteryPower() {
   return power_monitor_test_source_->IsOnBatteryPower();
 }
@@ -51,6 +56,11 @@
   power_monitor_test_source_->GeneratePowerStateEvent(on_battery_power);
 }
 
+void ScopedPowerMonitorTestSource::GenerateThermalThrottlingEvent(
+    PowerThermalObserver::DeviceThermalState new_thermal_state) {
+  power_monitor_test_source_->GenerateThermalThrottlingEvent(new_thermal_state);
+}
+
 }  // namespace test
 
 PowerMonitorTestSource::PowerMonitorTestSource() = default;
diff --git a/base/test/power_monitor_test_base.h b/base/test/power_monitor_test_base.h
index 82a5796..a6dd91cb 100644
--- a/base/test/power_monitor_test_base.h
+++ b/base/test/power_monitor_test_base.h
@@ -34,6 +34,8 @@
   ScopedPowerMonitorTestSource& operator=(const ScopedPowerMonitorTestSource&) =
       delete;
 
+  // Retrieve current states.
+  PowerThermalObserver::DeviceThermalState GetCurrentThermalState();
   bool IsOnBatteryPower();
 
   // Sends asynchronous notifications to registered observers.
@@ -44,6 +46,8 @@
   void GenerateSuspendEvent();
   void GenerateResumeEvent();
   void GeneratePowerStateEvent(bool on_battery_power);
+  void GenerateThermalThrottlingEvent(
+      PowerThermalObserver::DeviceThermalState new_thermal_state);
 
  private:
   // Owned by PowerMonitor.
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index f7848508..c4c2194d 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -254,37 +254,6 @@
 };
 #endif  // !defined(OS_IOS)
 
-class CheckThreadPriority : public testing::EmptyTestEventListener {
- public:
-  CheckThreadPriority(bool check_thread_priority_at_test_end)
-      : check_thread_priority_at_test_end_(check_thread_priority_at_test_end) {
-    CHECK_EQ(base::PlatformThread::GetCurrentThreadPriority(),
-             base::ThreadPriority::NORMAL)
-        << " -- The thread priority of this process is not the default. This "
-           "usually indicates nice has been used, which is not supported.";
-  }
-
-  void OnTestStart(const testing::TestInfo& test) override {
-    EXPECT_EQ(base::PlatformThread::GetCurrentThreadPriority(),
-              base::ThreadPriority::NORMAL)
-        << " -- The thread priority of this process is not the default. This "
-           "usually indicates nice has been used, which is not supported.";
-  }
-  void OnTestEnd(const testing::TestInfo& test) override {
-    if (check_thread_priority_at_test_end_) {
-      EXPECT_EQ(base::PlatformThread::GetCurrentThreadPriority(),
-                base::ThreadPriority::NORMAL)
-          << " -- The thread priority of this process is not the default. This "
-             "usually indicates nice has been used, which is not supported.";
-    }
-  }
-
- private:
-  const bool check_thread_priority_at_test_end_;
-
-  DISALLOW_COPY_AND_ASSIGN(CheckThreadPriority);
-};
-
 const std::string& GetProfileName() {
   static const NoDestructor<std::string> profile_name([]() {
     const CommandLine& command_line = *CommandLine::ForCurrentProcess();
diff --git a/base/trace_event/typed_macros_internal.h b/base/trace_event/typed_macros_internal.h
index 1bfb9c8..b342c46 100644
--- a/base/trace_event/typed_macros_internal.h
+++ b/base/trace_event/typed_macros_internal.h
@@ -13,6 +13,7 @@
 #include "build/build_config.h"
 #include "third_party/perfetto/include/perfetto/protozero/message_handle.h"
 #include "third_party/perfetto/include/perfetto/tracing/event_context.h"
+#include "third_party/perfetto/include/perfetto/tracing/internal/write_track_event_args.h"
 #include "third_party/perfetto/include/perfetto/tracing/string_helpers.h"
 #include "third_party/perfetto/include/perfetto/tracing/track.h"
 #include "third_party/perfetto/protos/perfetto/trace/track_event/track_event.pbzero.h"
@@ -28,7 +29,7 @@
   do {                                                                   \
     INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category);                    \
     if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED()) {                 \
-      trace_event_internal::AddTraceEvent(                               \
+      trace_event_internal::AddTypedTraceEvent(                          \
           phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
           ##__VA_ARGS__);                                                \
     }                                                                    \
@@ -62,25 +63,6 @@
 
 extern BASE_EXPORT const perfetto::Track kDefaultTrack;
 
-// Copy of function with the same name from Perfetto client library.
-template <typename T>
-constexpr bool IsValidTraceLambdaImpl(
-    typename std::enable_if<static_cast<bool>(
-        sizeof(std::declval<T>()(std::declval<perfetto::EventContext>()),
-               0))>::type* = nullptr) {
-  return true;
-}
-
-template <typename T>
-constexpr bool IsValidTraceLambdaImpl(...) {
-  return false;
-}
-
-template <typename T>
-constexpr bool IsValidTraceLambda() {
-  return IsValidTraceLambdaImpl<T>(nullptr);
-}
-
 // The perfetto client library does not use event names for
 // TRACE_EVENT_PHASE_END. However, TraceLog expects all TraceEvents to have
 // event names. So, until we move over to the client library, we will use this
@@ -110,16 +92,13 @@
       track, packet.TakePerfettoHandle());
 }
 
-template <
-    typename TrackEventArgumentFunction = void (*)(perfetto::EventContext),
-    typename ArgumentFunctionCheck = typename std::enable_if<
-        IsValidTraceLambda<TrackEventArgumentFunction>()>::type>
-inline void AddTraceEvent(char phase,
-                          const unsigned char* category_group_enabled,
-                          perfetto::StaticString name,
-                          const perfetto::Track& track,
-                          base::TimeTicks timestamp,
-                          TrackEventArgumentFunction argument_func) {
+template <typename... Args>
+inline void AddTypedTraceEventImpl(char phase,
+                                   const unsigned char* category_group_enabled,
+                                   perfetto::StaticString name,
+                                   const perfetto::Track& track,
+                                   base::TimeTicks timestamp,
+                                   Args&&... args) {
   bool emit_track_descriptor = false;
   {
     bool explicit_track = &track != &kDefaultTrack;
@@ -135,70 +114,62 @@
           track.uuid, track_event.incremental_state());
     }
 
-    argument_func(perfetto::EventContext(track_event.get(),
-                                         track_event.incremental_state()));
+    perfetto::internal::WriteTrackEventArgs(
+        perfetto::EventContext(track_event.get(),
+                               track_event.incremental_state()),
+        std::forward<Args>(args)...);
   }
 
   if (emit_track_descriptor)
     WriteTrackDescriptor(track);
 }
 
-template <
-    typename TrackEventArgumentFunction = void (*)(perfetto::EventContext),
-    typename ArgumentFunctionCheck = typename std::enable_if<
-        IsValidTraceLambda<TrackEventArgumentFunction>()>::type,
-    typename TrackType,
-    typename TrackTypeCheck = typename std::enable_if<
-        std::is_convertible<TrackType, perfetto::Track>::value>::type>
-inline void AddTraceEvent(char phase,
-                          const unsigned char* category_group_enabled,
-                          perfetto::StaticString name,
-                          const TrackType& track,
-                          TrackEventArgumentFunction argument_func) {
-  AddTraceEvent(phase, category_group_enabled, name, track, base::TimeTicks(),
-                argument_func);
-}
-
-template <
-    typename TrackEventArgumentFunction = void (*)(perfetto::EventContext),
-    typename ArgumentFunctionCheck = typename std::enable_if<
-        IsValidTraceLambda<TrackEventArgumentFunction>()>::type>
-inline void AddTraceEvent(char phase,
-                          const unsigned char* category_group_enabled,
-                          perfetto::StaticString name,
-                          TrackEventArgumentFunction argument_func) {
-  AddTraceEvent(phase, category_group_enabled, name, kDefaultTrack,
-                base::TimeTicks(), argument_func);
-}
-
-inline void AddTraceEvent(char phase,
-                          const unsigned char* category_group_enabled,
-                          perfetto::StaticString name) {
-  AddTraceEvent(phase, category_group_enabled, name, kDefaultTrack,
-                base::TimeTicks(), [](perfetto::EventContext ctx) {});
+template <typename TrackType,
+          typename... Args,
+          typename TrackTypeCheck = typename std::enable_if<
+              std::is_convertible<TrackType, perfetto::Track>::value>::type>
+inline void AddTypedTraceEvent(char phase,
+                               const unsigned char* category_group_enabled,
+                               perfetto::StaticString name,
+                               TrackType&& track,
+                               base::TimeTicks timestamp,
+                               Args&&... args) {
+  AddTypedTraceEventImpl(phase, category_group_enabled, name,
+                         std::forward<TrackType>(track), timestamp,
+                         std::forward<Args>(args)...);
 }
 
 template <typename TrackType,
+          typename... Args,
           typename TrackTypeCheck = typename std::enable_if<
               std::is_convertible<TrackType, perfetto::Track>::value>::type>
-inline void AddTraceEvent(char phase,
-                          const unsigned char* category_group_enabled,
-                          perfetto::StaticString name,
-                          const TrackType& track) {
-  AddTraceEvent(phase, category_group_enabled, name, track, base::TimeTicks(),
-                [](perfetto::EventContext ctx) {});
+inline void AddTypedTraceEvent(char phase,
+                               const unsigned char* category_group_enabled,
+                               perfetto::StaticString name,
+                               TrackType&& track,
+                               Args&&... args) {
+  AddTypedTraceEventImpl(phase, category_group_enabled, name,
+                         std::forward<TrackType>(track), base::TimeTicks(),
+                         std::forward<Args>(args)...);
 }
 
-template <typename TrackType,
-          typename TrackTypeCheck = typename std::enable_if<
-              std::is_convertible<TrackType, perfetto::Track>::value>::type>
-inline void AddTraceEvent(char phase,
-                          const unsigned char* category_group_enabled,
-                          perfetto::StaticString name,
-                          const TrackType& track,
-                          base::TimeTicks timestamp) {
-  AddTraceEvent(phase, category_group_enabled, name, track, timestamp,
-                [](perfetto::EventContext ctx) {});
+template <typename... Args>
+inline void AddTypedTraceEvent(char phase,
+                               const unsigned char* category_group_enabled,
+                               perfetto::StaticString name,
+                               base::TimeTicks timestamp,
+                               Args&&... args) {
+  AddTypedTraceEventImpl(phase, category_group_enabled, name, kDefaultTrack,
+                         timestamp, std::forward<Args>(args)...);
+}
+
+template <typename... Args>
+inline void AddTypedTraceEvent(char phase,
+                               const unsigned char* category_group_enabled,
+                               perfetto::StaticString name,
+                               Args&&... args) {
+  AddTypedTraceEventImpl(phase, category_group_enabled, name, kDefaultTrack,
+                         base::TimeTicks(), std::forward<Args>(args)...);
 }
 
 }  // namespace trace_event_internal
diff --git a/base/values.cc b/base/values.cc
index 15f5eb92e..169f72f 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -176,14 +176,9 @@
     case Type::LIST:
       data_.emplace<ListStorage>();
       return;
-    // TODO(crbug.com/859477): Remove after root cause is found.
-    case Type::DEAD:
-      CHECK(false);
-      return;
   }
 
-  // TODO(crbug.com/859477): Revert to NOTREACHED() after root cause is found.
-  CHECK(false);
+  NOTREACHED();
 }
 
 Value::Value(bool in_bool) : data_(in_bool) {}
@@ -929,14 +924,9 @@
           });
     case Value::Type::LIST:
       return lhs.list() == rhs.list();
-      // TODO(crbug.com/859477): Remove after root cause is found.
-    case Value::Type::DEAD:
-      CHECK(false);
-      return false;
   }
 
-  // TODO(crbug.com/859477): Revert to NOTREACHED() after root cause is found.
-  CHECK(false);
+  NOTREACHED();
   return false;
 }
 
@@ -973,14 +963,9 @@
           });
     case Value::Type::LIST:
       return lhs.list() < rhs.list();
-      // TODO(crbug.com/859477): Remove after root cause is found.
-    case Value::Type::DEAD:
-      CHECK(false);
-      return false;
   }
 
-  // TODO(crbug.com/859477): Revert to NOTREACHED() after root cause is found.
-  CHECK(false);
+  NOTREACHED();
   return false;
 }
 
@@ -1056,10 +1041,6 @@
     case Type::NONE:
       std::move(context).WriteString("<none>");
       return;
-    // TODO(crbug.com/859477): Remove after root cause is found.
-    case Type::DEAD:
-      CHECK(false);
-      return;
   }
 }
 
diff --git a/base/values.h b/base/values.h
index b83a24cb..9483b63 100644
--- a/base/values.h
+++ b/base/values.h
@@ -122,8 +122,6 @@
     BINARY,
     DICTIONARY,
     LIST,
-    // TODO(crbug.com/859477): Remove once root cause is found.
-    DEAD
     // Note: Do not add more types. See the file-level comment above for why.
   };
 
diff --git a/build/android/apk_operations.py b/build/android/apk_operations.py
index ff198098..a13808e 100755
--- a/build/android/apk_operations.py
+++ b/build/android/apk_operations.py
@@ -677,7 +677,7 @@
     self._found_initial_pid = self._primary_pid != None
     # Retrieve any additional patterns that are relevant for the User.
     self._user_defined_highlight = None
-    user_regex = os.environ['CHROMIUM_LOGCAT_HIGHLIGHT']
+    user_regex = os.environ.get('CHROMIUM_LOGCAT_HIGHLIGHT')
     if user_regex:
       self._user_defined_highlight = re.compile(user_regex)
       if not self._user_defined_highlight:
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
index e67a78c..37467f4 100644
--- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -106,7 +106,6 @@
 _DEVICE_GOLD_DIR = 'skia_gold'
 # A map of Android product models to SDK ints.
 RENDER_TEST_MODEL_SDK_CONFIGS = {
-    'Nexus 5X': [23],
     # Android x86 emulator.
     'Android SDK built for x86': [23],
 }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 34c4786..ae94f612 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-3.20210412.0.1
+3.20210412.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 34c4786..ae94f612 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-3.20210412.0.1
+3.20210412.1.1
diff --git a/cc/metrics/compositor_frame_reporting_controller.cc b/cc/metrics/compositor_frame_reporting_controller.cc
index fbd3b87..cc34dff 100644
--- a/cc/metrics/compositor_frame_reporting_controller.cc
+++ b/cc/metrics/compositor_frame_reporting_controller.cc
@@ -361,17 +361,29 @@
 void CompositorFrameReportingController::DidPresentCompositorFrame(
     uint32_t frame_token,
     const viz::FrameTimingDetails& details) {
-  while (!submitted_compositor_frames_.empty()) {
-    auto submitted_frame = submitted_compositor_frames_.begin();
-    if (viz::FrameTokenGT(submitted_frame->frame_token, frame_token))
-      break;
+  bool feedback_failed = details.presentation_feedback.failed();
+  for (auto submitted_frame = submitted_compositor_frames_.begin();
+       submitted_frame != submitted_compositor_frames_.end() &&
+       !viz::FrameTokenGT(submitted_frame->frame_token, frame_token);) {
+    bool is_earlier_frame = submitted_frame->frame_token != frame_token;
 
-    auto termination_status = FrameTerminationStatus::kPresentedFrame;
-    if (submitted_frame->frame_token != frame_token ||
-        details.presentation_feedback.failed()) {
-      termination_status = FrameTerminationStatus::kDidNotPresentFrame;
+    // If the presentation feedback is a failure, earlier frames should still be
+    // left in the queue as they still might end up being presented
+    // successfully. Skip to the next frame.
+    if (feedback_failed && is_earlier_frame) {
+      submitted_frame++;
+      continue;
     }
 
+    auto termination_status = feedback_failed
+                                  ? FrameTerminationStatus::kDidNotPresentFrame
+                                  : FrameTerminationStatus::kPresentedFrame;
+
+    // If this is an earlier frame, presentation feedback has been successful
+    // which means this earlier frame should be considered dropped.
+    if (is_earlier_frame)
+      termination_status = FrameTerminationStatus::kDidNotPresentFrame;
+
     auto& reporter = submitted_frame->reporter;
     reporter->SetVizBreakdown(details);
     reporter->TerminateFrame(termination_status,
@@ -393,7 +405,7 @@
         reporter->AddEventsMetrics(std::move(it->second));
       }
 
-      // For presented frames, if |reporter| was cloned from another reporter,
+      // For presented frames, if `reporter` was cloned from another reporter,
       // and the original reporter is still alive, then check whether the cloned
       // reporter has a 'partial update decider'. It is still possible for the
       // original reporter to terminate with 'no damage', and if that happens,
@@ -422,7 +434,23 @@
       }
     }
 
-    submitted_compositor_frames_.erase(submitted_frame);
+    if (feedback_failed) {
+      // When feedback is for a failed presentation, `submitted_frame` is not
+      // necessarily in the front of the queue. We will reach here only once per
+      // did-present; so, we will have 1 operation of O(n) complexity (n is the
+      // number of previous frames).
+      submitted_frame = submitted_compositor_frames_.erase(submitted_frame);
+    } else {
+      // When feedback is for a successful presentation, `submitted_frame` is in
+      // the front of the queue; so, we will have n operations of O(1)
+      // complexity for a did-present (n is the number of previous frames).
+      // `pop_front()` function is used here to shrink the queue when necessary
+      // to avoid unnecessary memory usage over time.
+      DCHECK_EQ(submitted_frame->frame_token,
+                submitted_compositor_frames_.front().frame_token);
+      submitted_compositor_frames_.pop_front();
+      submitted_frame = submitted_compositor_frames_.begin();
+    }
   }
 }
 
diff --git a/cc/metrics/compositor_frame_reporting_controller_unittest.cc b/cc/metrics/compositor_frame_reporting_controller_unittest.cc
index 151a52ae..1efcece 100644
--- a/cc/metrics/compositor_frame_reporting_controller_unittest.cc
+++ b/cc/metrics/compositor_frame_reporting_controller_unittest.cc
@@ -1628,5 +1628,37 @@
             dropped_counter_.total_compositor_dropped());
 }
 
+// Verifies that presentation feedbacks that arrive out of order are handled
+// properly. See crbug.com/1195105 for more details.
+TEST_F(CompositorFrameReportingControllerTest,
+       HandleOutOfOrderPresentationFeedback) {
+  // Submit three compositor frames without sending back their presentation
+  // feedbacks.
+  SimulateSubmitCompositorFrame({});
+
+  SimulateSubmitCompositorFrame({});
+  const uint32_t frame_token_2 = *current_token_;
+
+  SimulateSubmitCompositorFrame({});
+  const uint32_t frame_token_3 = *current_token_;
+
+  // Send a failed presentation feedback for frame 2. This should only drop
+  // frame 2 and leave frame 1 in the queue.
+  viz::FrameTimingDetails details_2;
+  details_2.presentation_feedback = {AdvanceNowByMs(10), base::TimeDelta(),
+                                     gfx::PresentationFeedback::kFailure};
+  reporting_controller_.DidPresentCompositorFrame(frame_token_2, details_2);
+  DCHECK_EQ(1u, dropped_counter_.total_frames());
+  DCHECK_EQ(1u, dropped_counter_.total_compositor_dropped());
+
+  // Send a successful presentation feedback for frame 3. This should drop frame
+  // 1.
+  viz::FrameTimingDetails details_3;
+  details_3.presentation_feedback.timestamp = AdvanceNowByMs(10);
+  reporting_controller_.DidPresentCompositorFrame(frame_token_3, details_3);
+  DCHECK_EQ(3u, dropped_counter_.total_frames());
+  DCHECK_EQ(2u, dropped_counter_.total_compositor_dropped());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/mojo_embedder/async_layer_tree_frame_sink.cc b/cc/mojo_embedder/async_layer_tree_frame_sink.cc
index ad8fa37..1f66b6e6 100644
--- a/cc/mojo_embedder/async_layer_tree_frame_sink.cc
+++ b/cc/mojo_embedder/async_layer_tree_frame_sink.cc
@@ -303,7 +303,7 @@
 void AsyncLayerTreeFrameSink::OnMojoConnectionError(
     uint32_t custom_reason,
     const std::string& description) {
-  // TODO(sgilhuly): Use DLOG(FATAL) once crbug.com/1043899 is resolved.
+  // TODO(rivr): Use DLOG(FATAL) once crbug.com/1043899 is resolved.
   if (custom_reason)
     DLOG(ERROR) << description;
   if (client_)
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 3eea6c5..52d1afc 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -677,7 +677,7 @@
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
     init_vulkan = true;
 #elif defined(OS_WIN)
-    // TODO(sgilhuly): Initialize D3D12 for Windows.
+    // TODO(rivr): Initialize D3D12 for Windows.
 #else
     NOTREACHED();
 #endif
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index 1fa414e..78edac9d8 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -74,7 +74,7 @@
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
     init_vulkan = true;
 #elif defined(OS_WIN)
-    // TODO(sgilhuly): Initialize D3D12 for Windows.
+    // TODO(rivr): Initialize D3D12 for Windows.
 #else
     NOTREACHED();
 #endif
diff --git a/cc/trees/layer_tree_host_pixeltest_tiles.cc b/cc/trees/layer_tree_host_pixeltest_tiles.cc
index a10ad840..c82cf696 100644
--- a/cc/trees/layer_tree_host_pixeltest_tiles.cc
+++ b/cc/trees/layer_tree_host_pixeltest_tiles.cc
@@ -267,7 +267,7 @@
     {viz::RendererType::kSkiaGL, TestRasterType::kOneCopy},
 #endif  // BUILDFLAG(ENABLE_GL_BACKEND_TESTS)
 #if BUILDFLAG(ENABLE_VULKAN_BACKEND_TESTS)
-    // TODO(sgilhuly): Switch this to one copy raster once is is supported for
+    // TODO(rivr): Switch this to one copy raster once is is supported for
     // Vulkan in these tests.
     {viz::RendererType::kSkiaVk, TestRasterType::kOop},
 #endif  // BUILDFLAG(ENABLE_VULKAN_BACKEND_TESTS)
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageCardViewModel.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageCardViewModel.java
index 36f3c9c..9fc354e 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageCardViewModel.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageCardViewModel.java
@@ -35,6 +35,8 @@
 
         return new PropertyModel.Builder(MessageCardViewProperties.ALL_KEYS)
                 .with(MessageCardViewProperties.MESSAGE_TYPE, MessageService.MessageType.IPH)
+                .with(MessageCardViewProperties.MESSAGE_IDENTIFIER,
+                        MessageService.DEFAULT_MESSAGE_IDENTIFIER)
                 .with(MessageCardViewProperties.ICON_PROVIDER,
                         IphMessageCardViewModel::getIconDrawable)
                 .with(MessageCardViewProperties.UI_DISMISS_ACTION_PROVIDER, uiDismissActionProvider)
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderCoordinator.java
index f55ef92d..b9c9e37 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderCoordinator.java
@@ -59,6 +59,15 @@
     }
 
     /**
+     * @param messageType The {@link MessageService.MessageType} associated with the message.
+     * @param identifier The identifier associated with the message.
+     * @return Whether the given message is shown.
+     */
+    boolean isMessageShown(@MessageService.MessageType int messageType, int identifier) {
+        return mMediator.isMessageShown(messageType, identifier);
+    }
+
+    /**
      * Clean up all member fields.
      */
     public void destroy() {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderMediator.java
index 218c95c..e58923db 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderMediator.java
@@ -93,6 +93,13 @@
         return message;
     }
 
+    boolean isMessageShown(@MessageService.MessageType int messageType, int identifier) {
+        if (!mShownMessageItems.containsKey(messageType)) return false;
+        return mShownMessageItems.get(messageType)
+                       .model.get(MessageCardViewProperties.MESSAGE_IDENTIFIER)
+                == identifier;
+    }
+
     private PropertyModel buildModel(int messageType, MessageService.MessageData data) {
         switch (messageType) {
             case TAB_SUGGESTION:
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardViewProperties.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardViewProperties.java
index a501a6c..543b73a 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardViewProperties.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardViewProperties.java
@@ -17,6 +17,10 @@
 class MessageCardViewProperties {
     public static final PropertyModel.ReadableIntPropertyKey MESSAGE_TYPE =
             new PropertyModel.ReadableIntPropertyKey();
+    // Identifier is the subtype of message. For example, the message with type PRICE_MESSAGE may
+    // have the identifier PRICE_WELCOME or PRICE_ALERTS.
+    public static final PropertyModel.ReadableIntPropertyKey MESSAGE_IDENTIFIER =
+            new PropertyModel.ReadableIntPropertyKey();
     public static final PropertyModel.WritableObjectPropertyKey<String> ACTION_TEXT =
             new PropertyModel.WritableObjectPropertyKey<>();
     public static final PropertyModel.WritableObjectPropertyKey<String> DESCRIPTION_TEXT =
@@ -54,10 +58,10 @@
             .WritableObjectPropertyKey<ShoppingPersistedTabData.PriceDrop> PRICE_DROP =
             new PropertyModel.WritableObjectPropertyKey<>();
 
-    public static final PropertyKey[] ALL_KEYS =
-            new PropertyKey[] {ACTION_TEXT, DESCRIPTION_TEXT, DESCRIPTION_TEXT_TEMPLATE,
-                    MESSAGE_TYPE, ICON_PROVIDER, UI_ACTION_PROVIDER, UI_DISMISS_ACTION_PROVIDER,
-                    MESSAGE_SERVICE_ACTION_PROVIDER, MESSAGE_SERVICE_DISMISS_ACTION_PROVIDER,
-                    DISMISS_BUTTON_CONTENT_DESCRIPTION, SHOULD_KEEP_AFTER_REVIEW, IS_ICON_VISIBLE,
-                    CARD_TYPE, CARD_ALPHA, IS_INCOGNITO, TITLE_TEXT, PRICE_DROP};
+    public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {ACTION_TEXT, DESCRIPTION_TEXT,
+            DESCRIPTION_TEXT_TEMPLATE, MESSAGE_TYPE, MESSAGE_IDENTIFIER, ICON_PROVIDER,
+            UI_ACTION_PROVIDER, UI_DISMISS_ACTION_PROVIDER, MESSAGE_SERVICE_ACTION_PROVIDER,
+            MESSAGE_SERVICE_DISMISS_ACTION_PROVIDER, DISMISS_BUTTON_CONTENT_DESCRIPTION,
+            SHOULD_KEEP_AFTER_REVIEW, IS_ICON_VISIBLE, CARD_TYPE, CARD_ALPHA, IS_INCOGNITO,
+            TITLE_TEXT, PRICE_DROP};
 }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageService.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageService.java
index a5bad90..e912da7 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageService.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageService.java
@@ -29,6 +29,11 @@
         int ALL = 4;
     }
 
+    // This identifier is used to serve messages that have no subtype, such as IPH. If one message
+    // type has multiple subtypes such as PRICE_MESSAGE, its service needs to define its own
+    // identifiers which should be used when creating the message card view model.
+    public static final int DEFAULT_MESSAGE_IDENTIFIER = -1;
+
     /**
      * This is a data wrapper. Implement this interface to send notification with data to all the
      * observers.
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageCardViewModel.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageCardViewModel.java
index 2f01901..a1947b2c 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageCardViewModel.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/PriceMessageCardViewModel.java
@@ -42,6 +42,7 @@
         return new PropertyModel.Builder(MessageCardViewProperties.ALL_KEYS)
                 .with(MessageCardViewProperties.MESSAGE_TYPE,
                         MessageService.MessageType.PRICE_MESSAGE)
+                .with(MessageCardViewProperties.MESSAGE_IDENTIFIER, data.getType())
                 .with(MessageCardViewProperties.UI_DISMISS_ACTION_PROVIDER, uiDismissActionProvider)
                 .with(MessageCardViewProperties.MESSAGE_SERVICE_DISMISS_ACTION_PROVIDER,
                         data.getDismissActionProvider())
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
index d492b9db..833dce5 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
@@ -173,19 +173,15 @@
      */
     static class ShoppingPersistedTabDataFetcher {
         protected Tab mTab;
-        protected TabListModel mModel;
         protected PriceWelcomeMessageController mPriceWelcomeMessageController;
 
         /**
          * @param tab {@link Tab} {@link ShoppingPersistedTabData} will be acquired for.
-         * @param model {@link TabListModel} to check if we already have the price welcome message
-         *         in the model.
          * @param priceWelcomeMessageController to show the price welcome message.
          */
-        ShoppingPersistedTabDataFetcher(Tab tab, @Nullable TabListModel model,
-                @Nullable PriceWelcomeMessageController priceWelcomeMessageController) {
+        ShoppingPersistedTabDataFetcher(
+                Tab tab, @Nullable PriceWelcomeMessageController priceWelcomeMessageController) {
             mTab = tab;
-            mModel = model;
             mPriceWelcomeMessageController = priceWelcomeMessageController;
         }
 
@@ -203,19 +199,12 @@
         @VisibleForTesting
         void maybeShowPriceWelcomeMessage(
                 @Nullable ShoppingPersistedTabData shoppingPersistedTabData) {
-            // TODO(crbug.com/1166702): Use another method to check if we already have the price
-            // welcome message in tab switcher instead of using
-            // mModel.lastIndexForMessageItemFromType(MessageService.MessageType.PRICE_MESSAGE),
-            // because we may have other price message types.
             // Avoid inserting message while RecyclerView is computing a layout.
             new Handler().post(() -> {
-                if (!PriceTrackingUtilities.isPriceWelcomeMessageCardEnabled() || (mModel == null)
+                if (!PriceTrackingUtilities.isPriceWelcomeMessageCardEnabled()
                         || (mPriceWelcomeMessageController == null)
                         || (shoppingPersistedTabData == null)
-                        || (shoppingPersistedTabData.getPriceDrop() == null)
-                        || (mModel.lastIndexForMessageItemFromType(
-                                    MessageService.MessageType.PRICE_MESSAGE)
-                                != TabModel.INVALID_TAB_INDEX)) {
+                        || (shoppingPersistedTabData.getPriceDrop() == null)) {
                     return;
                 }
                 mPriceWelcomeMessageController.showPriceWelcomeMessage(
@@ -1157,7 +1146,7 @@
                 && PriceTrackingUtilities.isTrackPricesOnTabsEnabled()) {
             mModel.get(index).model.set(TabProperties.SHOPPING_PERSISTED_TAB_DATA_FETCHER,
                     new ShoppingPersistedTabDataFetcher(
-                            pseudoTab.getTab(), mModel, mPriceWelcomeMessageController));
+                            pseudoTab.getTab(), mPriceWelcomeMessageController));
         } else {
             mModel.get(index).model.set(TabProperties.SHOPPING_PERSISTED_TAB_DATA_FETCHER, null);
         }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageCardViewModel.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageCardViewModel.java
index c2fe9b4c..faa978e 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageCardViewModel.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageCardViewModel.java
@@ -40,6 +40,7 @@
         return new PropertyModel.Builder(MessageCardViewProperties.ALL_KEYS)
                 .with(MessageCardViewProperties.MESSAGE_TYPE,
                         MessageService.MessageType.TAB_SUGGESTION)
+                .with(MessageCardViewProperties.MESSAGE_IDENTIFIER, data.getActionType())
                 .with(MessageCardViewProperties.ICON_PROVIDER,
                         TabSuggestionMessageCardViewModel::getIconDrawable)
                 .with(MessageCardViewProperties.UI_DISMISS_ACTION_PROVIDER, uiDismissActionProvider)
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
index 648f90e70f..cd1fa8bb 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
@@ -528,7 +528,9 @@
     @Override
     public void showPriceWelcomeMessage(PriceMessageService.PriceTabData priceTabData) {
         if (mPriceMessageService == null
-                || !PriceTrackingUtilities.isPriceWelcomeMessageCardEnabled()) {
+                || !PriceTrackingUtilities.isPriceWelcomeMessageCardEnabled()
+                || mMessageCardProviderCoordinator.isMessageShown(
+                        MessageService.MessageType.PRICE_MESSAGE, PriceMessageType.PRICE_WELCOME)) {
             return;
         }
         mPriceMessageService.preparePriceMessage(PriceMessageType.PRICE_WELCOME, priceTabData);
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
index b3e3674..928aed4d 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
@@ -727,7 +727,7 @@
             extends TabListMediator.ShoppingPersistedTabDataFetcher {
         private ShoppingPersistedTabData mShoppingPersistedTabData;
         MockShoppingPersistedTabDataFetcher(Tab tab) {
-            super(tab, null, null);
+            super(tab, null);
         }
 
         public void setPriceStrings(String priceString, String previousPriceString) {
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderMediatorUnitTest.java
index bf17e8c..414d5dc 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderMediatorUnitTest.java
@@ -350,4 +350,18 @@
                         .model;
         Assert.assertTrue(messageModel.get(MessageCardViewProperties.IS_INCOGNITO));
     }
+
+    @Test
+    public void isMessageShownTest() {
+        Assert.assertFalse(mMediator.isMessageShown(
+                MessageService.MessageType.PRICE_MESSAGE, PriceMessageType.PRICE_WELCOME));
+        enqueueMessageItem(MessageService.MessageType.PRICE_MESSAGE, -1);
+        // Mock pulling this message, which will move the message from mMessageItems to
+        // mShownMessageItems.
+        mMediator.getNextMessageItemForType(MessageService.MessageType.PRICE_MESSAGE);
+        Assert.assertTrue(mMediator.isMessageShown(
+                MessageService.MessageType.PRICE_MESSAGE, PriceMessageType.PRICE_WELCOME));
+        Assert.assertFalse(mMediator.isMessageShown(
+                MessageService.MessageType.PRICE_MESSAGE, PriceMessageType.PRICE_ALERTS));
+    }
 }
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
index 4c739788..8729997 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
@@ -2354,7 +2354,7 @@
     public void testMaybeShowPriceWelcomeMessage() {
         prepareTestMaybeShowPriceWelcomeMessage();
         ShoppingPersistedTabDataFetcher fetcher =
-                new ShoppingPersistedTabDataFetcher(mTab1, mModel, mPriceWelcomeMessageController);
+                new ShoppingPersistedTabDataFetcher(mTab1, mPriceWelcomeMessageController);
         fetcher.maybeShowPriceWelcomeMessage(mShoppingPersistedTabData);
         verify(mPriceWelcomeMessageController, times(1)).showPriceWelcomeMessage(mPriceTabData);
     }
@@ -2363,7 +2363,7 @@
     public void testMaybeShowPriceWelcomeMessage_MessageDisabled() {
         prepareTestMaybeShowPriceWelcomeMessage();
         ShoppingPersistedTabDataFetcher fetcher =
-                new ShoppingPersistedTabDataFetcher(mTab1, mModel, mPriceWelcomeMessageController);
+                new ShoppingPersistedTabDataFetcher(mTab1, mPriceWelcomeMessageController);
 
         PriceTrackingUtilities.SHARED_PREFERENCES_MANAGER.writeBoolean(
                 PriceTrackingUtilities.PRICE_WELCOME_MESSAGE_CARD, false);
@@ -2376,11 +2376,7 @@
     public void testMaybeShowPriceWelcomeMessage_NullParameter() {
         prepareTestMaybeShowPriceWelcomeMessage();
 
-        new ShoppingPersistedTabDataFetcher(mTab1, null, mPriceWelcomeMessageController)
-                .maybeShowPriceWelcomeMessage(mShoppingPersistedTabData);
-        verify(mPriceWelcomeMessageController, times(0)).showPriceWelcomeMessage(mPriceTabData);
-
-        new ShoppingPersistedTabDataFetcher(mTab1, mModel, null)
+        new ShoppingPersistedTabDataFetcher(mTab1, null)
                 .maybeShowPriceWelcomeMessage(mShoppingPersistedTabData);
         verify(mPriceWelcomeMessageController, times(0)).showPriceWelcomeMessage(mPriceTabData);
     }
@@ -2389,7 +2385,7 @@
     public void testMaybeShowPriceWelcomeMessage_NoPriceDrop() {
         prepareTestMaybeShowPriceWelcomeMessage();
         ShoppingPersistedTabDataFetcher fetcher =
-                new ShoppingPersistedTabDataFetcher(mTab1, mModel, mPriceWelcomeMessageController);
+                new ShoppingPersistedTabDataFetcher(mTab1, mPriceWelcomeMessageController);
 
         fetcher.maybeShowPriceWelcomeMessage(null);
         verify(mPriceWelcomeMessageController, times(0)).showPriceWelcomeMessage(mPriceTabData);
@@ -2400,19 +2396,6 @@
     }
 
     @Test
-    public void testMaybeShowPriceWelcomeMessage_AlreadyHasMessage() {
-        prepareTestMaybeShowPriceWelcomeMessage();
-        ShoppingPersistedTabDataFetcher fetcher =
-                new ShoppingPersistedTabDataFetcher(mTab1, mModel, mPriceWelcomeMessageController);
-
-        // Simulate that we already has the message.
-        addSpecialItem(1, TabProperties.UiType.LARGE_MESSAGE, PRICE_MESSAGE);
-
-        fetcher.maybeShowPriceWelcomeMessage(mShoppingPersistedTabData);
-        verify(mPriceWelcomeMessageController, times(0)).showPriceWelcomeMessage(mPriceTabData);
-    }
-
-    @Test
     @Features.EnableFeatures({TAB_GROUPS_CONTINUATION_ANDROID})
     public void testUpdateFaviconForGroup() {
         setUpForTabGroupOperation(TabListMediatorType.TAB_SWITCHER);
@@ -2841,7 +2824,5 @@
         mPriceDrop = new PriceDrop("1", "2");
         mPriceTabData = new PriceTabData(TAB1_ID, mPriceDrop);
         doReturn(mPriceDrop).when(mShoppingPersistedTabData).getPriceDrop();
-        assertThat(mModel.lastIndexForMessageItemFromType(PRICE_MESSAGE),
-                equalTo(TabModel.INVALID_TAB_INDEX));
     }
 }
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurface.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurface.java
index 4befffc..0c13072 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurface.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurface.java
@@ -338,6 +338,11 @@
                     return AutoplayPreference.AUTOPLAY_ON_WIFI_ONLY;
             }
         }
+
+        @Override
+        public long getReliabilityLoggingId() {
+            return FeedServiceBridge.getReliabilityLoggingId();
+        }
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SelectionClientManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SelectionClientManager.java
index 2aa63460..ec79ce90 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SelectionClientManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SelectionClientManager.java
@@ -11,7 +11,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.content_public.browser.SelectionClient;
-import org.chromium.content_public.browser.SelectionMetricsLogger;
+import org.chromium.content_public.browser.SelectionEventProcessor;
 import org.chromium.content_public.browser.SelectionPopupController;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.touch_selection.SelectionEventType;
@@ -192,8 +192,8 @@
         }
 
         @Override
-        public SelectionMetricsLogger getSelectionMetricsLogger() {
-            return mSmartSelectionClient.getSelectionMetricsLogger();
+        public SelectionEventProcessor getSelectionEventProcessor() {
+            return mSmartSelectionClient.getSelectionEventProcessor();
         }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java b/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java
index db5e1fdd..26d9acb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java
@@ -44,7 +44,10 @@
 import java.util.Random;
 
 /**
- * Class that controls if and when to show surveys.
+ * Class that controls if and when to show surveys. One instance of this class is associated with
+ * one trigger ID, which is used to fetch a survey, at the time it is created.
+ *
+ * @see #getTriggerId()
  */
 public class ChromeSurveyController implements InfoBarAnimationListener {
     private static final String TAG = "ChromeSurveyCtrler";
@@ -101,9 +104,14 @@
     private Tab mSurveyInfoBarTab;
     private TabModelSelectorObserver mTabModelObserver;
 
+    private final String mTriggerId;
+    private final String mPrefKeyPromptDisplayed;
+
     @VisibleForTesting
-    ChromeSurveyController() {
-        // Empty constructor.
+    ChromeSurveyController(String triggerId) {
+        mTriggerId = triggerId;
+        mPrefKeyPromptDisplayed =
+                ChromePreferenceKeys.CHROME_SURVEY_PROMPT_DISPLAYED_TIMESTAMP.createKey(mTriggerId);
     }
 
     /**
@@ -114,7 +122,8 @@
     public static void initialize(TabModelSelector tabModelSelector) {
         assert tabModelSelector != null;
         if (!isSurveyEnabled() || TextUtils.isEmpty(getTriggerId())) return;
-        new StartDownloadIfEligibleTask(new ChromeSurveyController(), tabModelSelector)
+        new StartDownloadIfEligibleTask(
+                new ChromeSurveyController(getTriggerId()), tabModelSelector)
                 .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
@@ -129,25 +138,21 @@
         mTabModelSelector = tabModelSelector;
 
         SurveyController surveyController = SurveyController.getInstance();
-
-        String triggerId = getTriggerId();
-
         Runnable onSuccessRunnable = new Runnable() {
             @Override
             public void run() {
-                onSurveyAvailable(triggerId);
+                onSurveyAvailable(mTriggerId);
             }
         };
 
         Runnable onFailureRunnable = () -> Log.w(TAG, "Survey does not exists or download failed.");
-        surveyController.downloadSurvey(context, triggerId, onSuccessRunnable, onFailureRunnable);
+        surveyController.downloadSurvey(context, mTriggerId, onSuccessRunnable, onFailureRunnable);
     }
 
     /** @return Whether the user qualifies for the survey. */
     private boolean doesUserQualifyForSurvey() {
         if (!isUMAEnabled() && !sForceUmaEnabledForTesting) return false;
-        if (hasInfoBarBeenDisplayed()) return false;
-        return true;
+        return !hasInfoBarBeenDisplayed();
     }
 
     /**
@@ -253,7 +258,9 @@
     @VisibleForTesting
     boolean hasInfoBarBeenDisplayed() {
         SharedPreferencesManager preferences = SharedPreferencesManager.getInstance();
-        if (preferences.readLong(ChromePreferenceKeys.SURVEY_INFO_BAR_DISPLAYED, -1L) != -1L) {
+
+        // TODO(https://crbug.com/1195928): Get an expiration date from feature flag.
+        if (preferences.readLong(mPrefKeyPromptDisplayed, -1L) != -1L) {
             recordSurveyFilteringResult(FilteringResult.SURVEY_INFOBAR_ALREADY_DISPLAYED);
             return true;
         }
@@ -394,7 +401,8 @@
     }
 
     /** Logs in SharedPreferences that the info bar was displayed. */
-    private void recordInfoBarDisplayed() {
+    @VisibleForTesting
+    void recordInfoBarDisplayed() {
         // This can be called multiple times e.g. by mLoggingHandler & onSurveyInfoBarClosed().
         // Return early to allow only one call to this method (http://crbug.com/791076).
         if (mSurveyInfoBarTab == null) return;
@@ -405,8 +413,7 @@
         mLoggingHandler.removeCallbacksAndMessages(null);
 
         SharedPreferencesManager preferences = SharedPreferencesManager.getInstance();
-        preferences.writeLong(
-                ChromePreferenceKeys.SURVEY_INFO_BAR_DISPLAYED, System.currentTimeMillis());
+        preferences.writeLong(mPrefKeyPromptDisplayed, System.currentTimeMillis());
         mSurveyInfoBarTab = null;
     }
 
@@ -485,11 +492,6 @@
     }
 
     @VisibleForTesting
-    public static String getChromeSurveyInfoBarDisplayedKey() {
-        return ChromePreferenceKeys.SURVEY_INFO_BAR_DISPLAYED;
-    }
-
-    @VisibleForTesting
     public static String getCommandLineParamName() {
         return COMMAND_LINE_PARAM_NAME;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarController.java b/chrome/android/java/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarController.java
index ddf83dd0..ef216cf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarController.java
@@ -91,12 +91,13 @@
                 // TabGridDialog is showing. If so, don't show the undo bar because TabGridDialog
                 // has its own undo bar. See crbug.com/1119899. Note that we don't disable attempts
                 // to dismiss snack bar to make sure that snack bar state is in sync with tab model.
-                if (dialogVisibilitySupplier != null && showingUndoBar) {
-                    return dialogVisibilitySupplier.get();
+                if (dialogVisibilitySupplier != null && dialogVisibilitySupplier.get()
+                        && showingUndoBar) {
+                    return true;
                 }
-                // If grid tab switcher is enabled, show the undo snack bar regardless of whether
+                // If grid / group M5 is enabled, show the undo snack bar regardless of whether
                 // accessibility mode is enabled.
-                if (TabUiFeatureUtilities.isGridTabSwitcherEnabled()) {
+                if (TabUiFeatureUtilities.isTabGroupsAndroidContinuationEnabled()) {
                     return false;
                 }
                 return ChromeAccessibilityUtil.get().isAccessibilityEnabled()
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java
index 0ef8923..078dca6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java
@@ -24,6 +24,7 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.LaunchIntentDispatcher;
 import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory.CustomTabNavigationDelegate;
@@ -80,6 +81,7 @@
         mActivityRule.startCustomTabActivityWithIntent(intent);
     }
 
+    @DisabledTest(message = "https://crbug.com/1197727")
     @Test
     @Feature("CustomTabFromChrome")
     @MediumTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarControllerTest.java
index be2083e..9727b698 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/undo_tab_close_snackbar/UndoBarControllerTest.java
@@ -17,6 +17,7 @@
 
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
@@ -25,6 +26,7 @@
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.ChromeTabUtils;
+import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
 import java.util.concurrent.Callable;
@@ -153,6 +155,27 @@
                 "Undo snack bar should not be showing in accessibility mode", getCurrentSnackbar());
     }
 
+    @Test
+    @SmallTest
+    @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_CONTINUATION_ANDROID})
+    public void testUndoSnackbarEnabled_AccessibilityEnabledWithGroupM5() throws Exception {
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> ChromeAccessibilityUtil.get().setAccessibilityEnabledForTesting(true));
+
+        Assert.assertNull("Snack bar should be null initially", getCurrentSnackbar());
+        Assert.assertEquals("Tab Model should contain 1 tab", 1, mTabModel.getCount());
+
+        ChromeTabUtils.closeAllTabs(
+                InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity());
+
+        Snackbar currentSnackbar = getCurrentSnackbar();
+        Assert.assertEquals("Incorrect snackbar text", "Closed about:blank", getSnackbarText());
+        Assert.assertTrue("Incorrect SnackbarController type",
+                currentSnackbar.getController() instanceof UndoBarController);
+        Assert.assertEquals(
+                "Tab Model should contain 0 tab after tab closed", 0, mTabModel.getCount());
+    }
+
     private void clickSnackbar() {
         TestThreadUtils.runOnUiThreadBlocking(
                 ()
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerTest.java
index 5417fe3..2ec2252 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerTest.java
@@ -34,8 +34,7 @@
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
 public class ChromeSurveyControllerTest {
-    private static final String STUDY_NAME = "HorizontalTabSwitcherStudyName";
-    private static final String GROUP_NAME = "HorizontalTabSwitcherGroupName";
+    private static final String TEST_SURVEY_TRIGGER_ID = "foobar";
 
     private TestChromeSurveyController mTestController;
     private RiggedSurveyController mRiggedController;
@@ -57,7 +56,7 @@
     public void before() {
         MockitoAnnotations.initMocks(this);
 
-        mTestController = new TestChromeSurveyController();
+        mTestController = new TestChromeSurveyController(TEST_SURVEY_TRIGGER_ID);
         mTestController.setTabModelSelector(mSelector);
         mSharedPreferences = SharedPreferencesManager.getInstance();
         Assert.assertNull("Tab should be null", mTestController.getLastTabInfobarShown());
@@ -65,12 +64,36 @@
 
     @Test
     public void testInfoBarDisplayedBefore() {
-        Assert.assertFalse(
-                mSharedPreferences.contains(ChromePreferenceKeys.SURVEY_INFO_BAR_DISPLAYED));
-        Assert.assertFalse(mTestController.hasInfoBarBeenDisplayed());
-        mSharedPreferences.writeLong(
-                ChromePreferenceKeys.SURVEY_INFO_BAR_DISPLAYED, System.currentTimeMillis());
-        Assert.assertTrue(mTestController.hasInfoBarBeenDisplayed());
+        final String triggerId1 = "triggerId1";
+        final String triggerId2 = "triggerId2";
+
+        TestChromeSurveyController controller1 = new TestChromeSurveyController(triggerId1);
+        TestChromeSurveyController controller2 = new TestChromeSurveyController(triggerId2);
+
+        String prefKey1 =
+                ChromePreferenceKeys.CHROME_SURVEY_PROMPT_DISPLAYED_TIMESTAMP.createKey(triggerId1);
+        String prefKey2 =
+                ChromePreferenceKeys.CHROME_SURVEY_PROMPT_DISPLAYED_TIMESTAMP.createKey(triggerId2);
+
+        // The new survey should not have been presented before.
+        Assert.assertFalse("SharedPref for triggerId1 should not be recorded.",
+                mSharedPreferences.contains(prefKey1));
+        Assert.assertFalse("SharedPref for triggerId2 should not be recorded.",
+                mSharedPreferences.contains(prefKey2));
+        Assert.assertFalse("Infobar for triggerId1 is marked displayed.",
+                controller1.hasInfoBarBeenDisplayed());
+        Assert.assertFalse("Infobar for triggerId2 is marked displayed.",
+                controller2.hasInfoBarBeenDisplayed());
+
+        mSharedPreferences.writeLong(prefKey1, System.currentTimeMillis());
+        Assert.assertTrue("Infobar for triggerId1 should be marked displayed.",
+                controller1.hasInfoBarBeenDisplayed());
+        Assert.assertFalse("Infobar for triggerId2 should not be marked displayed yet.",
+                controller2.hasInfoBarBeenDisplayed());
+
+        mSharedPreferences.writeLong(prefKey2, System.currentTimeMillis());
+        Assert.assertTrue("Infobar for trggerId2 should be marked displayed.",
+                controller2.hasInfoBarBeenDisplayed());
     }
 
     @Test
@@ -200,7 +223,7 @@
         private int mMaxNumber;
 
         RiggedSurveyController(int randomNumberToReturn, int dayOfYear, int maxNumber) {
-            super();
+            super(TEST_SURVEY_TRIGGER_ID);
             mRandomNumberToReturn = randomNumberToReturn;
             mDayOfYear = dayOfYear;
             mMaxNumber = maxNumber;
@@ -225,8 +248,8 @@
     class TestChromeSurveyController extends ChromeSurveyController {
         private Tab mTab;
 
-        public TestChromeSurveyController() {
-            super();
+        public TestChromeSurveyController(String triggerId) {
+            super(triggerId);
         }
 
         @Override
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 1a0711cc..f9c230a0 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3973,10 +3973,6 @@
      flag_descriptions::kKernelnextVMsName,
      flag_descriptions::kKernelnextVMsDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(features::kKernelnextVMs)},
-    {"enable-magnifier-new-focus-following",
-     flag_descriptions::kMagnifierNewFocusFollowingName,
-     flag_descriptions::kMagnifierNewFocusFollowingDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(features::kMagnifierNewFocusFollowing)},
     {"enable-magnifier-panning-improvements",
      flag_descriptions::kMagnifierPanningImprovementsName,
      flag_descriptions::kMagnifierPanningImprovementsDescription, kOsCrOS,
diff --git a/chrome/browser/accessibility/accessibility_extension_api.cc b/chrome/browser/accessibility/accessibility_extension_api.cc
index 2180054..6a7f5ba 100644
--- a/chrome/browser/accessibility/accessibility_extension_api.cc
+++ b/chrome/browser/accessibility/accessibility_extension_api.cc
@@ -455,9 +455,6 @@
   std::unique_ptr<accessibility_private::MoveMagnifierToRect::Params> params =
       accessibility_private::MoveMagnifierToRect::Params::Create(*args_);
   EXTENSION_FUNCTION_VALIDATE(params);
-  if (!features::IsMagnifierNewFocusFollowingEnabled()) {
-    return RespondNow(NoArguments());
-  }
   gfx::Rect bounds(params->rect.left, params->rect.top, params->rect.width,
                    params->rect.height);
 
diff --git a/chrome/browser/android/feed/v2/feed_service_bridge.cc b/chrome/browser/android/feed/v2/feed_service_bridge.cc
index 3342967..6493cdf1 100644
--- a/chrome/browser/android/feed/v2/feed_service_bridge.cc
+++ b/chrome/browser/android/feed/v2/feed_service_bridge.cc
@@ -12,12 +12,14 @@
 #include "base/check_op.h"
 #include "base/time/time.h"
 #include "chrome/browser/android/feed/v2/feed_service_factory.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/feed/android/jni_headers/FeedServiceBridge_jni.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "components/feed/core/shared_prefs/pref_names.h"
 #include "components/feed/core/v2/config.h"
 #include "components/feed/core/v2/public/feed_service.h"
+#include "components/metrics/metrics_service.h"
 #include "components/prefs/pref_service.h"
 
 namespace feed {
@@ -81,6 +83,10 @@
   pref_service->SetInteger(feed::prefs::kVideoPreviewsType, setting);
 }
 
+static jlong JNI_FeedServiceBridge_GetReliabilityLoggingId(JNIEnv* env) {
+  return FeedServiceBridge::GetReliabilityLoggingId();
+}
+
 std::string FeedServiceBridge::GetLanguageTag() {
   JNIEnv* env = base::android::AttachCurrentThread();
   return ConvertJavaStringToUTF8(env,
@@ -116,4 +122,16 @@
       env, base::android::ConvertUTF8ToJavaString(env, url.spec()));
 }
 
+uint64_t FeedServiceBridge::GetReliabilityLoggingId() {
+  PrefService* profile_prefs = ProfileManager::GetLastUsedProfile()->GetPrefs();
+  if (!g_browser_process->metrics_service()) {
+    // If for some reason we don't have the metrics client ID, an ID based only
+    // on the random "salt" will be generated.
+    return FeedService::GetReliabilityLoggingId(/*metrics_id=*/std::string(),
+                                                profile_prefs);
+  }
+  return FeedService::GetReliabilityLoggingId(
+      g_browser_process->metrics_service()->GetClientId(), profile_prefs);
+}
+
 }  // namespace feed
diff --git a/chrome/browser/android/feed/v2/feed_service_bridge.h b/chrome/browser/android/feed/v2/feed_service_bridge.h
index 3c9cc16..5bd073a 100644
--- a/chrome/browser/android/feed/v2/feed_service_bridge.h
+++ b/chrome/browser/android/feed/v2/feed_service_bridge.h
@@ -19,6 +19,7 @@
   static void ClearAll();
   static bool IsEnabled();
   static void PrefetchImage(const GURL& url);
+  static uint64_t GetReliabilityLoggingId();
 };
 
 }  // namespace feed
diff --git a/chrome/browser/ash/accessibility/accessibility_manager.cc b/chrome/browser/ash/accessibility/accessibility_manager.cc
index 3d48ca71..5ee9e01 100644
--- a/chrome/browser/ash/accessibility/accessibility_manager.cc
+++ b/chrome/browser/ash/accessibility/accessibility_manager.cc
@@ -556,11 +556,6 @@
 void AccessibilityManager::OnViewFocusedInArc(const gfx::Rect& bounds_in_screen,
                                               bool is_editable) {
   AccessibilityController::Get()->SetFocusHighlightRect(bounds_in_screen);
-
-  MagnificationManager* magnification_manager = MagnificationManager::Get();
-  if (magnification_manager)
-    magnification_manager->HandleFocusedRectChangedIfEnabled(bounds_in_screen,
-                                                             is_editable);
 }
 
 bool AccessibilityManager::PlayEarcon(Sound sound_key, PlaySoundOption option) {
diff --git a/chrome/browser/ash/accessibility/magnification_manager.cc b/chrome/browser/ash/accessibility/magnification_manager.cc
index 0fc28748..71e97a7 100644
--- a/chrome/browser/ash/accessibility/magnification_manager.cc
+++ b/chrome/browser/ash/accessibility/magnification_manager.cc
@@ -31,11 +31,6 @@
 namespace ash {
 namespace {
 
-// The duration of time to ignore focus changes after the last mouse event.
-// Keep under one frame length (~16ms at 60hz).
-constexpr base::TimeDelta kTimeIgnoreFocusChangeAfterMouseEvent =
-    base::TimeDelta::FromMilliseconds(15);
-
 MagnificationManager* g_magnification_manager = nullptr;
 
 }  // namespace
@@ -106,15 +101,6 @@
   SetProfile(nullptr);
 }
 
-void MagnificationManager::HandleFocusedRectChangedIfEnabled(
-    const gfx::Rect& bounds_in_screen,
-    bool is_editable) {
-  if (!fullscreen_magnifier_enabled_ && !IsDockedMagnifierEnabled())
-    return;
-
-  HandleFocusChanged(bounds_in_screen, is_editable);
-}
-
 void MagnificationManager::HandleMoveMagnifierToRectIfEnabled(
     const gfx::Rect& rect) {
   // Fullscreen magnifier and docked magnifier are mutually exclusive.
@@ -143,11 +129,6 @@
 
   ui::AXNodeData data;
   view->GetViewAccessibility().GetAccessibleNodeData(&data);
-
-  // Disallow focus on large containers, which probably should not move the
-  // magnified viewport to the center of the view.
-  if (ui::IsControl(data.role))
-    HandleFocusChanged(view->GetBoundsInScreen(), false);
 }
 
 void MagnificationManager::SetProfileForTest(Profile* profile) {
@@ -157,10 +138,6 @@
 MagnificationManager::MagnificationManager() {
   registrar_.Add(this, chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
                  content::NotificationService::AllSources());
-  // TODO(warx): observe focus changed in page notification when either
-  // fullscreen magnifier or docked magnifier is enabled.
-  registrar_.Add(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
-                 content::NotificationService::AllSources());
   user_manager::UserManager::Get()->AddSessionStateObserver(this);
   views::AXEventManager::Get()->AddObserver(this);
 }
@@ -183,10 +160,6 @@
         SetProfile(profile);
       break;
     }
-    case content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE: {
-      HandleFocusChangedInPage(details);
-      break;
-    }
   }
 }
 
@@ -332,47 +305,4 @@
   AccessibilityManager::Get()->NotifyAccessibilityStatusChanged(details);
 }
 
-void MagnificationManager::HandleFocusChangedInPage(
-    const content::NotificationDetails& details) {
-  const bool docked_magnifier_enabled = IsDockedMagnifierEnabled();
-  if (!fullscreen_magnifier_enabled_ && !docked_magnifier_enabled)
-    return;
-
-  content::FocusedNodeDetails* node_details =
-      content::Details<content::FocusedNodeDetails>(details).ptr();
-  // Ash uses the InputMethod of the window tree host to observe text input
-  // caret bounds changes, which works for both the native UI as well as
-  // webpages. We don't need to notify it of editable nodes in this case.
-  if (node_details->is_editable_node)
-    return;
-
-  HandleFocusChanged(node_details->node_bounds_in_screen,
-                     node_details->is_editable_node);
-}
-
-void MagnificationManager::HandleFocusChanged(const gfx::Rect& bounds_in_screen,
-                                              bool is_editable) {
-  if (features::IsMagnifierNewFocusFollowingEnabled())
-    return;
-
-  if (bounds_in_screen.IsEmpty())
-    return;
-
-  // Ignore focus changes while mouse activity is occurring.
-  if (base::TimeTicks::Now() - last_mouse_event_ <
-      kTimeIgnoreFocusChangeAfterMouseEvent) {
-    return;
-  }
-
-  // Fullscreen magnifier and docked magnifier are mutually exclusive.
-  if (fullscreen_magnifier_enabled_) {
-    Shell::Get()->magnification_controller()->HandleFocusedNodeChanged(
-        is_editable, bounds_in_screen);
-    return;
-  }
-  DCHECK(IsDockedMagnifierEnabled());
-  DockedMagnifierController::Get()->CenterOnPoint(
-      bounds_in_screen.CenterPoint());
-}
-
 }  // namespace ash
diff --git a/chrome/browser/ash/accessibility/magnification_manager.h b/chrome/browser/ash/accessibility/magnification_manager.h
index 50590f7..46fa944a 100644
--- a/chrome/browser/ash/accessibility/magnification_manager.h
+++ b/chrome/browser/ash/accessibility/magnification_manager.h
@@ -30,9 +30,6 @@
 //     desktop.
 //   - Watch change of the pref. When the pref changes, the setting of the
 //     magnifier will interlock with it.
-//
-// MagnificationManager also observes focus changed in page and calls Ash when
-// either Fullscreen or Docked magnifier is enabled.
 class MagnificationManager
     : public content::NotificationObserver,
       public user_manager::UserManager::UserSessionStateObserver,
@@ -67,10 +64,6 @@
   // Loads the Fullscreen magnifier scale from the pref.
   double GetSavedScreenMagnifierScale() const;
 
-  // Updates for a new focus rect (eg, from ARC++) if a magnifier is enabled.
-  void HandleFocusedRectChangedIfEnabled(const gfx::Rect& bounds_in_screen,
-                                         bool is_editable);
-
   // Move magnifier to ensure rect is within viewport if a magnifier is enabled.
   void HandleMoveMagnifierToRectIfEnabled(const gfx::Rect& rect);
 
@@ -108,12 +101,6 @@
   void UpdateMagnifierFromPrefs();
   void UpdateDockedMagnifierFromPrefs();
 
-  // Called when received content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE.
-  void HandleFocusChangedInPage(const content::NotificationDetails& details);
-
-  // Called in response to AXEventObserver.
-  void HandleFocusChanged(const gfx::Rect& bounds_in_screen, bool is_editable);
-
   Profile* profile_ = nullptr;
   base::ScopedObservation<Profile, ProfileObserver> profile_observation_{this};
 
diff --git a/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.cc b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.cc
index 7b43b14d5..a5821b6 100644
--- a/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.cc
+++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.cc
@@ -620,9 +620,8 @@
   if (accessibility_manager->IsSelectToSpeakEnabled() ||
       accessibility_manager->IsSwitchAccessEnabled() ||
       accessibility_manager->IsSpokenFeedbackEnabled() ||
-      (features::IsMagnifierNewFocusFollowingEnabled() &&
-       (magnification_manager->IsMagnifierEnabled() ||
-        magnification_manager->IsDockedMagnifierEnabled()))) {
+      magnification_manager->IsMagnifierEnabled() ||
+      magnification_manager->IsDockedMagnifierEnabled()) {
     return arc::mojom::AccessibilityFilterType::ALL;
   }
 
@@ -739,11 +738,7 @@
   if (!accessibility_manager || !magnification_manager)
     return;
 
-  is_focus_event_enabled_ =
-      (!features::IsMagnifierNewFocusFollowingEnabled() &&
-       (magnification_manager->IsMagnifierEnabled() ||
-        magnification_manager->IsDockedMagnifierEnabled())) ||
-      accessibility_manager->IsFocusHighlightEnabled();
+  is_focus_event_enabled_ = accessibility_manager->IsFocusHighlightEnabled();
 
   use_full_focus_mode_ = accessibility_manager->IsSwitchAccessEnabled() ||
                          accessibility_manager->IsSpokenFeedbackEnabled();
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
index b087f138..61f5e40 100644
--- a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
+++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
@@ -236,6 +236,7 @@
     case BinaryUploadService::Result::UPLOAD_FAILURE:
     case BinaryUploadService::Result::TIMEOUT:
     case BinaryUploadService::Result::FAILED_TO_GET_TOKEN:
+    case BinaryUploadService::Result::TOO_MANY_REQUESTS:
     // UNAUTHORIZED allows data usage since it's a result only obtained if the
     // browser is not authorized to perform deep scanning. It does not make
     // sense to block data in this situation since no actual scanning of the
@@ -447,6 +448,9 @@
     base::FilePath path,
     BinaryUploadService::Result result,
     enterprise_connectors::ContentAnalysisResponse response) {
+  if (result == BinaryUploadService::Result::TOO_MANY_REQUESTS)
+    throttled_ = true;
+
   // Find the path in the set of files that are being scanned.
   auto it = std::find(data_.paths.begin(), data_.paths.end(), path);
   DCHECK(it != data_.paths.end());
@@ -534,6 +538,8 @@
   request->set_per_profile_request(data_.settings.per_profile);
   for (const std::string& tag : data_.settings.tags)
     request->add_tag(tag);
+  if (data_.settings.client_metadata)
+    request->set_client_metadata(*data_.settings.client_metadata);
 }
 
 void ContentAnalysisDelegate::FillAllResultsWith(bool status) {
@@ -611,6 +617,14 @@
     return;
   }
 
+  // If |throttled_| is true, then the file shouldn't be upload since the server
+  // is receiving too many requests.
+  if (throttled_) {
+    request->FinishRequest(BinaryUploadService::Result::TOO_MANY_REQUESTS,
+                           enterprise_connectors::ContentAnalysisResponse());
+    return;
+  }
+
   UploadFileForDeepScanning(result, data_.paths[index], std::move(request));
 }
 
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h
index fbab5d6..a6b257e 100644
--- a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h
+++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h
@@ -360,6 +360,10 @@
   // for every file/text. This is read to ensure |this| isn't deleted too early.
   bool data_uploaded_ = false;
 
+  // This is set to true as soon as a TOO_MANY_REQUESTS response is obtained. No
+  // more data should be upload for |this| at that point.
+  bool throttled_ = false;
+
   base::TimeTicks upload_start_time_;
 
   base::WeakPtrFactory<ContentAnalysisDelegate> weak_ptr_factory_{this};
diff --git a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate_browsertest.cc b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate_browsertest.cc
index cd17970..1f571275 100644
--- a/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate_browsertest.cc
+++ b/chrome/browser/enterprise/connectors/analysis/content_analysis_delegate_browsertest.cc
@@ -511,6 +511,88 @@
   ASSERT_EQ(FakeBinaryUploadServiceStorage()->requests_count(), 2);
 }
 
+IN_PROC_BROWSER_TEST_P(ContentAnalysisDelegateBrowserTest, Throttled) {
+  base::ScopedAllowBlockingForTesting allow_blocking;
+
+  // Set up delegate and upload service.
+  EnableUploadsScanningAndReporting();
+
+  ContentAnalysisDelegate::SetFactoryForTesting(
+      base::BindRepeating(&MinimalFakeContentAnalysisDelegate::Create));
+
+  FakeBinaryUploadServiceStorage()->SetAuthorized(true);
+  FakeBinaryUploadServiceStorage()->SetShouldAutomaticallyAuthorize(true);
+
+  // Create the files to be opened and scanned.
+  ContentAnalysisDelegate::Data data;
+  CreateFilesForTest({"a.exe", "b.exe", "c.exe"},
+                     {"a content", "b content", "c content"}, &data);
+  ASSERT_TRUE(ContentAnalysisDelegate::IsEnabled(
+      browser()->profile(), GURL(kTestUrl), &data, FILE_ATTACHED));
+
+  // The malware verdict means an event should be reported.
+  safe_browsing::EventReportValidator validator(client());
+  validator.ExpectUnscannedFileEvents(
+      /*url*/ "about:blank",
+      {
+          created_file_paths()[0].AsUTF8Unsafe(),
+          created_file_paths()[1].AsUTF8Unsafe(),
+          created_file_paths()[2].AsUTF8Unsafe(),
+      },
+      {
+          // printf "a content" | sha256sum | tr '[:lower:]' '[:upper:]'
+          "D2D2ACF640179223BF9E1EB43C5FBF854C4E50FFB6733BC3A9279D3FF7DE9BE1",
+          // printf "b content" | sha256sum | tr '[:lower:]' '[:upper:]'
+          "93CB3641ADD6A9A6619D7E2F304EBCF5160B2DB016B27C6E3D641C5306897224",
+          // printf "c content" | sha256sum | tr '[:lower:]' '[:upper:]'
+          "2E6D1C4A1F39A02562BF1505AD775C0323D7A04C0C37C9B29D25F532B9972080",
+      },
+      /*trigger*/ SafeBrowsingPrivateEventRouter::kTriggerFileUpload,
+      // TODO(crbug.com/1191060): Update this string when the event is supported
+      /*reason*/ "SERVICE_UNAVAILABLE",
+      /*mimetypes*/ ExeMimeTypes(),
+      /*size*/ 9,
+      /*result*/
+      safe_browsing::EventResultToString(safe_browsing::EventResult::ALLOWED),
+      /*username*/ kUserName);
+
+  // While only one file should reach the upload part and get a
+  // TOO_MANY_REQUEST result, it can be any of them depending on how quickly
+  // they are opened asynchronously. This means responses must be set up for
+  // each of them.
+  for (const std::string& file_name : {"a.exe", "b.exe", "c.exe"}) {
+    FakeBinaryUploadServiceStorage()->SetResponseForFile(
+        file_name, BinaryUploadService::Result::TOO_MANY_REQUESTS,
+        ContentAnalysisResponse());
+  }
+
+  bool called = false;
+  base::RunLoop run_loop;
+  SetQuitClosure(run_loop.QuitClosure());
+
+  // Start test.
+  ContentAnalysisDelegate::CreateForWebContents(
+      browser()->tab_strip_model()->GetActiveWebContents(), std::move(data),
+      base::BindLambdaForTesting(
+          [&called](const ContentAnalysisDelegate::Data& data,
+                    const ContentAnalysisDelegate::Result& result) {
+            ASSERT_TRUE(result.text_results.empty());
+            ASSERT_EQ(result.paths_results.size(), 3u);
+            for (bool result : result.paths_results)
+              ASSERT_TRUE(result);
+            called = true;
+          }),
+      safe_browsing::DeepScanAccessPoint::UPLOAD);
+
+  run_loop.Run();
+
+  EXPECT_TRUE(called);
+
+  // There should have been 1 request for the first file and 1 for
+  // authentication.
+  ASSERT_EQ(FakeBinaryUploadServiceStorage()->requests_count(), 2);
+}
+
 // This class tests each of the blocking settings used in Connector policies:
 // - block_until_verdict
 // - block_password_protected
diff --git a/chrome/browser/enterprise/connectors/common.h b/chrome/browser/enterprise/connectors/common.h
index 9025b5c..e53edb18 100644
--- a/chrome/browser/enterprise/connectors/common.h
+++ b/chrome/browser/enterprise/connectors/common.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_ENTERPRISE_CONNECTORS_COMMON_H_
 #define CHROME_BROWSER_ENTERPRISE_CONNECTORS_COMMON_H_
 
+#include <memory>
 #include <set>
 #include <string>
 #include <vector>
@@ -83,6 +84,10 @@
   // Indicates if the scan is made at the profile level, or at the browser level
   // if false.
   bool per_profile = false;
+
+  // ClientMetadata to include in the scanning request(s). This is populated
+  // based on OnSecurityEvent and the affiliation state of the browser.
+  std::unique_ptr<ClientMetadata> client_metadata = nullptr;
 };
 
 struct ReportingSettings {
diff --git a/chrome/browser/enterprise/connectors/connectors_service.cc b/chrome/browser/enterprise/connectors/connectors_service.cc
index 9ea20a7..a682d6a 100644
--- a/chrome/browser/enterprise/connectors/connectors_service.cc
+++ b/chrome/browser/enterprise/connectors/connectors_service.cc
@@ -7,6 +7,8 @@
 
 #include "base/memory/singleton.h"
 #include "base/no_destructor.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/enterprise/connectors/common.h"
@@ -16,19 +18,111 @@
 #include "chrome/browser/policy/chrome_browser_policy_connector.h"
 #include "chrome/browser/policy/dm_token_utils.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "components/embedder_support/user_agent_utils.h"
 #include "components/enterprise/browser/controller/browser_dm_token_storage.h"
 #include "components/enterprise/common/proto/connectors.pb.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/policy/core/common/cloud/cloud_policy_util.h"
 #include "components/policy/core/common/cloud/dm_token.h"
 #include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h"
 #include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
 #include "components/policy/core/common/policy_types.h"
 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
+#include "components/signin/public/identity_manager/consent_level.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/user_prefs/user_prefs.h"
+#include "components/version_info/version_info.h"
 #include "content/public/browser/browser_context.h"
+#include "device_management_backend.pb.h"
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
+#endif
 
 namespace enterprise_connectors {
 
+namespace {
+
+const enterprise_management::PolicyData* GetProfilePolicyData(
+    Profile* profile) {
+  DCHECK(profile);
+  auto* manager =
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+      profile->GetUserCloudPolicyManagerChromeOS();
+#else
+      profile->GetUserCloudPolicyManager();
+#endif
+  if (manager && manager->core()->store() &&
+      manager->core()->store()->has_policy()) {
+    return manager->core()->store()->policy();
+  }
+  return nullptr;
+}
+
+void PopulateBrowserMetadata(bool include_device_info,
+                             ClientMetadata::Browser* browser_proto) {
+  base::FilePath browser_id;
+  if (base::PathService::Get(base::DIR_EXE, &browser_id))
+    browser_proto->set_browser_id(browser_id.AsUTF8Unsafe());
+  browser_proto->set_user_agent(embedder_support::GetUserAgent());
+  browser_proto->set_chrome_version(version_info::GetVersionNumber());
+  if (include_device_info)
+    browser_proto->set_machine_user(policy::GetOSUsername());
+}
+
+void PopulateDeviceMetadata(const ReportingSettings& reporting_settings,
+                            Profile* profile,
+                            ClientMetadata::Device* device_proto) {
+  if (!reporting_settings.per_profile)
+    device_proto->set_dm_token(reporting_settings.dm_token);
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  std::string client_id;
+  auto* manager = profile->GetUserCloudPolicyManagerChromeOS();
+  if (manager && manager->core() && manager->core()->client())
+    client_id = manager->core()->client()->client_id();
+#else
+  std::string client_id =
+      policy::BrowserDMTokenStorage::Get()->RetrieveClientId();
+#endif
+  device_proto->set_client_id(client_id);
+  device_proto->set_os_version(policy::GetOSVersion());
+  device_proto->set_os_platform(policy::GetOSPlatform());
+  device_proto->set_name(policy::GetDeviceName());
+}
+
+void PopulateProfileMetadata(const ReportingSettings& reporting_settings,
+                             Profile* profile,
+                             ClientMetadata::Profile* profile_proto) {
+  if (reporting_settings.per_profile)
+    profile_proto->set_dm_token(reporting_settings.dm_token);
+  auto* identity_manager = IdentityManagerFactory::GetForProfile(profile);
+  if (identity_manager) {
+    profile_proto->set_gaia_email(
+        identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin)
+            .email);
+  }
+  profile_proto->set_profile_path(profile->GetPath().AsUTF8Unsafe());
+  ProfileAttributesEntry* entry =
+      g_browser_process->profile_manager()
+          ->GetProfileAttributesStorage()
+          .GetProfileAttributesWithPath(profile->GetPath());
+  if (entry) {
+    profile_proto->set_profile_name(base::UTF16ToUTF8(entry->GetName()));
+  }
+  const enterprise_management::PolicyData* profile_policy =
+      GetProfilePolicyData(profile);
+  if (profile_policy) {
+    if (profile_policy->has_device_id())
+      profile_proto->set_client_id(profile_policy->device_id());
+  }
+}
+
+}  // namespace
+
 const base::Feature kEnterpriseConnectorsEnabled{
     "EnterpriseConnectorsEnabled", base::FEATURE_ENABLED_BY_DEFAULT};
 
@@ -179,6 +273,7 @@
   settings.value().dm_token = dm_token.value().value;
   settings.value().per_profile =
       dm_token.value().scope == policy::POLICY_SCOPE_USER;
+  settings.value().client_metadata = BuildClientMetadata();
 
   return settings;
 }
@@ -359,6 +454,29 @@
   return !Profile::FromBrowserContext(context_)->IsOffTheRecord();
 }
 
+std::unique_ptr<ClientMetadata> ConnectorsService::BuildClientMetadata() {
+  // Check the reporting policy value to check if the analysis should include
+  // browser/device/profile information.
+  auto reporting_settings =
+      GetReportingSettings(ReportingConnector::SECURITY_EVENT);
+  if (!reporting_settings.has_value())
+    return nullptr;
+
+  bool include_device_info = !reporting_settings.value().per_profile;
+  Profile* profile = Profile::FromBrowserContext(context_);
+
+  auto metadata = std::make_unique<ClientMetadata>();
+  PopulateBrowserMetadata(include_device_info, metadata->mutable_browser());
+  if (include_device_info) {
+    PopulateDeviceMetadata(reporting_settings.value(), profile,
+                           metadata->mutable_device());
+  }
+  PopulateProfileMetadata(reporting_settings.value(), profile,
+                          metadata->mutable_profile());
+
+  return metadata;
+}
+
 // ---------------------------------------
 // ConnectorsServiceFactory implementation
 // ---------------------------------------
diff --git a/chrome/browser/enterprise/connectors/connectors_service.h b/chrome/browser/enterprise/connectors/connectors_service.h
index e0415ce..b318586 100644
--- a/chrome/browser/enterprise/connectors/connectors_service.h
+++ b/chrome/browser/enterprise/connectors/connectors_service.h
@@ -10,6 +10,7 @@
 #include "base/feature_list.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/enterprise/connectors/connectors_manager.h"
+#include "components/enterprise/common/proto/connectors.pb.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/policy/core/common/policy_types.h"
@@ -118,6 +119,10 @@
   // - The profile is incognito
   bool ConnectorsEnabled() const;
 
+  // Obtain a ClientMetadata instance corresponding to the current
+  // OnSecurityEvent policy value.
+  std::unique_ptr<ClientMetadata> BuildClientMetadata();
+
   content::BrowserContext* context_;
   std::unique_ptr<ConnectorsManager> connectors_manager_;
 };
diff --git a/chrome/browser/enterprise/connectors/connectors_service_browsertest.cc b/chrome/browser/enterprise/connectors/connectors_service_browsertest.cc
index 98a6537..c381934 100644
--- a/chrome/browser/enterprise/connectors/connectors_service_browsertest.cc
+++ b/chrome/browser/enterprise/connectors/connectors_service_browsertest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/json/json_reader.h"
+#include "base/path_service.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/enterprise/connectors/common.h"
@@ -48,6 +49,7 @@
 constexpr char kFakeProfileDMToken[] = "fake-profile-dm-token";
 constexpr char kFakeEnrollmentToken[] = "fake-enrollment-token";
 constexpr char kFakeBrowserClientId[] = "fake-browser-client-id";
+constexpr char kFakeProfileClientId[] = "fake-profile-client-id";
 constexpr char kAffiliationId1[] = "affiliation-id-1";
 constexpr char kAffiliationId2[] = "affiliation-id-2";
 #endif
@@ -115,6 +117,7 @@
     auto profile_policy_data =
         std::make_unique<enterprise_management::PolicyData>();
     profile_policy_data->add_user_affiliation_ids(kAffiliationId1);
+    profile_policy_data->set_device_id(kFakeProfileClientId);
     profile_policy_manager->core()->store()->set_policy_data_for_testing(
         std::move(profile_policy_data));
 
@@ -144,16 +147,22 @@
 
   void SetPrefs(const char* pref,
                 const char* scope_pref,
-                const char* pref_value) {
+                const char* pref_value,
+                bool profile_scope = true) {
     browser()->profile()->GetPrefs()->Set(pref,
                                           *base::JSONReader::Read(pref_value));
-    browser()->profile()->GetPrefs()->SetInteger(scope_pref,
-                                                 policy::POLICY_SCOPE_USER);
+    browser()->profile()->GetPrefs()->SetInteger(
+        scope_pref, profile_scope ? policy::POLICY_SCOPE_USER
+                                  : policy::POLICY_SCOPE_MACHINE);
   }
-  void SetPrefs(const char* pref, const char* scope_pref, int pref_value) {
+  void SetPrefs(const char* pref,
+                const char* scope_pref,
+                int pref_value,
+                bool profile_scope = true) {
     browser()->profile()->GetPrefs()->SetInteger(pref, pref_value);
-    browser()->profile()->GetPrefs()->SetInteger(scope_pref,
-                                                 policy::POLICY_SCOPE_USER);
+    browser()->profile()->GetPrefs()->SetInteger(
+        scope_pref, profile_scope ? policy::POLICY_SCOPE_USER
+                                  : policy::POLICY_SCOPE_MACHINE);
   }
 
   ManagementStatus management_status() { return management_status_; }
@@ -223,6 +232,35 @@
   ConnectorsServiceAnalysisProfileBrowserTest()
       : ConnectorsServiceProfileBrowserTest(std::get<1>(GetParam())) {}
   AnalysisConnector connector() { return std::get<0>(GetParam()); }
+
+  void ValidateClientMetadata(const ClientMetadata& metadata,
+                              bool profile_reporting) {
+    ASSERT_TRUE(metadata.has_browser());
+    ASSERT_TRUE(metadata.browser().has_browser_id());
+    ASSERT_TRUE(metadata.browser().has_user_agent());
+    ASSERT_TRUE(metadata.browser().has_chrome_version());
+    ASSERT_NE(profile_reporting, metadata.browser().has_machine_user());
+
+    ASSERT_NE(profile_reporting, metadata.has_device());
+    if (!profile_reporting) {
+      // The device DM token should only be populated when reporting is set at
+      // the device level, aka not the profile level.
+      ASSERT_NE(profile_reporting, metadata.device().has_dm_token());
+      ASSERT_TRUE(metadata.device().has_client_id());
+      ASSERT_TRUE(metadata.device().has_os_version());
+      ASSERT_TRUE(metadata.device().has_os_platform());
+      ASSERT_TRUE(metadata.device().has_name());
+    }
+
+    ASSERT_TRUE(metadata.has_profile());
+    ASSERT_EQ(profile_reporting, metadata.profile().has_dm_token());
+    ASSERT_TRUE(metadata.profile().has_gaia_email());
+    ASSERT_TRUE(metadata.profile().has_profile_path());
+    ASSERT_TRUE(metadata.profile().has_profile_name());
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+    ASSERT_TRUE(metadata.profile().has_client_id());
+#endif
+  }
 };
 
 INSTANTIATE_TEST_SUITE_P(
@@ -234,7 +272,75 @@
                         ManagementStatus::UNAFFILIATED,
                         ManagementStatus::UNMANAGED)));
 
-IN_PROC_BROWSER_TEST_P(ConnectorsServiceAnalysisProfileBrowserTest, Test) {
+IN_PROC_BROWSER_TEST_P(ConnectorsServiceAnalysisProfileBrowserTest,
+                       DeviceReporting) {
+  SetPrefs(ConnectorPref(connector()), ConnectorScopePref(connector()),
+           kNormalAnalysisSettingsPref, /*profile_scope*/ false);
+  SetPrefs(ConnectorPref(ReportingConnector::SECURITY_EVENT),
+           ConnectorScopePref(ReportingConnector::SECURITY_EVENT),
+           kNormalReportingSettingsPref, /*profile_scope*/ false);
+  auto settings =
+      ConnectorsServiceFactory::GetForBrowserContext(browser()->profile())
+          ->GetAnalysisSettings(GURL(kTestUrl), connector());
+
+  if (management_status() == ManagementStatus::UNMANAGED) {
+    ASSERT_FALSE(settings.has_value());
+  } else {
+    ASSERT_TRUE(settings.has_value());
+    ASSERT_EQ(kFakeBrowserDMToken, settings.value().dm_token);
+    ASSERT_FALSE(settings.value().per_profile);
+    ValidateClientMetadata(*settings.value().client_metadata,
+                           /*profile_reporting*/ false);
+  }
+}
+
+IN_PROC_BROWSER_TEST_P(ConnectorsServiceAnalysisProfileBrowserTest,
+                       ProfileReporting) {
+  SetPrefs(ConnectorPref(connector()), ConnectorScopePref(connector()),
+           kNormalAnalysisSettingsPref);
+  SetPrefs(ConnectorPref(ReportingConnector::SECURITY_EVENT),
+           ConnectorScopePref(ReportingConnector::SECURITY_EVENT),
+           kNormalReportingSettingsPref);
+  auto settings =
+      ConnectorsServiceFactory::GetForBrowserContext(browser()->profile())
+          ->GetAnalysisSettings(GURL(kTestUrl), connector());
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  if (management_status() == ManagementStatus::UNMANAGED) {
+    ASSERT_FALSE(settings.has_value());
+  } else {
+    ASSERT_TRUE(settings.has_value());
+    ASSERT_EQ(kFakeBrowserDMToken, settings.value().dm_token);
+    ASSERT_FALSE(settings.value().per_profile);
+    ValidateClientMetadata(*settings.value().client_metadata,
+                           /*profile_reporting*/ false);
+  }
+#else
+  switch (management_status()) {
+    case ManagementStatus::AFFILIATED:
+      EXPECT_TRUE(settings.has_value());
+      ASSERT_EQ(kFakeProfileDMToken, settings.value().dm_token);
+      ASSERT_TRUE(settings.value().per_profile);
+      ValidateClientMetadata(*settings.value().client_metadata,
+                             /*profile_reporting*/ true);
+      break;
+    case ManagementStatus::UNAFFILIATED:
+      EXPECT_FALSE(settings.has_value());
+      break;
+    case ManagementStatus::UNMANAGED:
+      EXPECT_TRUE(settings.has_value());
+      ASSERT_EQ(kFakeProfileDMToken, settings.value().dm_token);
+      ASSERT_TRUE(settings.value().per_profile);
+      ASSERT_TRUE(settings.value().client_metadata);
+      ValidateClientMetadata(*settings.value().client_metadata,
+                             /*profile_reporting*/ true);
+      break;
+  }
+#endif
+}
+
+IN_PROC_BROWSER_TEST_P(ConnectorsServiceAnalysisProfileBrowserTest,
+                       NoReporting) {
   SetPrefs(ConnectorPref(connector()), ConnectorScopePref(connector()),
            kNormalAnalysisSettingsPref);
   auto settings =
@@ -248,6 +354,7 @@
     ASSERT_TRUE(settings.has_value());
     ASSERT_EQ(kFakeBrowserDMToken, settings.value().dm_token);
     ASSERT_FALSE(settings.value().per_profile);
+    ASSERT_FALSE(settings.value().client_metadata);
   }
 #else
   switch (management_status()) {
@@ -255,6 +362,7 @@
       EXPECT_TRUE(settings.has_value());
       ASSERT_EQ(kFakeProfileDMToken, settings.value().dm_token);
       ASSERT_TRUE(settings.value().per_profile);
+      ASSERT_FALSE(settings.value().client_metadata);
       break;
     case ManagementStatus::UNAFFILIATED:
       EXPECT_FALSE(settings.has_value());
@@ -263,6 +371,7 @@
       EXPECT_TRUE(settings.has_value());
       ASSERT_EQ(kFakeProfileDMToken, settings.value().dm_token);
       ASSERT_TRUE(settings.value().per_profile);
+      ASSERT_FALSE(settings.value().client_metadata);
       break;
   }
 #endif
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedServiceBridge.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedServiceBridge.java
index a0fe550..7b92eb3 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedServiceBridge.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedServiceBridge.java
@@ -122,6 +122,10 @@
         FeedServiceBridgeJni.get().setVideoPreviewsTypePreference(videoPreviewsType);
     }
 
+    public static long getReliabilityLoggingId() {
+        return FeedServiceBridgeJni.get().getReliabilityLoggingId();
+    }
+
     @NativeMethods
     public interface Natives {
         boolean isEnabled();
@@ -132,5 +136,6 @@
         void reportOpenVisitComplete(long visitTimeMs);
         int getVideoPreviewsTypePreference();
         void setVideoPreviewsTypePreference(int videoPreviewsType);
+        long getReliabilityLoggingId();
     }
 }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index cec0a14..373395a 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2030,11 +2030,6 @@
     "expiry_milestone": 92
   },
   {
-    "name": "enable-magnifier-new-focus-following",
-    "owners": [ "josiahk", "//ui/accessibility/OWNERS" ],
-    "expiry_milestone": 92
-  },
-  {
     "name": "enable-magnifier-panning-improvements",
     "owners": [ "josiahk", "//ui/accessibility/OWNERS" ],
     "expiry_milestone": 92
@@ -2700,7 +2695,7 @@
   {
     "name": "enable-webrtc-pipewire-capturer",
     "owners": [ "tomas.popela@gmail.com" ],
-    "expiry_milestone": 90
+    "expiry_milestone": 100
   },
   {
     "name": "enable-webrtc-remote-event-log",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index f2ef46c..0ab5e3e 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -4417,12 +4417,6 @@
     "Enable a setup guide to walk through the steps of initially configuring "
     "Switch Access.";
 
-const char kMagnifierNewFocusFollowingName[] =
-    "Enable new focus following in Magnifier";
-const char kMagnifierNewFocusFollowingDescription[] =
-    "Enable feature which allows more comprehensive focus following in"
-    "in Magnifier.";
-
 const char kMagnifierPanningImprovementsName[] =
     "Enable panning improvements in magnifier";
 const char kMagnifierPanningImprovementsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 7bbc2359..a6f5a6c 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2565,9 +2565,6 @@
 extern const char kExperimentalAccessibilitySwitchAccessSetupGuideName[];
 extern const char kExperimentalAccessibilitySwitchAccessSetupGuideDescription[];
 
-extern const char kMagnifierNewFocusFollowingName[];
-extern const char kMagnifierNewFocusFollowingDescription[];
-
 extern const char kMagnifierPanningImprovementsName[];
 extern const char kMagnifierPanningImprovementsDescription[];
 
diff --git a/chrome/browser/history_clusters/history_clusters_tab_helper.cc b/chrome/browser/history_clusters/history_clusters_tab_helper.cc
index 3fdff6f..a0a14e8 100644
--- a/chrome/browser/history_clusters/history_clusters_tab_helper.cc
+++ b/chrome/browser/history_clusters/history_clusters_tab_helper.cc
@@ -115,14 +115,17 @@
 HistoryClustersTabHelper::~HistoryClustersTabHelper() = default;
 
 void HistoryClustersTabHelper::OnOmniboxUrlCopied() {
-  DCHECK(!navigation_ids_.empty());
+  // It's possible that there have been no navigations if certain builtin pages
+  // were opened in a new tab (e.g. chrome://crash or chrome://invalid-page).
+  if (navigation_ids_.empty())
+    return;
   auto* memories_service = GetMemoriesService();
   // It's possible that the last navigation is complete if the tab crashed and a
   // new navigation hasn't began.
-  if (memories_service->HasIncompleteVisit(navigation_ids_.back())) {
-    memories_service->GetIncompleteVisit(navigation_ids_.back())
-        .context_signals.omnibox_url_copied = true;
-  }
+  if (!memories_service->HasIncompleteVisit(navigation_ids_.back()))
+    return;
+  memories_service->GetIncompleteVisit(navigation_ids_.back())
+      .context_signals.omnibox_url_copied = true;
 }
 
 void HistoryClustersTabHelper::OnUpdatedHistoryForNavigation(
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLocaleUtils.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLocaleUtils.java
index 241e372..e7a0a75 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLocaleUtils.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/AppLocaleUtils.java
@@ -80,8 +80,4 @@
             listener.onComplete(true);
         }
     }
-
-    public static boolean languageSplitAvalilable(String language) {
-      return LanguageSplitInstaller.getInstance().getInstalledLanguages().contains(language);
-    }
 }
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/GlobalAppLocaleController.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/GlobalAppLocaleController.java
index 6a8acffb..c7e70f2b 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/GlobalAppLocaleController.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/GlobalAppLocaleController.java
@@ -38,8 +38,7 @@
         mOverrideLanguage = AppLocaleUtils.getAppLanguagePrefStartUp(base);
 
         mIsOverridden = !TextUtils.isEmpty(mOverrideLanguage)
-                && !TextUtils.equals(mOriginalSystemLocal.toLanguageTag(), mOverrideLanguage)
-                && AppLocaleUtils.languageSplitAvalilable(mOverrideLanguage);
+                && !TextUtils.equals(mOriginalSystemLocal.toLanguageTag(), mOverrideLanguage);
         return mIsOverridden;
     }
 
diff --git a/chrome/browser/long_screenshots/long_screenshots_tab_service.h b/chrome/browser/long_screenshots/long_screenshots_tab_service.h
index 3b49b468..facfea3 100644
--- a/chrome/browser/long_screenshots/long_screenshots_tab_service.h
+++ b/chrome/browser/long_screenshots/long_screenshots_tab_service.h
@@ -43,6 +43,11 @@
   // Define a list of statuses to describe the calling of paint preview and
   // generation of the bitmap.
   //
+  // When updating this, also update LongScreenshotsMetrics in
+  // /chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMetrics.java
+  // and SharingLongScreenshotsEvent in enums.xml
+  // and logCaptureResultStatus() in ./bitmap_generation/BitmapGenerator.java
+  //
   // A Java counterpart will be generated for this enum.
   // GENERATED_JAVA_ENUM_PACKAGE: (
   // org.chromium.chrome.browser.share.long_screenshots.bitmap_generation)
diff --git a/chrome/browser/policy/browsing_history_policy_handler.cc b/chrome/browser/policy/browsing_history_policy_handler.cc
index b322622..b9797600 100644
--- a/chrome/browser/policy/browsing_history_policy_handler.cc
+++ b/chrome/browser/policy/browsing_history_policy_handler.cc
@@ -22,9 +22,7 @@
     const PolicyMap& policies,
     PrefValueMap* prefs) {
   const base::Value* value = policies.GetValue(policy_name());
-  bool deleting_history_allowed;
-  if (value && value->GetAsBoolean(&deleting_history_allowed) &&
-      !deleting_history_allowed) {
+  if (value && value->is_bool() && !value->GetBool()) {
     prefs->SetBoolean(browsing_data::prefs::kDeleteBrowsingHistory, false);
     prefs->SetBoolean(browsing_data::prefs::kDeleteBrowsingHistoryBasic, false);
     prefs->SetBoolean(browsing_data::prefs::kDeleteDownloadHistory, false);
diff --git a/chrome/browser/policy/file_selection_dialogs_policy_handler.cc b/chrome/browser/policy/file_selection_dialogs_policy_handler.cc
index 1a304928..169ecb68 100644
--- a/chrome/browser/policy/file_selection_dialogs_policy_handler.cc
+++ b/chrome/browser/policy/file_selection_dialogs_policy_handler.cc
@@ -21,9 +21,9 @@
 void FileSelectionDialogsPolicyHandler::ApplyPolicySettings(
     const PolicyMap& policies,
     PrefValueMap* prefs) {
-  bool allow_dialogs;
   const base::Value* value = policies.GetValue(policy_name());
-  if (value && value->GetAsBoolean(&allow_dialogs)) {
+  if (value && value->is_bool()) {
+    bool allow_dialogs = value->GetBool();
     prefs->SetBoolean(prefs::kAllowFileSelectionDialogs, allow_dialogs);
     // Disallow selecting the download location if file dialogs are disabled.
     if (!allow_dialogs)
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
index 57b363f..9df07c8 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -98,6 +98,13 @@
      */
     public static final String CHROME_DEFAULT_BROWSER = "applink.chrome_default_browser";
 
+    /**
+     * Key prefix used to indicate the timestamps when the survey info bar is displayed for a
+     * certain survey.
+     */
+    public static final KeyPrefix CHROME_SURVEY_PROMPT_DISPLAYED_TIMESTAMP =
+            new KeyPrefix("Chrome.Survey.PromptDisplayedTimestamp.*");
+
     /** The URI of Chrome shared URI to Android system clibpoard. */
     public static final String CLIPBOARD_SHARED_URI = "Chrome.Clipboard.SharedUri";
 
@@ -822,12 +829,6 @@
     public static final String SNAPSHOT_DATABASE_REMOVED = "snapshot_database_removed";
 
     public static final String SURVEY_DATE_LAST_ROLLED = "last_rolled_for_chrome_survey_key";
-    /**
-     *  The survey questions for this survey are the same as those in the survey used for Chrome
-     *  Home, so we reuse the old infobar key to prevent the users from seeing the same survey more
-     *  than once.
-     */
-    public static final String SURVEY_INFO_BAR_DISPLAYED = "chrome_home_survey_info_bar_displayed";
 
     public static final String TABBED_ACTIVITY_LAST_BACKGROUNDED_TIME_MS_PREF =
             "ChromeTabbedActivity.BackgroundTimeMs";
@@ -953,6 +954,7 @@
                 AUTOFILL_ASSISTANT_NUMBER_OF_LITE_SCRIPTS_CANCELED,
                 AUTOFILL_ASSISTANT_PROACTIVE_HELP,
                 APPLICATION_OVERRIDE_LANGUAGE,
+                CHROME_SURVEY_PROMPT_DISPLAYED_TIMESTAMP.pattern(),
                 CLIPBOARD_SHARED_URI,
                 CLIPBOARD_SHARED_URI_TIMESTAMP,
                 COMMERCE_SUBSCRIPTIONS_CHROME_MANAGED_TIMESTAMP,
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
index d383c091..68376a9 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
@@ -49,6 +49,7 @@
                 "chrome_home_enabled_date",
                 "chrome_home_info_promo_shown",
                 "chrome_home_opt_out_snackbar_shown",
+                "chrome_home_survey_info_bar_displayed",
                 "chrome_home_user_enabled",
                 "chrome_modern_design_enabled",
                 "chromium.invalidations.uuid",
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/LegacyChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/LegacyChromePreferenceKeys.java
index 22ef17fa..dfe818f3 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/LegacyChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/LegacyChromePreferenceKeys.java
@@ -160,7 +160,6 @@
                 ChromePreferenceKeys.SIGNIN_LEGACY_SYNC_ACCOUNT_EMAIL,
                 ChromePreferenceKeys.SNAPSHOT_DATABASE_REMOVED,
                 ChromePreferenceKeys.SURVEY_DATE_LAST_ROLLED,
-                ChromePreferenceKeys.SURVEY_INFO_BAR_DISPLAYED,
                 ChromePreferenceKeys.TABBED_ACTIVITY_LAST_BACKGROUNDED_TIME_MS_PREF,
                 ChromePreferenceKeys.TABMODEL_ACTIVE_TAB_ID,
                 ChromePreferenceKeys.TABMODEL_HAS_COMPUTED_MAX_ID,
diff --git a/chrome/browser/profiles/force_safe_search_policy_handler.cc b/chrome/browser/profiles/force_safe_search_policy_handler.cc
index 237d9bb..e17f527 100644
--- a/chrome/browser/profiles/force_safe_search_policy_handler.cc
+++ b/chrome/browser/profiles/force_safe_search_policy_handler.cc
@@ -38,12 +38,12 @@
 
     // Note that ForceYouTubeRestrict is an int policy, we cannot simply deep
     // copy value, which is a boolean.
-    bool enabled = false;
-    if (value->GetAsBoolean(&enabled)) {
+    if (value->is_bool()) {
       prefs->SetValue(
           prefs::kForceYouTubeRestrict,
-          base::Value(enabled ? safe_search_util::YOUTUBE_RESTRICT_MODERATE
-                              : safe_search_util::YOUTUBE_RESTRICT_OFF));
+          base::Value(value->GetBool()
+                          ? safe_search_util::YOUTUBE_RESTRICT_MODERATE
+                          : safe_search_util::YOUTUBE_RESTRICT_OFF));
     }
   }
 }
diff --git a/chrome/browser/profiles/incognito_mode_policy_handler.cc b/chrome/browser/profiles/incognito_mode_policy_handler.cc
index 7db135a..0cbe5cf0 100644
--- a/chrome/browser/profiles/incognito_mode_policy_handler.cc
+++ b/chrome/browser/profiles/incognito_mode_policy_handler.cc
@@ -87,11 +87,11 @@
   } else if (deprecated_enabled) {
     // If kIncognitoModeAvailability is not specified, check the obsolete
     // kIncognitoEnabled.
-    bool enabled = true;
-    if (deprecated_enabled->GetAsBoolean(&enabled)) {
-      prefs->SetInteger(
-          prefs::kIncognitoModeAvailability,
-          enabled ? IncognitoModePrefs::ENABLED : IncognitoModePrefs::DISABLED);
+    if (deprecated_enabled->is_bool()) {
+      prefs->SetInteger(prefs::kIncognitoModeAvailability,
+                        deprecated_enabled->GetBool()
+                            ? IncognitoModePrefs::ENABLED
+                            : IncognitoModePrefs::DISABLED);
     } else {
       NOTREACHED();
     }
diff --git a/chrome/browser/resources/device_log_ui/device_log_ui.html b/chrome/browser/resources/device_log_ui/device_log_ui.html
index 0970967..0c7c912 100644
--- a/chrome/browser/resources/device_log_ui/device_log_ui.html
+++ b/chrome/browser/resources/device_log_ui/device_log_ui.html
@@ -5,11 +5,7 @@
   <title id="device-log-title">$i18n{titleText}</title>
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <link rel="stylesheet" href="device_log_ui.css">
-  <script src="chrome://resources/js/load_time_data.js"></script>
-  <script src="chrome://resources/js/assert.js"></script>
-  <script src="chrome://resources/js/util.js"></script>
-  <script src="strings.js"></script>
-  <script src="device_log_ui.js"></script>
+  <script type="module" src="device_log_ui.js"></script>
 </head>
 <body>
   <div id="header">
diff --git a/chrome/browser/resources/device_log_ui/device_log_ui.js b/chrome/browser/resources/device_log_ui/device_log_ui.js
index 6132c4f2..730cb20 100644
--- a/chrome/browser/resources/device_log_ui/device_log_ui.js
+++ b/chrome/browser/resources/device_log_ui/device_log_ui.js
@@ -2,179 +2,179 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-const DeviceLogUI = (function() {
-  'use strict';
+import './strings.m.js';
 
-  // List of log levels in priority order.
-  const logLevels = ['Debug', 'Event', 'User', 'Error'];
+import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {$} from 'chrome://resources/js/util.m.js';
 
-  /**
-   * Creates a tag for the log level.
-   *
-   * @param {string} level A string that represents log level.
-   * @return {HTMLSpanElement} The created span element.
-   */
-  const createLevelTag = function(level) {
-    const levelClassName = 'log-level-' + level.toLowerCase();
-    const tag = document.createElement('span');
-    tag.textContent = level;
-    tag.className = 'level-tag ' + levelClassName;
-    return tag;
-  };
+// List of log levels in priority order.
+const logLevels = ['Debug', 'Event', 'User', 'Error'];
 
-  /**
-   * Creates a tag for the log type.
-   *
-   * @param {string} level A string that represents log type.
-   * @return {HTMLSpanElement} The created span element.
-   */
-  const createTypeTag = function(type) {
-    const typeClassName = 'log-type-' + type.toLowerCase();
-    const tag = document.createElement('span');
-    tag.textContent = type;
-    tag.className = 'type-tag ' + typeClassName;
-    return tag;
-  };
+/**
+ * Creates a tag for the log level.
+ *
+ * @param {string} level A string that represents log level.
+ * @return {HTMLSpanElement} The created span element.
+ */
+const createLevelTag = function(level) {
+  const levelClassName = 'log-level-' + level.toLowerCase();
+  const tag = document.createElement('span');
+  tag.textContent = level;
+  tag.className = 'level-tag ' + levelClassName;
+  return tag;
+};
 
-  /**
-   * Creates an element that contains the time, the event, the level and
-   * the description of the given log entry.
-   *
-   * @param {Object} logEntry An object that represents a single line of log.
-   * @return {?HTMLParagraphElement} The created p element that represents
-   *     the log entry, or null if the entry should be skipped.
-   */
-  const createLogEntryText = function(logEntry) {
-    const level = logEntry['level'];
-    const levelIndex = logLevels.indexOf(level);
-    const levelSelectIndex = logLevels.indexOf($('log-level-select').value);
-    if (levelIndex < levelSelectIndex) {
-      return null;
+/**
+ * Creates a tag for the log type.
+ *
+ * @param {string} level A string that represents log type.
+ * @return {HTMLSpanElement} The created span element.
+ */
+const createTypeTag = function(type) {
+  const typeClassName = 'log-type-' + type.toLowerCase();
+  const tag = document.createElement('span');
+  tag.textContent = type;
+  tag.className = 'type-tag ' + typeClassName;
+  return tag;
+};
+
+/**
+ * Creates an element that contains the time, the event, the level and
+ * the description of the given log entry.
+ *
+ * @param {Object} logEntry An object that represents a single line of log.
+ * @return {?HTMLParagraphElement} The created p element that represents
+ *     the log entry, or null if the entry should be skipped.
+ */
+const createLogEntryText = function(logEntry) {
+  const level = logEntry['level'];
+  const levelIndex = logLevels.indexOf(level);
+  const levelSelectIndex = logLevels.indexOf($('log-level-select').value);
+  if (levelIndex < levelSelectIndex) {
+    return null;
+  }
+
+  const type = logEntry['type'];
+  const typeCheckbox = 'log-type-' + type.toLowerCase();
+  if ($(typeCheckbox) && !$(typeCheckbox).checked) {
+    return null;
+  }
+
+  const res = document.createElement('p');
+  const textWrapper = document.createElement('span');
+  let fileinfo = '';
+  if ($('log-fileinfo').checked) {
+    fileinfo = logEntry['file'];
+  }
+  let timestamp = '';
+  if ($('log-timedetail').checked) {
+    timestamp = logEntry['timestamp'];
+  } else {
+    timestamp = logEntry['timestampshort'];
+  }
+  textWrapper.textContent = loadTimeData.getStringF(
+      'logEntryFormat', timestamp, fileinfo, logEntry['event']);
+  res.appendChild(createTypeTag(type));
+  res.appendChild(createLevelTag(level));
+  res.appendChild(textWrapper);
+  return res;
+};
+
+/**
+ * Creates event log entries.
+ *
+ * @param {Array<string>} logEntries An array of strings that represent log
+ *     log events in JSON format.
+ */
+const createEventLog = function(logEntries) {
+  const container = $('log-container');
+  container.textContent = '';
+  for (let i = 0; i < logEntries.length; ++i) {
+    const entry = createLogEntryText(JSON.parse(logEntries[i]));
+    if (entry) {
+      container.appendChild(entry);
     }
+  }
+};
 
-    const type = logEntry['type'];
-    const typeCheckbox = 'log-type-' + type.toLowerCase();
-    if ($(typeCheckbox) && !$(typeCheckbox).checked) {
-      return null;
-    }
-
-    const res = document.createElement('p');
-    const textWrapper = document.createElement('span');
-    let fileinfo = '';
-    if ($('log-fileinfo').checked) {
-      fileinfo = logEntry['file'];
-    }
-    let timestamp = '';
-    if ($('log-timedetail').checked) {
-      timestamp = logEntry['timestamp'];
-    } else {
-      timestamp = logEntry['timestampshort'];
-    }
-    textWrapper.textContent = loadTimeData.getStringF(
-        'logEntryFormat', timestamp, fileinfo, logEntry['event']);
-    res.appendChild(createTypeTag(type));
-    res.appendChild(createLevelTag(level));
-    res.appendChild(textWrapper);
-    return res;
-  };
-
-  /**
-   * Creates event log entries.
-   *
-   * @param {Array<string>} logEntries An array of strings that represent log
-   *     log events in JSON format.
-   */
-  const createEventLog = function(logEntries) {
-    const container = $('log-container');
-    container.textContent = '';
-    for (let i = 0; i < logEntries.length; ++i) {
-      const entry = createLogEntryText(JSON.parse(logEntries[i]));
-      if (entry) {
-        container.appendChild(entry);
-      }
-    }
-  };
-
-  /**
-   * Callback function, triggered when the log is received.
-   *
-   * @param {Object} data A JSON structure of event log entries.
-   */
-  const getLogCallback = function(data) {
-    const container = $('log-container');
-    try {
-      createEventLog(JSON.parse(data));
-      if (container.textContent == '') {
-        container.textContent = loadTimeData.getString('logNoEntriesText');
-      }
-    } catch (e) {
+/**
+ * Callback function, triggered when the log is received.
+ *
+ * @param {Object} data A JSON structure of event log entries.
+ */
+const getLogCallback = function(data) {
+  const container = $('log-container');
+  try {
+    createEventLog(JSON.parse(data));
+    if (container.textContent == '') {
       container.textContent = loadTimeData.getString('logNoEntriesText');
     }
-  };
+  } catch (e) {
+    container.textContent = loadTimeData.getString('logNoEntriesText');
+  }
+};
 
-  /**
-   * Requests a log update.
-   */
-  const requestLog = function() {
-    chrome.send('DeviceLog.getLog');
-  };
+/**
+ * Requests a log update.
+ */
+const requestLog = function() {
+  sendWithPromise('getLog').then(data => getLogCallback(data));
+};
 
-  const clearLog = function() {
-    chrome.send('DeviceLog.clearLog');
-    requestLog();
-  };
+const clearLog = function() {
+  chrome.send('clearLog');
+  requestLog();
+};
 
-  const clearLogTypes = function() {
-    const checkboxes = document.querySelectorAll(
-        '#log-checkbox-container input[type="checkbox"]');
-    for (let i = 0; i < checkboxes.length; ++i) {
-      checkboxes[i].checked = false;
-    }
-  };
+const clearLogTypes = function() {
+  const checkboxes = document.querySelectorAll(
+      '#log-checkbox-container input[type="checkbox"]');
+  for (let i = 0; i < checkboxes.length; ++i) {
+    checkboxes[i].checked = false;
+  }
+};
 
-  /**
-   * Sets refresh rate if the interval is found in the url.
-   */
-  const setRefresh = function() {
-    const interval = new URL(window.location).searchParams.get('refresh');
-    if (interval) {
-      setInterval(requestLog, parseInt(interval, 10) * 1000);
-    }
-  };
+/**
+ * Sets refresh rate if the interval is found in the url.
+ */
+const setRefresh = function() {
+  const interval = new URL(window.location).searchParams.get('refresh');
+  if (interval) {
+    setInterval(requestLog, parseInt(interval, 10) * 1000);
+  }
+};
 
-  /**
-   * Gets log information from WebUI.
-   */
-  document.addEventListener('DOMContentLoaded', function() {
-    // Debug is the default level to show.
-    $('log-level-select').value = 'Debug';
-    $('log-level-select').onchange = requestLog;
+/**
+ * Gets log information from WebUI.
+ */
+document.addEventListener('DOMContentLoaded', function() {
+  // Debug is the default level to show.
+  $('log-level-select').value = 'Debug';
+  $('log-level-select').onchange = requestLog;
 
-    // Show all types by default.
-    let checkboxes = document.querySelectorAll(
-        '#log-checkbox-container input[type="checkbox"]');
-    for (let i = 0; i < checkboxes.length; ++i) {
-      checkboxes[i].checked = true;
-    }
+  // Show all types by default.
+  let checkboxes = document.querySelectorAll(
+      '#log-checkbox-container input[type="checkbox"]');
+  for (let i = 0; i < checkboxes.length; ++i) {
+    checkboxes[i].checked = true;
+  }
 
-    $('log-fileinfo').checked = false;
-    $('log-fileinfo').onclick = requestLog;
-    $('log-timedetail').checked = false;
-    $('log-timedetail').onclick = requestLog;
+  $('log-fileinfo').checked = false;
+  $('log-fileinfo').onclick = requestLog;
+  $('log-timedetail').checked = false;
+  $('log-timedetail').onclick = requestLog;
 
-    $('log-refresh').onclick = requestLog;
-    $('log-clear').onclick = clearLog;
-    $('log-clear-types').onclick = clearLogTypes;
+  $('log-refresh').onclick = requestLog;
+  $('log-clear').onclick = clearLog;
+  $('log-clear-types').onclick = clearLogTypes;
 
-    checkboxes = document.querySelectorAll(
-        '#log-checkbox-container input[type="checkbox"]');
-    for (let i = 0; i < checkboxes.length; ++i) {
-      checkboxes[i].onclick = requestLog;
-    }
+  checkboxes = document.querySelectorAll(
+      '#log-checkbox-container input[type="checkbox"]');
+  for (let i = 0; i < checkboxes.length; ++i) {
+    checkboxes[i].onclick = requestLog;
+  }
 
-    setRefresh();
-    requestLog();
-  });
-
-  return {getLogCallback: getLogCallback};
-})();
+  setRefresh();
+  requestLog();
+});
diff --git a/chrome/browser/resources/memories/app.js b/chrome/browser/resources/memories/app.js
index a741586..b00e9a43 100644
--- a/chrome/browser/resources/memories/app.js
+++ b/chrome/browser/resources/memories/app.js
@@ -120,14 +120,11 @@
     if (searchField.getValue() !== this.query_) {
       searchField.setValue(this.query_);
     }
-    // <if expr="not is_official_build">
     this.onBrowserIdle_().then(() => {
-      this.pageHandler_.getSampleMemories(this.query_.trim())
-          .then(({result}) => {
-            this.result_ = result;
-          });
+      this.pageHandler_.queryMemories(this.query_.trim()).then(({result}) => {
+        this.result_ = result;
+      });
     });
-    // </if>
   }
 }
 
diff --git a/chrome/browser/resources/nearby_internals/BUILD.gn b/chrome/browser/resources/nearby_internals/BUILD.gn
index c6c552f..a1569cc 100644
--- a/chrome/browser/resources/nearby_internals/BUILD.gn
+++ b/chrome/browser/resources/nearby_internals/BUILD.gn
@@ -37,6 +37,7 @@
     "nearby_contact_browser_proxy.js",
     "nearby_http_browser_proxy.js",
     "nearby_logs_browser_proxy.js",
+    "nearby_prefs_browser_proxy.js",
     "nearby_ui_trigger_browser_proxy.js",
     "types.js",
   ]
@@ -91,6 +92,7 @@
     ":nearby_http_browser_proxy",
     ":nearby_internals",
     ":nearby_logs_browser_proxy",
+    ":nearby_prefs_browser_proxy",
     ":nearby_ui_trigger_browser_proxy",
     ":types",
     ":ui_trigger_list_object",
@@ -109,6 +111,7 @@
     ":nearby_contact_browser_proxy",
     ":nearby_http_browser_proxy",
     ":nearby_logs_browser_proxy",
+    ":nearby_prefs_browser_proxy",
     ":nearby_ui_trigger_browser_proxy",
     ":types",
     ":ui_trigger_list_object",
@@ -122,6 +125,7 @@
   deps = [
     ":log_object",
     ":nearby_logs_browser_proxy",
+    ":nearby_prefs_browser_proxy",
     ":types",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/webui/resources/js:cr.m",
@@ -144,6 +148,13 @@
   ]
 }
 
+js_library("nearby_prefs_browser_proxy") {
+  deps = [
+    ":types",
+    "//ui/webui/resources/js:cr.m",
+  ]
+}
+
 js_library("nearby_http_browser_proxy") {
   deps = [
     ":types",
diff --git a/chrome/browser/resources/nearby_internals/logging_tab.html b/chrome/browser/resources/nearby_internals/logging_tab.html
index 4b9873f5..b31d6d0d 100644
--- a/chrome/browser/resources/nearby_internals/logging_tab.html
+++ b/chrome/browser/resources/nearby_internals/logging_tab.html
@@ -28,6 +28,10 @@
     on-click="onClearLogsButtonClicked_">
   Clear Logs
 </cr-button>
+<cr-button class="internals-button"
+    on-click="onClearPrefsButtonClicked_">
+  Reset Nearby
+</cr-button>
 <iron-list items="[[logList_]]" as="log" id="logs-list">
   <template>
     <log-object log-message="[[log]]">
diff --git a/chrome/browser/resources/nearby_internals/logging_tab.js b/chrome/browser/resources/nearby_internals/logging_tab.js
index c8b6b8dd..9a7f6bc8 100644
--- a/chrome/browser/resources/nearby_internals/logging_tab.js
+++ b/chrome/browser/resources/nearby_internals/logging_tab.js
@@ -11,6 +11,7 @@
 import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {NearbyLogsBrowserProxy} from './nearby_logs_browser_proxy.js';
+import {NearbyPrefsBrowserProxy} from './nearby_prefs_browser_proxy.js';
 import {LogMessage, Severity} from './types.js';
 
 /**
@@ -65,12 +66,16 @@
   /** @private {?NearbyLogsBrowserProxy}*/
   browserProxy_: null,
 
+  /** @private {?NearbyPrefsBrowserProxy}*/
+  prefsBrowserProxy_: null,
+
   /**
    * Initialize |browserProxy_| and |logList_|.
    * @override
    */
   created() {
     this.browserProxy_ = NearbyLogsBrowserProxy.getInstance();
+    this.prefsBrowserProxy_ = NearbyPrefsBrowserProxy.getInstance();
   },
 
   /**
@@ -96,6 +101,14 @@
   },
 
   /**
+   * Clears Nearby Share Prefs.
+   * @private
+   */
+  onClearPrefsButtonClicked_() {
+    this.prefsBrowserProxy_.clearNearbyPrefs();
+  },
+
+  /**
    * Saves and downloads javascript logs that appear on the page.
    * @private
    */
diff --git a/chrome/browser/resources/nearby_internals/nearby_prefs_browser_proxy.js b/chrome/browser/resources/nearby_internals/nearby_prefs_browser_proxy.js
new file mode 100644
index 0000000..e5d2539
--- /dev/null
+++ b/chrome/browser/resources/nearby_internals/nearby_prefs_browser_proxy.js
@@ -0,0 +1,20 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
+
+/**
+ * JavaScript hooks into the native WebUI handler to communicate with C++ about
+ * Nearby prefs.
+ */
+export class NearbyPrefsBrowserProxy {
+  /**
+   * Tells C++ side to clear Nearby Prefs.
+   */
+  clearNearbyPrefs() {
+    chrome.send('clearNearbyPrefs');
+  }
+}
+
+addSingletonGetter(NearbyPrefsBrowserProxy);
diff --git a/chrome/browser/resources/new_tab_page/BUILD.gn b/chrome/browser/resources/new_tab_page/BUILD.gn
index 0a8cf5a..c3e5f4ad 100644
--- a/chrome/browser/resources/new_tab_page/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/BUILD.gn
@@ -31,8 +31,8 @@
     ":voice_search_overlay",
     ":window_proxy",
     "modules:module_descriptor",
+    "modules:module_descriptors",
     "modules:module_registry",
-    "modules:modules",
     "modules/dummy:foo_proxy",
     "realbox:realbox",
     "realbox:realbox_browser_proxy",
@@ -82,8 +82,8 @@
     ":one_google_bar_api",
     ":promo_browser_command_proxy",
     ":window_proxy",
+    "modules:module_registry",
     "modules:module_wrapper",
-    "modules:modules",
     "realbox:realbox",
     "//skia/public/mojom:mojom_webui_js",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
diff --git a/chrome/browser/resources/new_tab_page/app.js b/chrome/browser/resources/new_tab_page/app.js
index 81bc331..086bdab9 100644
--- a/chrome/browser/resources/new_tab_page/app.js
+++ b/chrome/browser/resources/new_tab_page/app.js
@@ -7,7 +7,6 @@
 import './realbox/realbox.js';
 import './logo.js';
 import './modules/module_wrapper.js';
-import './modules/modules.js'; // Registers module descriptors.
 import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
 import 'chrome://resources/cr_elements/cr_toast/cr_toast.m.js';
 import 'chrome://resources/cr_elements/shared_style_css.m.js';
diff --git a/chrome/browser/resources/new_tab_page/modules/BUILD.gn b/chrome/browser/resources/new_tab_page/modules/BUILD.gn
index 21f3f8ea..27aefad6 100644
--- a/chrome/browser/resources/new_tab_page/modules/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/modules/BUILD.gn
@@ -16,12 +16,13 @@
   ]
 }
 
-js_library("modules") {
+js_library("module_descriptors") {
   deps = [
-    ":module_registry",
+    ":module_descriptor",
     "cart:module",
     "drive:module",
     "task_module:module",
+    "//ui/webui/resources/js:load_time_data.m",
   ]
   if (!is_official_build) {
     deps += [ "dummy:module" ]
@@ -48,6 +49,7 @@
 js_library("module_registry") {
   deps = [
     ":module_descriptor",
+    ":module_descriptors",
     "..:new_tab_page_proxy",
   ]
 }
@@ -97,7 +99,7 @@
   out_manifest = "$target_gen_dir/$preprocess_manifest"
   in_files = [
     "module_descriptor.js",
-    "modules.js",
+    "module_descriptors.js",
     "module_registry.js",
     "task_module/task_module_handler_proxy.js",
     "cart/chrome_cart_proxy.js",
diff --git a/chrome/browser/resources/new_tab_page/modules/modules.js b/chrome/browser/resources/new_tab_page/modules/module_descriptors.js
similarity index 89%
rename from chrome/browser/resources/new_tab_page/modules/modules.js
rename to chrome/browser/resources/new_tab_page/modules/module_descriptors.js
index b9bd0a6c..46702fb3 100644
--- a/chrome/browser/resources/new_tab_page/modules/modules.js
+++ b/chrome/browser/resources/new_tab_page/modules/module_descriptors.js
@@ -14,11 +14,10 @@
 import {dummyDescriptor, dummyDescriptor2} from './dummy/module.js';
 // </if>
 import {ModuleDescriptor} from './module_descriptor.js';
-import {ModuleRegistry} from './module_registry.js';
 import {recipeTasksDescriptor, shoppingTasksDescriptor} from './task_module/module.js';
 
 /** @type {!Array<!ModuleDescriptor>} */
-const descriptors = [];
+export const descriptors = [];
 
 if (loadTimeData.getBoolean('shoppingTasksModuleEnabled')) {
   descriptors.push(shoppingTasksDescriptor);
@@ -40,5 +39,3 @@
 descriptors.push(dummyDescriptor);
 descriptors.push(dummyDescriptor2);
 // </if>
-
-ModuleRegistry.getInstance().registerModules(descriptors);
diff --git a/chrome/browser/resources/new_tab_page/modules/module_registry.js b/chrome/browser/resources/new_tab_page/modules/module_registry.js
index bc4b9dc0..06a7585 100644
--- a/chrome/browser/resources/new_tab_page/modules/module_registry.js
+++ b/chrome/browser/resources/new_tab_page/modules/module_registry.js
@@ -4,6 +4,7 @@
 
 import {NewTabPageProxy} from '../new_tab_page_proxy.js';
 import {ModuleDescriptor} from './module_descriptor.js';
+import {descriptors} from './module_descriptors.js';
 
 /**
  * @fileoverview The module registry holds the descriptors of NTP modules and
@@ -16,7 +17,7 @@
 export class ModuleRegistry {
   /** @return {!ModuleRegistry} */
   static getInstance() {
-    return instance || (instance = new ModuleRegistry());
+    return instance || (instance = new ModuleRegistry(descriptors));
   }
 
   /** @param {ModuleRegistry} newInstance */
@@ -24,9 +25,13 @@
     instance = newInstance;
   }
 
-  constructor() {
+  /**
+   * Creates a registry populated with a list of descriptors
+   * @param {!Array<!ModuleDescriptor>} descriptors
+   */
+  constructor(descriptors) {
     /** @private {!Array<!ModuleDescriptor>} */
-    this.descriptors_ = [];
+    this.descriptors_ = descriptors;
   }
 
   /** @return {!Array<!ModuleDescriptor>} */
@@ -35,15 +40,6 @@
   }
 
   /**
-   * Registers modules via their descriptors.
-   * @param {!Array<!ModuleDescriptor>} descriptors
-   */
-  registerModules(descriptors) {
-    /** @type {!Array<!ModuleDescriptor>} */
-    this.descriptors_ = descriptors;
-  }
-
-  /**
    * Initializes enabled modules previously set via |registerModules| and
    * returns the initialized descriptors.
    * @param {number} timeout Timeout in milliseconds after which initialization
diff --git a/chrome/browser/resources/webid/default_100_percent/global_id_risk.png b/chrome/browser/resources/webid/default_100_percent/global_id_risk.png
index 5b2307af..462e759 100644
--- a/chrome/browser/resources/webid/default_100_percent/global_id_risk.png
+++ b/chrome/browser/resources/webid/default_100_percent/global_id_risk.png
Binary files differ
diff --git a/chrome/browser/resources/webid/default_100_percent/sign_in.png b/chrome/browser/resources/webid/default_100_percent/sign_in.png
index 2f33aa356..bdc311c 100644
--- a/chrome/browser/resources/webid/default_100_percent/sign_in.png
+++ b/chrome/browser/resources/webid/default_100_percent/sign_in.png
Binary files differ
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc
index b46abd7f..de24a4b 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc
@@ -83,6 +83,8 @@
       return "FILE_ENCRYPTED";
     case BinaryUploadService::Result::DLP_SCAN_UNSUPPORTED_FILE_TYPE:
       return "DLP_SCAN_UNSUPPORTED_FILE_TYPE";
+    case BinaryUploadService::Result::TOO_MANY_REQUESTS:
+      return "TOO_MANY_REQUESTS";
   }
 }
 
@@ -364,10 +366,17 @@
 
 void BinaryUploadService::OnUploadComplete(Request* request,
                                            bool success,
+                                           int http_status,
                                            const std::string& response_data) {
   if (!IsActive(request))
     return;
 
+  if (http_status == net::HTTP_TOO_MANY_REQUESTS) {
+    FinishRequest(request, Result::TOO_MANY_REQUESTS,
+                  enterprise_connectors::ContentAnalysisResponse());
+    return;
+  }
+
   if (!success) {
     FinishRequest(request, Result::UPLOAD_FAILURE,
                   enterprise_connectors::ContentAnalysisResponse());
@@ -601,6 +610,11 @@
   content_analysis_request_.mutable_request_data()->set_email(email);
 }
 
+void BinaryUploadService::Request::set_client_metadata(
+    enterprise_connectors::ClientMetadata metadata) {
+  *content_analysis_request_.mutable_client_metadata() = std::move(metadata);
+}
+
 enterprise_connectors::AnalysisConnector
 BinaryUploadService::Request::analysis_connector() {
   return content_analysis_request_.analysis_connector();
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h
index ac4de13..3ec8b0b2 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h
@@ -81,7 +81,11 @@
     // The file's type is not supported and the file was not uploaded.
     DLP_SCAN_UNSUPPORTED_FILE_TYPE = 8,
 
-    kMaxValue = DLP_SCAN_UNSUPPORTED_FILE_TYPE,
+    // The server returned a 429 HTTP status indicating too many requests are
+    // being sent.
+    TOO_MANY_REQUESTS = 9,
+
+    kMaxValue = TOO_MANY_REQUESTS,
   };
 
   // Callbacks used to pass along the results of scanning. The response protos
@@ -159,6 +163,7 @@
     void set_filename(const std::string& filename);
     void set_digest(const std::string& digest);
     void clear_dlp_scan_request();
+    void set_client_metadata(enterprise_connectors::ClientMetadata metadata);
 
     // Methods for accessing the ContentAnalysisRequest.
     enterprise_connectors::AnalysisConnector analysis_connector();
@@ -244,6 +249,7 @@
 
   void OnUploadComplete(Request* request,
                         bool success,
+                        int http_status,
                         const std::string& response_data);
 
   void OnGetResponse(Request* request,
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc
index 33d5c7b..85dea566 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc
@@ -63,7 +63,8 @@
   void Start() override {
     std::string serialized_response;
     response_.SerializeToString(&serialized_response);
-    std::move(callback_).Run(should_succeed_, serialized_response);
+    std::move(callback_).Run(should_succeed_, should_succeed_ ? 200 : 401,
+                             serialized_response);
   }
 
  private:
@@ -161,7 +162,7 @@
   void ReceiveResponseFromUpload(BinaryUploadService::Request* request,
                                  bool success,
                                  const std::string& response) {
-    service_->OnUploadComplete(request, success, response);
+    service_->OnUploadComplete(request, success, success ? 200 : 401, response);
   }
 
   void ServiceWithNoFCMConnection() {
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.cc b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.cc
index 76424db..e3a0c8b 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h"
 
+#include "base/containers/flat_map.h"
 #include "base/json/json_reader.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
@@ -48,8 +49,7 @@
     const std::string& expected_username) {
   event_key_ = SafeBrowsingPrivateEventRouter::kKeyUnscannedFileEvent;
   url_ = expected_url;
-  filename_ = expected_filename;
-  sha256_ = expected_sha256;
+  filenames_and_hashes_[expected_filename] = expected_sha256;
   mimetypes_ = expected_mimetypes;
   trigger_ = expected_trigger;
   unscanned_reason_ = expected_reason;
@@ -66,6 +66,37 @@
       });
 }
 
+void EventReportValidator::ExpectUnscannedFileEvents(
+    const std::string& expected_url,
+    const std::vector<const std::string>& expected_filenames,
+    const std::vector<const std::string>& expected_sha256s,
+    const std::string& expected_trigger,
+    const std::string& expected_reason,
+    const std::set<std::string>* expected_mimetypes,
+    int expected_content_size,
+    const std::string& expected_result,
+    const std::string& expected_username) {
+  DCHECK_EQ(expected_filenames.size(), expected_sha256s.size());
+  for (size_t i = 0; i < expected_filenames.size(); ++i)
+    filenames_and_hashes_[expected_filenames[i]] = expected_sha256s[i];
+
+  event_key_ = SafeBrowsingPrivateEventRouter::kKeyUnscannedFileEvent;
+  url_ = expected_url;
+  mimetypes_ = expected_mimetypes;
+  trigger_ = expected_trigger;
+  unscanned_reason_ = expected_reason;
+  content_size_ = expected_content_size;
+  result_ = expected_result;
+  username_ = expected_username;
+  EXPECT_CALL(*client_, UploadSecurityEventReport_(_, _, _, _))
+      .Times(expected_filenames.size())
+      .WillRepeatedly([this](content::BrowserContext* context,
+                             bool include_device_info, base::Value& report,
+                             base::OnceCallback<void(bool)>& callback) {
+        ValidateReport(&report);
+      });
+}
+
 void EventReportValidator::ExpectDangerousDeepScanningResult(
     const std::string& expected_url,
     const std::string& expected_filename,
@@ -78,8 +109,7 @@
     const std::string& expected_username) {
   event_key_ = SafeBrowsingPrivateEventRouter::kKeyDangerousDownloadEvent;
   url_ = expected_url;
-  filename_ = expected_filename;
-  sha256_ = expected_sha256;
+  filenames_and_hashes_[expected_filename] = expected_sha256;
   threat_type_ = expected_threat_type;
   mimetypes_ = expected_mimetypes;
   trigger_ = expected_trigger;
@@ -110,8 +140,7 @@
   event_key_ = SafeBrowsingPrivateEventRouter::kKeySensitiveDataEvent;
   url_ = expected_url;
   dlp_verdict_ = expected_dlp_verdict;
-  filename_ = expected_filename;
-  sha256_ = expected_sha256;
+  filenames_and_hashes_[expected_filename] = expected_sha256;
   mimetypes_ = expected_mimetypes;
   trigger_ = expected_trigger;
   content_size_ = expected_content_size;
@@ -142,8 +171,7 @@
         const std::string& expected_username) {
   event_key_ = SafeBrowsingPrivateEventRouter::kKeyDangerousDownloadEvent;
   url_ = expected_url;
-  filename_ = expected_filename;
-  sha256_ = expected_sha256;
+  filenames_and_hashes_[expected_filename] = expected_sha256;
   threat_type_ = expected_threat_type;
   trigger_ = expected_trigger;
   mimetypes_ = expected_mimetypes;
@@ -184,8 +212,7 @@
         const std::string& expected_username) {
   event_key_ = SafeBrowsingPrivateEventRouter::kKeySensitiveDataEvent;
   url_ = expected_url;
-  filename_ = expected_filename;
-  sha256_ = expected_sha256;
+  filenames_and_hashes_[expected_filename] = expected_sha256;
   trigger_ = expected_trigger;
   mimetypes_ = expected_mimetypes;
   content_size_ = expected_content_size;
@@ -223,8 +250,7 @@
     const std::string& expected_username) {
   event_key_ = SafeBrowsingPrivateEventRouter::kKeyDangerousDownloadEvent;
   url_ = expected_url;
-  filename_ = expected_filename;
-  sha256_ = expected_sha256;
+  filenames_and_hashes_[expected_filename] = expected_sha256;
   threat_type_ = expected_threat_type;
   mimetypes_ = expected_mimetypes;
   trigger_ = expected_trigger;
@@ -261,9 +287,7 @@
 
   // The event should match the expected values.
   ValidateField(event, SafeBrowsingPrivateEventRouter::kKeyUrl, url_);
-  ValidateField(event, SafeBrowsingPrivateEventRouter::kKeyFileName, filename_);
-  ValidateField(event, SafeBrowsingPrivateEventRouter::kKeyDownloadDigestSha256,
-                sha256_);
+  ValidateFilenameAndHash(event);
   ValidateField(event, SafeBrowsingPrivateEventRouter::kKeyTrigger, trigger_);
   ValidateField(event, SafeBrowsingPrivateEventRouter::kKeyContentSize,
                 content_size_);
@@ -316,6 +340,16 @@
                 expected_rule.rule_id());
 }
 
+void EventReportValidator::ValidateFilenameAndHash(base::Value* value) {
+  const std::string* filename =
+      value->FindStringKey(SafeBrowsingPrivateEventRouter::kKeyFileName);
+  ASSERT_TRUE(filename);
+  ASSERT_TRUE(filenames_and_hashes_.count(*filename))
+      << "Mismatch in field " << SafeBrowsingPrivateEventRouter::kKeyFileName;
+  ValidateField(value, SafeBrowsingPrivateEventRouter::kKeyDownloadDigestSha256,
+                filenames_and_hashes_[*filename]);
+}
+
 void EventReportValidator::ValidateField(
     base::Value* value,
     const std::string& field_key,
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h
index 5e1898e3..56bfd500c 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/containers/flat_map.h"
 #include "base/optional.h"
 #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
 #include "components/enterprise/common/proto/connectors.pb.h"
@@ -93,6 +94,17 @@
                                 const std::string& expected_result,
                                 const std::string& expected_username);
 
+  void ExpectUnscannedFileEvents(
+      const std::string& expected_url,
+      const std::vector<const std::string>& expected_filenames,
+      const std::vector<const std::string>& expected_sha256s,
+      const std::string& expected_trigger,
+      const std::string& expected_reason,
+      const std::set<std::string>* expected_mimetypes,
+      int expected_content_size,
+      const std::string& expected_result,
+      const std::string& expected_username);
+
   void ExpectDangerousDownloadEvent(
       const std::string& expected_url,
       const std::string& expected_filename,
@@ -116,6 +128,7 @@
   void ValidateDlpRule(base::Value* value,
                        const enterprise_connectors::ContentAnalysisResponse::
                            Result::TriggeredRule& expected_rule);
+  void ValidateFilenameAndHash(base::Value* value);
   void ValidateField(base::Value* value,
                      const std::string& field_key,
                      const base::Optional<std::string>& expected_value);
@@ -130,8 +143,6 @@
 
   std::string event_key_;
   std::string url_;
-  std::string filename_;
-  std::string sha256_;
   std::string trigger_;
   base::Optional<enterprise_connectors::ContentAnalysisResponse::Result>
       dlp_verdict_ = base::nullopt;
@@ -142,6 +153,11 @@
   base::Optional<std::string> result_ = base::nullopt;
   std::string username_;
 
+  // When multiple files generate events, we don't necessarily know in which
+  // order they will be reported. As such, we use a map to ensure all of them
+  // are called as expected.
+  base::flat_map<std::string, std::string> filenames_and_hashes_;
+
   base::RepeatingClosure done_closure_;
 };
 
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc
index 7e33556..104a5e5 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.cc
@@ -36,6 +36,8 @@
     case BinaryUploadService::Result::UNKNOWN:
     case BinaryUploadService::Result::UPLOAD_FAILURE:
     case BinaryUploadService::Result::FAILED_TO_GET_TOKEN:
+    // TODO(crbug.com/1191060): Update this string when the event is supported.
+    case BinaryUploadService::Result::TOO_MANY_REQUESTS:
       unscanned_reason = "SERVICE_UNAVAILABLE";
       break;
     case BinaryUploadService::Result::FILE_ENCRYPTED:
@@ -324,6 +326,8 @@
       return "FileEncrypted";
     case BinaryUploadService::Result::DLP_SCAN_UNSUPPORTED_FILE_TYPE:
       return "DlpScanUnsupportedFileType";
+    case BinaryUploadService::Result::TOO_MANY_REQUESTS:
+      return "TooManyRequests";
   }
 }
 
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.cc b/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.cc
index a0f4ac7..04bfd04 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.cc
@@ -133,13 +133,15 @@
     base::UmaHistogramMediumTimes(
         "SBMultipartUploader.SuccessfulUploadDuration",
         base::Time::Now() - start_time_);
-    std::move(callback_).Run(/*success=*/true, *response_body.get());
+    std::move(callback_).Run(/*success=*/true, response_code,
+                             *response_body.get());
   } else {
     if (response_code < 500 || retry_count_ >= kMaxRetryAttempts) {
       RecordUploadSuccessHistogram(/*success=*/false);
       base::UmaHistogramMediumTimes("SBMultipartUploader.FailedUploadDuration",
                                     base::Time::Now() - start_time_);
-      std::move(callback_).Run(/*success=*/false, *response_body.get());
+      std::move(callback_).Run(/*success=*/false, response_code,
+                               *response_body.get());
     } else {
       content::GetUIThreadTaskRunner({})->PostDelayedTask(
           FROM_HERE,
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.h b/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.h
index b6b9690..d8e3a8c 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.h
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/multipart_uploader.h
@@ -29,8 +29,8 @@
 // multipart protocol. This class is neither movable nor copyable.
 class MultipartUploadRequest {
  public:
-  using Callback =
-      base::OnceCallback<void(bool success, const std::string& response_data)>;
+  using Callback = base::OnceCallback<
+      void(bool success, int http_status, const std::string& response_data)>;
 
   // Creates a MultipartUploadRequest, which will upload |data| to the given
   // |base_url| with |metadata| attached.
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc
index 91a46df..76c366cfd 100644
--- a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc
+++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc
@@ -236,6 +236,8 @@
   if (trigger_ == DeepScanTrigger::TRIGGER_POLICY) {
     request->set_device_token(analysis_settings_.dm_token);
     request->set_per_profile_request(analysis_settings_.per_profile);
+    if (analysis_settings_.client_metadata)
+      request->set_client_metadata(*analysis_settings_.client_metadata);
   }
 
   request->set_analysis_connector(enterprise_connectors::FILE_DOWNLOADED);
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc b/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc
index 0c73448..e87a8525 100644
--- a/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc
@@ -43,6 +43,10 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chromeos/system/fake_statistics_provider.h"
+#endif
+
 namespace safe_browsing {
 
 using ::testing::Return;
@@ -441,6 +445,11 @@
 
     SetOnSecurityEventReporting(profile_->GetPrefs(), true);
     EnableAllFeatures();
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+    fake_statistics_provider_.SetMachineStatistic(
+        chromeos::system::kSerialNumberKeyForTest, "fake_serial_number");
+#endif
   }
 
   void TearDown() override {
@@ -452,6 +461,9 @@
  protected:
   std::unique_ptr<policy::MockCloudPolicyClient> client_;
   signin::IdentityTestEnvironment identity_test_environment_;
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  chromeos::system::ScopedFakeStatisticsProvider fake_statistics_provider_;
+#endif
 };
 
 TEST_F(DeepScanningReportingTest, ProcessesResponseCorrectly) {
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMediator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMediator.java
index 70fec05..cd8ad92c 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMediator.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMediator.java
@@ -91,11 +91,15 @@
         ImageView imageView = mDialogView.findViewById(R.id.screenshot_image);
         imageView.setImageBitmap(mInitialBitmap);
 
+        LongScreenshotsMetrics.logLongScreenshotsEvent(
+                LongScreenshotsMetrics.LongScreenshotsEvent.DIALOG_OPEN);
         mDialog.show();
     }
 
     public void areaSelectionDone(View view) {
         // TODO(1163193): Delete all bitmaps.
+        LongScreenshotsMetrics.logLongScreenshotsEvent(
+                LongScreenshotsMetrics.LongScreenshotsEvent.DIALOG_OK);
         mDialog.cancel();
         mDone = true;
         if (mDoneCallback != null) {
@@ -106,6 +110,8 @@
 
     public void areaSelectionClose(View view) {
         // TODO(1163193): Delete all bitmaps.
+        LongScreenshotsMetrics.logLongScreenshotsEvent(
+                LongScreenshotsMetrics.LongScreenshotsEvent.DIALOG_CANCEL);
         mDialog.cancel();
     }
 
@@ -255,6 +261,8 @@
     @Override
     public Bitmap getScreenshot() {
         // TODO(skare): Populate with actual selected region.
+        // TODO(skare): At that time, log the height in a new histogram such as
+        //     Sharing.LongScreenshots.ScreenshotHeight.
         return mInitialBitmap;
     }
 }
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMetrics.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMetrics.java
new file mode 100644
index 0000000..ecbe2d9
--- /dev/null
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMetrics.java
@@ -0,0 +1,91 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.share.long_screenshots;
+
+import androidx.annotation.IntDef;
+
+import org.chromium.base.metrics.RecordHistogram;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A helper class to log long screenshots metrics.
+ */
+public class LongScreenshotsMetrics {
+    // These values are persisted to logs. Entries should not be renumbered and
+    // numeric values should never be reused.
+    @IntDef({
+            LongScreenshotsEvent.DIALOG_OPEN,
+            LongScreenshotsEvent.DIALOG_CANCEL,
+            LongScreenshotsEvent.DIALOG_OK,
+            LongScreenshotsEvent.GENERATOR_CAPTURE_GENERATION_ERROR,
+            LongScreenshotsEvent.GENERATOR_CAPTURE_INSUFFICIENT_MEMORY,
+            LongScreenshotsEvent.GENERATOR_COMPOSITOR_CAPTURE_COMPLETE,
+            LongScreenshotsEvent.GENERATOR_COMPOSITOR_MEMORY_PRESSURE,
+            LongScreenshotsEvent.GENERATOR_COMPOSITOR_GENERATION_ERROR,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LongScreenshotsEvent {
+        int DIALOG_OPEN = 0;
+        int DIALOG_CANCEL = 1;
+        int DIALOG_OK = 2;
+        int GENERATOR_CAPTURE_GENERATION_ERROR = 3;
+        int GENERATOR_CAPTURE_INSUFFICIENT_MEMORY = 4;
+        int GENERATOR_COMPOSITOR_CAPTURE_COMPLETE = 5;
+        int GENERATOR_COMPOSITOR_MEMORY_PRESSURE = 6;
+        int GENERATOR_COMPOSITOR_GENERATION_ERROR = 7;
+        int COUNT = 8;
+    };
+
+    // These values are persisted to logs. Entries should not be renumbered and
+    // numeric values should never be reused.
+    // These should correspond to the Status enum in
+    // chrome/browser/long_screenshots/long_screenshots_tab_service.h
+    @IntDef({
+            BitmapGenerationStatus.UNKNOWN,
+            BitmapGenerationStatus.OK,
+            BitmapGenerationStatus.DIRECTORY_CREATION_FAILED,
+            BitmapGenerationStatus.CAPTURE_FAILED,
+            BitmapGenerationStatus.PROTO_SERIALIZATION_FAILED,
+            BitmapGenerationStatus.WEB_CONTENTS_GONE,
+            BitmapGenerationStatus.NATIVE_SERVICE_UNINITIALIZED,
+            BitmapGenerationStatus.LOW_MEMORY_DETECTED,
+            BitmapGenerationStatus.PROTO_DESERIALIZATION_FAILED,
+            BitmapGenerationStatus.NATIVE_SERVICE_NOT_INITIALIZED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface BitmapGenerationStatus {
+        int UNKNOWN = 0;
+        int OK = 1;
+        int DIRECTORY_CREATION_FAILED = 2;
+        int CAPTURE_FAILED = 3;
+        int PROTO_SERIALIZATION_FAILED = 4;
+        int WEB_CONTENTS_GONE = 5;
+        int NATIVE_SERVICE_UNINITIALIZED = 6;
+        int LOW_MEMORY_DETECTED = 7;
+        int PROTO_DESERIALIZATION_FAILED = 8;
+        int NATIVE_SERVICE_NOT_INITIALIZED = 9;
+        int COUNT = 10;
+    };
+
+    /**
+     * A helper function to log long screenshots UI events.
+     * @param action the action to be logged.
+     */
+    public static void logLongScreenshotsEvent(@LongScreenshotsEvent int action) {
+        RecordHistogram.recordEnumeratedHistogram(
+                "Sharing.LongScreenshots.Event", action, LongScreenshotsEvent.COUNT);
+    }
+
+    /**
+     * A helper function to log long screenshots bitmap generation statuses.
+     * @param status the bitmap generation status to be logged.
+     */
+    public static void logBitmapGenerationStatus(@BitmapGenerationStatus int status) {
+        RecordHistogram.recordEnumeratedHistogram("Sharing.LongScreenshots.BitmapGenerationStatus",
+                status, BitmapGenerationStatus.COUNT);
+    }
+}
\ No newline at end of file
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/BitmapGenerator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/BitmapGenerator.java
index 2cc5a09..680c295 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/BitmapGenerator.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/BitmapGenerator.java
@@ -10,6 +10,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Callback;
+import org.chromium.chrome.browser.share.long_screenshots.LongScreenshotsMetrics;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.components.paint_preview.common.proto.PaintPreview.PaintPreviewProto;
 import org.chromium.components.paintpreview.player.CompositorStatus;
@@ -132,7 +133,7 @@
     }
 
     private void onCaptureResult(@Status int status) {
-        // TODO(tgupta): Add metrics logging here.
+        LongScreenshotsMetrics.logBitmapGenerationStatus(status);
         mGeneratorCallBack.onCaptureResult(status);
     }
 }
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/EntryManager.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/EntryManager.java
index 85cc162..2f95700 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/EntryManager.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/EntryManager.java
@@ -9,6 +9,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.chrome.browser.share.long_screenshots.LongScreenshotsMetrics;
 import org.chromium.chrome.browser.share.long_screenshots.bitmap_generation.LongScreenshotsEntry.EntryStatus;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.components.paintpreview.player.CompositorStatus;
@@ -195,24 +196,37 @@
         return new BitmapGenerator.GeneratorCallBack() {
             @Override
             public void onCompositorResult(@CompositorStatus int status) {
-                // TODO(tgupta): Add metrics logging here.
                 if (status == CompositorStatus.STOPPED_DUE_TO_MEMORY_PRESSURE
                         || status == CompositorStatus.SKIPPED_DUE_TO_MEMORY_PRESSURE) {
                     updateGeneratorStatus(EntryStatus.INSUFFICIENT_MEMORY);
+                    LongScreenshotsMetrics.logLongScreenshotsEvent(
+                            LongScreenshotsMetrics.LongScreenshotsEvent
+                                    .GENERATOR_COMPOSITOR_MEMORY_PRESSURE);
                 } else if (status == CompositorStatus.OK) {
                     updateGeneratorStatus(EntryStatus.CAPTURE_COMPLETE);
+                    LongScreenshotsMetrics.logLongScreenshotsEvent(
+                            LongScreenshotsMetrics.LongScreenshotsEvent
+                                    .GENERATOR_COMPOSITOR_CAPTURE_COMPLETE);
                 } else {
                     updateGeneratorStatus(EntryStatus.GENERATION_ERROR);
+                    LongScreenshotsMetrics.logLongScreenshotsEvent(
+                            LongScreenshotsMetrics.LongScreenshotsEvent
+                                    .GENERATOR_COMPOSITOR_GENERATION_ERROR);
                 }
             }
 
             @Override
             public void onCaptureResult(@Status int status) {
-                // TODO(tgupta): Add metrics logging here.
                 if (status == Status.LOW_MEMORY_DETECTED) {
                     updateGeneratorStatus(EntryStatus.INSUFFICIENT_MEMORY);
+                    LongScreenshotsMetrics.logLongScreenshotsEvent(
+                            LongScreenshotsMetrics.LongScreenshotsEvent
+                                    .GENERATOR_CAPTURE_INSUFFICIENT_MEMORY);
                 } else if (status != Status.OK) {
                     updateGeneratorStatus(EntryStatus.GENERATION_ERROR);
+                    LongScreenshotsMetrics.logLongScreenshotsEvent(
+                            LongScreenshotsMetrics.LongScreenshotsEvent
+                                    .GENERATOR_CAPTURE_GENERATION_ERROR);
                 }
             }
         };
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsEntry.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsEntry.java
index 519552c9..6536a24 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsEntry.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsEntry.java
@@ -138,7 +138,6 @@
     }
 
     private void onBitmapGenerated(Bitmap bitmap) {
-        // TODO(tgupta): Add metrics logging here.
         mGeneratedBitmap = bitmap;
 
         if (mMemoryTracker != null && mGeneratedBitmap != null) {
diff --git a/chrome/browser/share/android/java_sources.gni b/chrome/browser/share/android/java_sources.gni
index 39a67b2..7b04835 100644
--- a/chrome/browser/share/android/java_sources.gni
+++ b/chrome/browser/share/android/java_sources.gni
@@ -13,6 +13,7 @@
   "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsAreaSelectionDialogViewBinder.java",
   "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsCoordinator.java",
   "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMediator.java",
+  "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMetrics.java",
   "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/BitmapGenerator.java",
   "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/EntryManager.java",
   "//chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsCompositor.java",
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 65ee6b4..06c4669 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1380,6 +1380,8 @@
       "webui/extensions/extensions_ui.h",
       "webui/favicon_source.cc",
       "webui/favicon_source.h",
+      "webui/feedback/child_web_dialog.cc",
+      "webui/feedback/child_web_dialog.h",
       "webui/feedback/feedback_dialog.cc",
       "webui/feedback/feedback_dialog.h",
       "webui/feedback/feedback_handler.cc",
@@ -2503,6 +2505,8 @@
       "webui/nearby_internals/nearby_internals_http_handler.h",
       "webui/nearby_internals/nearby_internals_logs_handler.cc",
       "webui/nearby_internals/nearby_internals_logs_handler.h",
+      "webui/nearby_internals/nearby_internals_prefs_handler.cc",
+      "webui/nearby_internals/nearby_internals_prefs_handler.h",
       "webui/nearby_internals/nearby_internals_ui.cc",
       "webui/nearby_internals/nearby_internals_ui.h",
       "webui/nearby_internals/nearby_internals_ui_trigger_handler.cc",
diff --git a/chrome/browser/ui/cocoa/applescript/apple_event_util.mm b/chrome/browser/ui/cocoa/applescript/apple_event_util.mm
index 2a155b2c..b995f41 100644
--- a/chrome/browser/ui/cocoa/applescript/apple_event_util.mm
+++ b/chrome/browser/ui/cocoa/applescript/apple_event_util.mm
@@ -96,16 +96,6 @@
       }
       break;
     }
-
-    // TODO(crbug.com/859477): Remove after root cause is found.
-    case base::Value::Type::DEAD:
-      CHECK(false);
-      break;
-
-    // TODO(crbug.com/859477): Remove after root cause is found.
-    default:
-      CHECK(false);
-      break;
   }
 
   return descriptor;
diff --git a/chrome/browser/ui/global_media_controls/media_notification_service.cc b/chrome/browser/ui/global_media_controls/media_notification_service.cc
index 98c6ede..afb3a254 100644
--- a/chrome/browser/ui/global_media_controls/media_notification_service.cc
+++ b/chrome/browser/ui/global_media_controls/media_notification_service.cc
@@ -79,14 +79,19 @@
       !media_session_notification_producer_->ActivateItem(id)) {
     return;
   }
-  ShowAndObserveContainer(id);
+
+  // If new notifications come up while the dialog is open for a
+  // PresentationRequest, do not show the new notifications.
+  if (!HasOpenDialogForPresentationRequest()) {
+    ShowAndObserveContainer(id);
+  }
 }
 
 void MediaNotificationService::HideNotification(const std::string& id) {
   if (media_session_notification_producer_) {
     media_session_notification_producer_->HideItem(id);
   }
-  OnNotificationChanged(&id);
+  OnNotificationChanged();
   if (!dialog_delegate_) {
     return;
   }
@@ -99,7 +104,7 @@
   const auto id_copy{id};
   if (media_session_notification_producer_)
     media_session_notification_producer_->RemoveItem(id_copy);
-  OnNotificationChanged(&id_copy);
+  OnNotificationChanged();
 }
 
 scoped_refptr<base::SequencedTaskRunner>
@@ -131,11 +136,12 @@
 }
 
 void MediaNotificationService::OnCastNotificationsChanged() {
-  OnNotificationChanged(nullptr);
+  OnNotificationChanged();
 }
 
 void MediaNotificationService::SetDialogDelegate(
     MediaDialogDelegate* delegate) {
+  dialog_opened_from_presentation_ = false;
   SetDialogDelegateCommon(delegate);
   if (!dialog_delegate_)
     return;
@@ -172,6 +178,7 @@
 void MediaNotificationService::SetDialogDelegateForWebContents(
     MediaDialogDelegate* delegate,
     content::WebContents* contents) {
+  dialog_opened_from_presentation_ = true;
   SetDialogDelegateCommon(delegate);
   if (!dialog_delegate_)
     return;
@@ -250,6 +257,10 @@
   return !!dialog_delegate_;
 }
 
+bool MediaNotificationService::HasOpenDialogForPresentationRequest() const {
+  return HasOpenDialog() && dialog_opened_from_presentation_;
+}
+
 void MediaNotificationService::HideMediaDialog() {
   if (dialog_delegate_) {
     dialog_delegate_->HideMediaDialog();
@@ -310,7 +321,7 @@
 }
 
 void MediaNotificationService::ShowAndObserveContainer(const std::string& id) {
-  OnNotificationChanged(&id);
+  OnNotificationChanged();
   if (!dialog_delegate_) {
     return;
   }
@@ -334,9 +345,7 @@
   return nullptr;
 }
 
-// TODO(muyaoxu@): Remove |changed_notification_id| since its no longer used.
-void MediaNotificationService::OnNotificationChanged(
-    const std::string* changed_notification_id) {
+void MediaNotificationService::OnNotificationChanged() {
   for (auto& observer : observers_)
     observer.OnNotificationListChanged();
 }
diff --git a/chrome/browser/ui/global_media_controls/media_notification_service.h b/chrome/browser/ui/global_media_controls/media_notification_service.h
index 59cb71b..ea62b5f 100644
--- a/chrome/browser/ui/global_media_controls/media_notification_service.h
+++ b/chrome/browser/ui/global_media_controls/media_notification_service.h
@@ -165,10 +165,8 @@
   GetNotificationItem(const std::string& id);
 
   // Called after changing anything about a notification to notify any observers
-  // and update the visibility of supplemental notifications.  If the change is
-  // associated with a particular notification ID, that ID should be passed as
-  // the argument, otherwise the argument should be nullptr.
-  void OnNotificationChanged(const std::string* changed_notification_id);
+  // and update the visibility of supplemental notifications.
+  void OnNotificationChanged();
 
   MediaNotificationProducer* GetNotificationProducer(
       const std::string& notification_id);
@@ -177,8 +175,16 @@
   // SetDialogDelegate() and SetDialogDelegateForPresentationRequest().
   void SetDialogDelegateCommon(MediaDialogDelegate* delegate);
 
+  // True if there is an open MediaDialogView and the dialog is opened for a
+  // PresentationRequest.
+  bool HasOpenDialogForPresentationRequest() const;
+
   MediaDialogDelegate* dialog_delegate_ = nullptr;
 
+  // True if the dialog was opened by |SetDialogDelegateForWebContents()|. The
+  // value does not indicate whether the MediaDialogView is opened or not.
+  bool dialog_opened_from_presentation_ = false;
+
   std::unique_ptr<MediaSessionNotificationProducer>
       media_session_notification_producer_;
   std::unique_ptr<CastMediaNotificationProducer> cast_notification_producer_;
diff --git a/chrome/browser/ui/global_media_controls/media_session_notification_producer.cc b/chrome/browser/ui/global_media_controls/media_session_notification_producer.cc
index 740069f..75fe9f30 100644
--- a/chrome/browser/ui/global_media_controls/media_session_notification_producer.cc
+++ b/chrome/browser/ui/global_media_controls/media_session_notification_producer.cc
@@ -418,7 +418,7 @@
                      base::Unretained(this), id));
   active_controllable_session_ids_.erase(id);
   frozen_session_ids_.insert(id);
-  service_->OnNotificationChanged(&id);
+  service_->OnNotificationChanged();
 }
 
 void MediaSessionNotificationProducer::OnContainerClicked(
@@ -485,7 +485,7 @@
   dragged_out_session_ids_.insert(id);
   overlay_media_notifications_manager_.ShowOverlayNotification(
       id, std::move(overlay_notification));
-  service_->OnNotificationChanged(&id);
+  service_->OnNotificationChanged();
 }
 
 void MediaSessionNotificationProducer::OnAudioSinkChosen(
@@ -708,5 +708,5 @@
   if (!base::Contains(dragged_out_session_ids_, id))
     active_controllable_session_ids_.insert(id);
 
-  service_->OnNotificationChanged(&id);
+  service_->OnNotificationChanged();
 }
diff --git a/chrome/browser/ui/user_education/feature_promo_snooze_service.cc b/chrome/browser/ui/user_education/feature_promo_snooze_service.cc
index 79b91c2..f2c12af 100644
--- a/chrome/browser/ui/user_education/feature_promo_snooze_service.cc
+++ b/chrome/browser/ui/user_education/feature_promo_snooze_service.cc
@@ -24,37 +24,25 @@
 // PrefService path.
 const char kIPHSnoozeDataPath[] = "in_product_help.snoozed_feature";
 
-// Path to the boolean indicates if an IPH was dismissed.
+// Path to the boolean indicates if an IPH is dismissed.
 // in_product_help.snoozed_feature.[iph_name].is_dismissed
-constexpr char kIPHIsDismissedPath[] = "is_dismissed";
-// Path to the timestamp an IPH was last shown.
-// in_product_help.snoozed_feature.[iph_name].last_show_time
-constexpr char kIPHLastShowTimePath[] = "last_show_time";
-// Path to the timestamp an IPH was last snoozed.
+constexpr char kIPHIsFeatureDismissed[] = "is_dismissed";
+// Path to the timestamp an IPH is snoozed.
 // in_product_help.snoozed_feature.[iph_name].last_snooze_time
-constexpr char kIPHLastSnoozeTimePath[] = "last_snooze_time";
+constexpr char kIPHSnoozedFeatureTime[] = "last_snooze_time";
 // Path to the duration of snooze.
 // in_product_help.snoozed_feature.[iph_name].last_snooze_duration
-constexpr char kIPHLastSnoozeDurationPath[] = "last_snooze_duration";
+constexpr char kIPHSnoozedFeatureDuration[] = "last_snooze_duration";
 // Path to the count of how many times this IPH has been snoozed.
 // in_product_help.snoozed_feature.[iph_name].snooze_count
-constexpr char kIPHSnoozeCountPath[] = "snooze_count";
-// Path to the count of how many times this IPH has been shown.
-// in_product_help.snoozed_feature.[iph_name].show_count
-constexpr char kIPHShowCountPath[] = "show_count";
+constexpr char kIPHSnoozedFeatureCount[] = "snooze_count";
 
 // Finch parameter to control the snooze duration.
 // If this parameter is not specified or is zero, the default duration at the
 // client side will be used.
 constexpr base::FeatureParam<base::TimeDelta> kOverriddenDuration{
     &feature_engagement::kIPHDesktopSnoozeFeature,
-    "x_iph_snooze_overridden_duration", base::TimeDelta::FromHours(0)};
-
-constexpr base::FeatureParam<FeaturePromoSnoozeService::NonClickerPolicy>::
-    Option kNonClickerPolicyOptions[] = {
-        {FeaturePromoSnoozeService::NonClickerPolicy::kDismiss, "dismiss"},
-        {FeaturePromoSnoozeService::NonClickerPolicy::kLongSnooze,
-         "long_snooze"}};
+    "x_iph_snooze_overridden_duration ", base::TimeDelta::FromHours(0)};
 
 // Used in UMA histogram to track if the user snoozes for once or more.
 enum class SnoozeType {
@@ -113,18 +101,6 @@
       snooze_data->snooze_count, kUmaMaxSnoozeCount);
 }
 
-void FeaturePromoSnoozeService::OnPromoShown(const base::Feature& iph_feature) {
-  auto snooze_data = ReadSnoozeData(iph_feature);
-
-  if (!snooze_data)
-    snooze_data = SnoozeData();
-
-  snooze_data->last_show_time = base::Time::Now();
-  snooze_data->show_count++;
-
-  SaveSnoozeData(iph_feature, *snooze_data);
-}
-
 bool FeaturePromoSnoozeService::IsBlocked(const base::Feature& iph_feature) {
   auto snooze_data = ReadSnoozeData(iph_feature);
 
@@ -135,37 +111,17 @@
   if (snooze_data->is_dismissed)
     return true;
 
-  // This IPH is shown for the first time.
-  if (snooze_data->show_count == 0)
+  // This IPH has neither been dismissed nor snoozed.
+  if (snooze_data->snooze_count == 0)
     return false;
 
-  if (snooze_data->snooze_count > 0 &&
-      snooze_data->last_snooze_time >= snooze_data->last_show_time) {
-    // The IPH was snoozed on last display.
+  // Corruption: Snooze time is in the future.
+  if (snooze_data->last_snooze_time > base::Time::Now())
+    return true;
 
-    // Corruption: Snooze time is in the future.
-    if (snooze_data->last_snooze_time > base::Time::Now())
-      return true;
-
-    // This IPH is snoozed. Test if snooze period has expired.
-    return base::Time::Now() <
-           snooze_data->last_snooze_time + snooze_data->last_snooze_duration;
-  } else {
-    // The IPH was neither snoozed or dismissed on last display.
-    const base::FeatureParam<FeaturePromoSnoozeService::NonClickerPolicy>
-        kNonClickerPolicy{
-            &iph_feature, "x_iph_snooze_non_clicker_policy",
-            FeaturePromoSnoozeService::NonClickerPolicy::kLongSnooze,
-            &kNonClickerPolicyOptions};
-
-    NonClickerPolicy non_clicker_policy = kNonClickerPolicy.Get();
-
-    if (non_clicker_policy == NonClickerPolicy::kDismiss)
-      return true;
-
-    return base::Time::Now() <
-           snooze_data->last_show_time + base::TimeDelta::FromDays(14);
-  }
+  // This IPH is snoozed. Test if snooze period has expired.
+  return base::Time::Now() <
+         snooze_data->last_snooze_time + snooze_data->last_snooze_duration;
 }
 
 // static
@@ -193,17 +149,13 @@
   const base::DictionaryValue* pref_data =
       profile_->GetPrefs()->GetDictionary(kIPHSnoozeDataPath);
   base::Optional<bool> is_dismissed =
-      pref_data->FindBoolPath(path_prefix + kIPHIsDismissedPath);
-  base::Optional<base::Time> show_time = util::ValueToTime(
-      pref_data->FindPath(path_prefix + kIPHLastShowTimePath));
+      pref_data->FindBoolPath(path_prefix + kIPHIsFeatureDismissed);
   base::Optional<base::Time> snooze_time = util::ValueToTime(
-      pref_data->FindPath(path_prefix + kIPHLastSnoozeTimePath));
-  base::Optional<base::TimeDelta> snooze_duration = util::ValueToTimeDelta(
-      pref_data->FindPath(path_prefix + kIPHLastSnoozeDurationPath));
+      pref_data->FindPath(path_prefix + kIPHSnoozedFeatureTime));
   base::Optional<int> snooze_count =
-      pref_data->FindIntPath(path_prefix + kIPHSnoozeCountPath);
-  base::Optional<int> show_count =
-      pref_data->FindIntPath(path_prefix + kIPHShowCountPath);
+      pref_data->FindIntPath(path_prefix + kIPHSnoozedFeatureCount);
+  base::Optional<base::TimeDelta> snooze_duration = util::ValueToTimeDelta(
+      pref_data->FindPath(path_prefix + kIPHSnoozedFeatureDuration));
 
   base::Optional<SnoozeData> snooze_data;
 
@@ -218,11 +170,9 @@
 
   snooze_data = SnoozeData();
   snooze_data->is_dismissed = *is_dismissed;
-  snooze_data->last_show_time = *show_time;
   snooze_data->last_snooze_time = *snooze_time;
   snooze_data->last_snooze_duration = *snooze_duration;
   snooze_data->snooze_count = *snooze_count;
-  snooze_data->show_count = *show_count;
 
   return snooze_data;
 }
@@ -235,16 +185,12 @@
   DictionaryPrefUpdate update(profile_->GetPrefs(), kIPHSnoozeDataPath);
   base::DictionaryValue* pref_data = update.Get();
 
-  pref_data->SetBoolPath(path_prefix + kIPHIsDismissedPath,
+  pref_data->SetBoolPath(path_prefix + kIPHIsFeatureDismissed,
                          snooze_data.is_dismissed);
-  pref_data->SetPath(path_prefix + kIPHLastShowTimePath,
-                     util::TimeToValue(snooze_data.last_show_time));
-  pref_data->SetPath(path_prefix + kIPHLastSnoozeTimePath,
+  pref_data->SetPath(path_prefix + kIPHSnoozedFeatureTime,
                      util::TimeToValue(snooze_data.last_snooze_time));
-  pref_data->SetPath(path_prefix + kIPHLastSnoozeDurationPath,
+  pref_data->SetPath(path_prefix + kIPHSnoozedFeatureDuration,
                      util::TimeDeltaToValue(snooze_data.last_snooze_duration));
-  pref_data->SetIntPath(path_prefix + kIPHSnoozeCountPath,
+  pref_data->SetIntPath(path_prefix + kIPHSnoozedFeatureCount,
                         snooze_data.snooze_count);
-  pref_data->SetIntPath(path_prefix + kIPHShowCountPath,
-                        snooze_data.show_count);
 }
diff --git a/chrome/browser/ui/user_education/feature_promo_snooze_service.h b/chrome/browser/ui/user_education/feature_promo_snooze_service.h
index 3d915e5b..c364f05 100644
--- a/chrome/browser/ui/user_education/feature_promo_snooze_service.h
+++ b/chrome/browser/ui/user_education/feature_promo_snooze_service.h
@@ -17,21 +17,14 @@
 class Profile;
 class PrefRegistrySimple;
 
-// This service manages snooze and dismiss of snoozable in-product help promo.
+// This service manages snooze and dismiss of in-product help promo.
 //
-// Before showing an IPH, the IPH controller should ask if the IPH is blocked.
-// The controller should also notify after the IPH is shown and after the user
-// clicks the snooze/dismiss button.
+// An IPH controller notifies this service when an IPH is snoozed or dismissed.
+// When the snooze period expires, this service will approve controller's
+// request to retrigger the IPH.
+// If an IPH is dismissed, this service will reject controller's request.
 class FeaturePromoSnoozeService {
  public:
-  // Policies to handler users who don't interact with the IPH.
-  enum class NonClickerPolicy {
-    // Permanently dismiss the IPH. Equivalent to clicking the dismiss button.
-    kDismiss = 0,
-    // Reshow the IPH later after at least 14 days.
-    kLongSnooze
-  };
-
   // Maximum count of snoozes to track in UMA histogram.
   // Snooze counts that are equal or larger than this value will be conflated.
   static const int kUmaMaxSnoozeCount;
@@ -55,9 +48,6 @@
   // after a fixed amount of time.
   void OnUserDismiss(const base::Feature& iph_feature);
 
-  // The IPH controller must call this method after an IPH is shown.
-  void OnPromoShown(const base::Feature& iph_feature);
-
   // The IPH controller must call this method to check if an IPH is blocked by
   // dismiss or snooze. An IPH will be approved if it is not snoozed or the
   // snoozing period has timed out.
@@ -80,11 +70,9 @@
   // in_product_help.snoozed_feature.[iph_name] in PerfService.
   struct SnoozeData {
     bool is_dismissed = false;
-    base::Time last_show_time = base::Time();
     base::Time last_snooze_time = base::Time();
     base::TimeDelta last_snooze_duration = base::TimeDelta();
     int snooze_count = 0;
-    int show_count = 0;
   };
 
   base::Optional<SnoozeData> ReadSnoozeData(const base::Feature& iph_feature);
diff --git a/chrome/browser/ui/user_education/feature_promo_snooze_service_unittest.cc b/chrome/browser/ui/user_education/feature_promo_snooze_service_unittest.cc
index 59bd3c43..679f1a2 100644
--- a/chrome/browser/ui/user_education/feature_promo_snooze_service_unittest.cc
+++ b/chrome/browser/ui/user_education/feature_promo_snooze_service_unittest.cc
@@ -7,12 +7,9 @@
 #include <memory>
 
 #include "base/feature_list.h"
-#include "base/metrics/field_trial_param_associator.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
 #include "chrome/test/base/testing_profile.h"
-#include "components/feature_engagement/public/feature_constants.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -30,31 +27,19 @@
                               MOCK_TIME},
         service_{&profile_} {}
 
-  void SetNonClickerPolicy(base::test::ScopedFeatureList& feature_list,
-                           FeaturePromoSnoozeService::NonClickerPolicy policy) {
-    std::map<std::string, std::string> parameters = {
-        {"x_iph_snooze_non_clicker_policy",
-         policy == FeaturePromoSnoozeService::NonClickerPolicy::kDismiss
-             ? "dismiss"
-             : "long_snooze"}};
-    feature_list.InitAndEnableFeatureWithParameters(kTestIPHFeature,
-                                                    parameters);
-  }
-
  protected:
   content::BrowserTaskEnvironment task_environment_;
   TestingProfile profile_;
   FeaturePromoSnoozeService service_;
 };
 
-TEST_F(FeaturePromoSnoozeServiceTest, AllowFirstTimeIPH) {
+TEST_F(FeaturePromoSnoozeServiceTest, AllowNonSnoozedIPH) {
   service_.Reset(kTestIPHFeature);
   EXPECT_FALSE(service_.IsBlocked(kTestIPHFeature));
 }
 
 TEST_F(FeaturePromoSnoozeServiceTest, BlockDismissedIPH) {
   service_.Reset(kTestIPHFeature);
-  service_.OnPromoShown(kTestIPHFeature);
   service_.OnUserDismiss(kTestIPHFeature);
   EXPECT_TRUE(service_.IsBlocked(kTestIPHFeature));
   service_.Reset(kTestIPHFeature);
@@ -63,14 +48,12 @@
 
 TEST_F(FeaturePromoSnoozeServiceTest, BlockSnoozedIPH) {
   service_.Reset(kTestIPHFeature);
-  service_.OnPromoShown(kTestIPHFeature);
   service_.OnUserSnooze(kTestIPHFeature);
   EXPECT_TRUE(service_.IsBlocked(kTestIPHFeature));
 }
 
 TEST_F(FeaturePromoSnoozeServiceTest, ReleaseSnoozedIPH) {
   service_.Reset(kTestIPHFeature);
-  service_.OnPromoShown(kTestIPHFeature);
   service_.OnUserSnooze(kTestIPHFeature, base::TimeDelta::FromHours(1));
   EXPECT_TRUE(service_.IsBlocked(kTestIPHFeature));
   task_environment_.FastForwardBy(base::TimeDelta::FromHours(2));
@@ -80,9 +63,7 @@
 TEST_F(FeaturePromoSnoozeServiceTest, MultipleIPH) {
   service_.Reset(kTestIPHFeature);
   service_.Reset(kTestIPHFeature2);
-  service_.OnPromoShown(kTestIPHFeature);
   service_.OnUserSnooze(kTestIPHFeature, base::TimeDelta::FromHours(1));
-  service_.OnPromoShown(kTestIPHFeature2);
   service_.OnUserSnooze(kTestIPHFeature2, base::TimeDelta::FromHours(3));
   EXPECT_TRUE(service_.IsBlocked(kTestIPHFeature));
   EXPECT_TRUE(service_.IsBlocked(kTestIPHFeature2));
@@ -93,25 +74,3 @@
   EXPECT_FALSE(service_.IsBlocked(kTestIPHFeature));
   EXPECT_FALSE(service_.IsBlocked(kTestIPHFeature2));
 }
-
-TEST_F(FeaturePromoSnoozeServiceTest, SnoozeNonClicker) {
-  base::test::ScopedFeatureList feature_list;
-  SetNonClickerPolicy(feature_list,
-                      FeaturePromoSnoozeService::NonClickerPolicy::kLongSnooze);
-  service_.Reset(kTestIPHFeature);
-  service_.OnPromoShown(kTestIPHFeature);
-  EXPECT_TRUE(service_.IsBlocked(kTestIPHFeature));
-  task_environment_.FastForwardBy(base::TimeDelta::FromDays(15));
-  EXPECT_FALSE(service_.IsBlocked(kTestIPHFeature));
-}
-
-TEST_F(FeaturePromoSnoozeServiceTest, DismissNonClicker) {
-  base::test::ScopedFeatureList feature_list;
-  SetNonClickerPolicy(feature_list,
-                      FeaturePromoSnoozeService::NonClickerPolicy::kDismiss);
-  service_.Reset(kTestIPHFeature);
-  service_.OnPromoShown(kTestIPHFeature);
-  EXPECT_TRUE(service_.IsBlocked(kTestIPHFeature));
-  task_environment_.FastForwardBy(base::TimeDelta::FromDays(15));
-  EXPECT_TRUE(service_.IsBlocked(kTestIPHFeature));
-}
diff --git a/chrome/browser/ui/views/location_bar/permission_chip_browsertest.cc b/chrome/browser/ui/views/location_bar/permission_chip_browsertest.cc
index bf5cad1..c09a923 100644
--- a/chrome/browser/ui/views/location_bar/permission_chip_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/permission_chip_browsertest.cc
@@ -83,6 +83,8 @@
   base::test::ScopedFeatureList feature_list_;
 };
 
-IN_PROC_BROWSER_TEST_F(PermissionChipBrowserTest, InvokeUi_geolocation) {
+// Temporarily disabled per https://crbug.com/1197280
+IN_PROC_BROWSER_TEST_F(PermissionChipBrowserTest,
+                       DISABLED_InvokeUi_geolocation) {
   ShowAndVerifyUi();
 }
diff --git a/chrome/browser/ui/views/overlay/back_to_tab_label_button.cc b/chrome/browser/ui/views/overlay/back_to_tab_label_button.cc
index d30ad5a7..622103e2 100644
--- a/chrome/browser/ui/views/overlay/back_to_tab_label_button.cc
+++ b/chrome/browser/ui/views/overlay/back_to_tab_label_button.cc
@@ -17,6 +17,8 @@
 
 namespace {
 
+constexpr int kBackToTabButtonMargin = 48;
+
 constexpr int kBackToTabButtonSize = 20;
 
 constexpr int kBackToTabImageSize = 14;
@@ -88,7 +90,8 @@
   if (!window_size_.has_value())
     return;
 
-  SetMaxSize(gfx::Size(window_size_->width() - 48, kBackToTabButtonSize));
+  SetMaxSize(gfx::Size(window_size_->width() - kBackToTabButtonMargin,
+      kBackToTabButtonSize));
   SetSize(CalculatePreferredSize());
   LabelButton::SetPosition(
       gfx::Point((window_size_->width() / 2) - (size().width() / 2),
diff --git a/chrome/browser/ui/views/page_info/page_info_hover_button.cc b/chrome/browser/ui/views/page_info/page_info_hover_button.cc
index 0fc0925..e8d075a7 100644
--- a/chrome/browser/ui/views/page_info/page_info_hover_button.cc
+++ b/chrome/browser/ui/views/page_info/page_info_hover_button.cc
@@ -6,30 +6,47 @@
 
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/accessibility/non_accessible_image_view.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
+#include "components/page_info/features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/views/animation/ink_drop.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/styled_label.h"
+#include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/metadata/metadata_impl_macros.h"
 #include "ui/views/style/typography.h"
 
+namespace {
+
+std::unique_ptr<views::View> CreateIconView(const gfx::ImageSkia& icon_image) {
+  auto icon = std::make_unique<NonAccessibleImageView>();
+  icon->SetImage(icon_image);
+  // Make sure hovering over the icon also hovers the `PageInfoHoverButton`.
+  icon->SetCanProcessEventsWithinSubtree(false);
+  // Don't cover |icon| when the ink drops are being painted.
+  icon->SetPaintToLayer();
+  icon->layer()->SetFillsBoundsOpaquely(false);
+  return icon;
+}
+
+}  // namespace
+
 PageInfoHoverButton::PageInfoHoverButton(
     views::Button::PressedCallback callback,
-    const gfx::ImageSkia& image_icon,
+    const gfx::ImageSkia& main_image_icon,
     int title_resource_id,
     const std::u16string& secondary_text,
     int click_target_id,
     const std::u16string& tooltip_text,
-    const std::u16string& subtitle_text)
+    const std::u16string& subtitle_text,
+    base::Optional<gfx::ImageSkia> action_image_icon)
     : HoverButton(std::move(callback), std::u16string()) {
   label()->SetHandlesTooltips(false);
-  auto icon = std::make_unique<NonAccessibleImageView>();
-  icon->SetImage(image_icon);
 
   ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get();
 
@@ -44,39 +61,56 @@
                      views::GridLayout::kFixedSize,
                      views::GridLayout::ColumnSize::kUsePreferred, 0, 0);
   columns->AddPaddingColumn(views::GridLayout::kFixedSize, icon_label_spacing);
-  columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1.0,
+  columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 1.0,
                      views::GridLayout::ColumnSize::kUsePreferred, 0, 0);
+  columns->AddPaddingColumn(views::GridLayout::kFixedSize, icon_label_spacing);
+  columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::FILL,
+                     views::GridLayout::kFixedSize,
+                     views::GridLayout::ColumnSize::kUsePreferred,
+                     views::GridLayout::kFixedSize, 0);
+  columns->AddPaddingColumn(views::GridLayout::kFixedSize, icon_label_spacing);
+  columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
+                     views::GridLayout::kFixedSize,
+                     views::GridLayout::ColumnSize::kFixed, 16, 0);
 
-  // Make sure hovering over the icon also hovers the |PageInfoHoverButton|.
-  icon->SetCanProcessEventsWithinSubtree(false);
-  // Don't cover |icon_view| when the ink drops are being painted.
-  icon->SetPaintToLayer();
-  icon->layer()->SetFillsBoundsOpaquely(false);
+  views::style::TextContext text_context =
+      base::FeatureList::IsEnabled(page_info::kPageInfoV2Desktop)
+          ? views::style::CONTEXT_DIALOG_BODY_TEXT
+          : views::style::CONTEXT_LABEL;
 
   // Force row to have sufficient height for full line-height of the title.
   grid_layout->StartRow(
       views::GridLayout::kFixedSize, kColumnSetId,
-      views::style::GetLineHeight(views::style::CONTEXT_LABEL,
-                                  views::style::STYLE_PRIMARY));
+      views::style::GetLineHeight(text_context, views::style::STYLE_PRIMARY));
 
-  icon_view_ = grid_layout->AddView(std::move(icon));
-
+  grid_layout->AddView(CreateIconView(main_image_icon));
   auto title_label = std::make_unique<views::StyledLabel>();
-  title_label->SetTextContext(views::style::CONTEXT_LABEL);
-  // views::StyledLabels are all multi-line. With a layout manager, StyledLabel
-  // will try use the available space to size itself, and long titles will wrap
-  // to the next line (for smaller PageInfoHoverButtons, this will also cover up
-  // |subtitle_|). Wrap it in a parent view with no layout manager to ensure it
-  // keeps its original size set by SizeToFit() above. Long titles will then be
-  // truncated.
-  auto title_wrapper = std::make_unique<views::View>();
-  title_ = title_wrapper->AddChildView(std::move(title_label));
-  SetTitleText(title_resource_id, secondary_text);
+  title_label->SetTextContext(text_context);
 
-  // Hover the whole button when hovering |title_|. This is OK because |title_|
-  // will never have a link in it.
-  title_wrapper->SetCanProcessEventsWithinSubtree(false);
-  grid_layout->AddView(std::move(title_wrapper));
+  if (base::FeatureList::IsEnabled(page_info::kPageInfoV2Desktop)) {
+    title_ = grid_layout->AddView(std::move(title_label));
+    title_->SetCanProcessEventsWithinSubtree(false);
+
+    auto secondary_label = std::make_unique<views::Label>(
+        std::u16string(), views::style::CONTEXT_LABEL,
+        views::style::STYLE_SECONDARY);
+    secondary_label->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
+    secondary_label_ = grid_layout->AddView(std::move(secondary_label));
+
+    if (action_image_icon.has_value()) {
+      grid_layout->AddView(CreateIconView(action_image_icon.value()));
+    }
+  } else {
+    auto title_wrapper = std::make_unique<views::View>();
+    title_wrapper->SetLayoutManager(std::make_unique<views::BoxLayout>(
+        views::BoxLayout::Orientation::kHorizontal));
+    title_ = title_wrapper->AddChildView(std::move(title_label));
+    // Hover the whole button when hovering |title_|. This is OK because
+    // |title_| will never have a link in it.
+    title_wrapper->SetCanProcessEventsWithinSubtree(false);
+    grid_layout->AddView(std::move(title_wrapper));
+  }
+  SetTitleText(title_resource_id, secondary_text);
 
   if (!subtitle_text.empty()) {
     grid_layout->StartRow(views::GridLayout::kFixedSize, kColumnSetId);
@@ -110,6 +144,9 @@
   DCHECK(title_);
   if (secondary_text.empty()) {
     title_->SetText(l10n_util::GetStringUTF16(title_resource_id));
+  } else if (base::FeatureList::IsEnabled(page_info::kPageInfoV2Desktop)) {
+    title_->SetText(l10n_util::GetStringUTF16(title_resource_id));
+    secondary_label_->SetText(secondary_text);
   } else {
     size_t offset;
     auto title_text =
@@ -125,11 +162,15 @@
 }
 
 void PageInfoHoverButton::UpdateAccessibleName() {
+  const std::u16string title_text =
+      secondary_label_ == nullptr
+          ? title()->GetText()
+          : base::JoinString({title()->GetText(), secondary_label_->GetText()},
+                             u" ");
   const std::u16string accessible_name =
       subtitle() == nullptr
-          ? title()->GetText()
-          : base::JoinString({title()->GetText(), subtitle()->GetText()},
-                             u"\n");
+          ? title_text
+          : base::JoinString({title_text, subtitle()->GetText()}, u"\n");
   HoverButton::SetAccessibleName(accessible_name);
 }
 
diff --git a/chrome/browser/ui/views/page_info/page_info_hover_button.h b/chrome/browser/ui/views/page_info/page_info_hover_button.h
index ee44e8b9..84bbf5a 100644
--- a/chrome/browser/ui/views/page_info/page_info_hover_button.h
+++ b/chrome/browser/ui/views/page_info/page_info_hover_button.h
@@ -27,8 +27,8 @@
 class PageInfoBubbleViewBrowserTest;
 
 // Hoverable button containing icon, styled title, and (multi-line) subtitle.
-// PageInfoHoverButton inherits the interaction behavior from HoverButton but
-// sets up its own layout and content.
+// 'PageInfoHoverButton' inherits the interaction behavior from 'HoverButton'
+// but sets up its own layout and content.
 class PageInfoHoverButton : public HoverButton {
  public:
   METADATA_HEADER(PageInfoHoverButton);
@@ -38,18 +38,29 @@
   // the secondary text color. The |subtitle_text| is shown below the title text
   // in secondary text color. |tooltip_text| is used for the tooltip shown on
   // hovering over the button.
-  // *-----------------------------------------------------------------*
-  // | Icon | Title |title_resource_id| string + |secondary_text|      |
-  // |-----------------------------------------------------------------|
-  // |      | |subtitle_text|                                          |
-  // *-----------------------------------------------------------------*
-  PageInfoHoverButton(views::Button::PressedCallback callback,
-                      const gfx::ImageSkia& image_icon,
-                      int title_resource_id,
-                      const std::u16string& secondary_text,
-                      int click_target_id,
-                      const std::u16string& tooltip_text,
-                      const std::u16string& subtitle_text);
+  // *-------------------------------------------------------------------------*
+  // | Icon | |title_resource_id| + |secondary_text|                           |
+  // |-------------------------------------------------------------------------|
+  // |      | |subtitle_text|                                                  |
+  // *-------------------------------------------------------------------------*
+  // If flag PageInfoV2Desktop is enabled, the button will look different.
+  // Optional |action_image_icom| is shown on right side. |secondary_text| isn't
+  // concatenated with the |title_resource_id|, it is shown separately on right
+  // side before the |action_image_icon|.
+  // *-------------------------------------------------------------------------*
+  // | Icon | |title_resource_id|               |secondary_text| | Action icon |
+  // |-------------------------------------------------------------------------|
+  // |      | |subtitle_text|                                                  |
+  // *-------------------------------------------------------------------------*
+  PageInfoHoverButton(
+      views::Button::PressedCallback callback,
+      const gfx::ImageSkia& main_image_icon,
+      int title_resource_id,
+      const std::u16string& secondary_text,
+      int click_target_id,
+      const std::u16string& tooltip_text,
+      const std::u16string& subtitle_text,
+      base::Optional<gfx::ImageSkia> action_image_icon = base::nullopt);
   ~PageInfoHoverButton() override {}
 
   // Updates the title text, and applies the secondary style to the secondary
@@ -60,7 +71,6 @@
  protected:
   views::StyledLabel* title() const { return title_; }
   views::Label* subtitle() const { return subtitle_; }
-  views::View* icon_view() const { return icon_view_; }
   // HoverButton:
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
   views::View* GetTooltipHandlerForPoint(const gfx::Point& point) override;
@@ -74,8 +84,9 @@
   void UpdateAccessibleName();
 
   views::StyledLabel* title_ = nullptr;
+  // Shows secondary text on right side. Used for page info v2 only.
+  views::Label* secondary_label_ = nullptr;
   views::Label* subtitle_ = nullptr;
-  views::View* icon_view_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(PageInfoHoverButton);
 };
diff --git a/chrome/browser/ui/views/page_info/page_info_main_view.cc b/chrome/browser/ui/views/page_info/page_info_main_view.cc
index 9e383754..2e72ebf 100644
--- a/chrome/browser/ui/views/page_info/page_info_main_view.cc
+++ b/chrome/browser/ui/views/page_info/page_info_main_view.cc
@@ -39,6 +39,12 @@
                                 views::style::STYLE_PRIMARY);
 }
 
+SkColor GetSecondaryLabelColor() {
+  views::Label label;
+  return views::style::GetColor(label, views::style::CONTEXT_LABEL,
+                                views::style::STYLE_SECONDARY);
+}
+
 }  // namespace
 
 PageInfoMainView::PageInfoMainView(PageInfo* presenter,
@@ -95,7 +101,8 @@
         PageInfoUI::GetSiteSettingsIcon(GetRelatedTextColor()),
         IDS_PAGE_INFO_SITE_SETTINGS_LINK, std::u16string(),
         PageInfoMainView::VIEW_ID_PAGE_INFO_LINK_OR_BUTTON_SITE_SETTINGS,
-        tooltip, std::u16string()));
+        tooltip, std::u16string(),
+        PageInfoUI::GetLaunchIcon(GetSecondaryLabelColor())));
   }
 
 #if defined(OS_WIN) && BUILDFLAG(ENABLE_VR)
@@ -119,7 +126,7 @@
 
   // Get the string to display the number of cookies.
   const std::u16string num_cookies_text = l10n_util::GetPluralStringFUTF16(
-      IDS_PAGE_INFO_NUM_COOKIES_PARENTHESIZED, total_allowed);
+      IDS_PAGE_INFO_NUM_COOKIES, total_allowed);
 
   // Create the cookie button if it doesn't yet exist. This method gets called
   // each time site data is updated, so if it *does* already exist, skip this
@@ -142,16 +149,16 @@
                   view->HandleMoreInfoRequest(view->cookie_button_);
                 },
                 this),
-            icon, IDS_PAGE_INFO_COOKIES_BUTTON_TEXT, num_cookies_text,
+            icon, IDS_PAGE_INFO_COOKIES, num_cookies_text,
             VIEW_ID_PAGE_INFO_LINK_OR_BUTTON_COOKIE_DIALOG, tooltip,
-            std::u16string())
+            std::u16string(),
+            PageInfoUI::GetLaunchIcon(GetSecondaryLabelColor()))
             .release();
     site_settings_view_->AddChildView(cookie_button_);
   }
 
   // Update the text displaying the number of allowed cookies.
-  cookie_button_->SetTitleText(IDS_PAGE_INFO_COOKIES_BUTTON_TEXT,
-                               num_cookies_text);
+  cookie_button_->SetTitleText(IDS_PAGE_INFO_COOKIES, num_cookies_text);
 
   PreferredSizeChanged();
 }
@@ -327,9 +334,9 @@
                   view->HandleMoreInfoRequest(view->certificate_button_);
                 },
                 this),
-            icon, IDS_PAGE_INFO_CERTIFICATE_BUTTON_TEXT, secondary_text,
+            icon, IDS_PAGE_INFO_CERTIFICATE, secondary_text,
             VIEW_ID_PAGE_INFO_LINK_OR_BUTTON_CERTIFICATE_VIEWER, tooltip,
-            subtitle_text)
+            subtitle_text, PageInfoUI::GetLaunchIcon(GetSecondaryLabelColor()))
             .release());
   }
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 2d44d9734..4fcd83c1 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -3385,7 +3385,7 @@
 
   Tab* tab = tab_at(std::min(drop_index, GetTabCount() - 1));
   const bool first_in_group =
-      tab->group().has_value() &&
+      drop_index < GetTabCount() && tab->group().has_value() &&
       GetModelIndexOf(tab) ==
           controller_->GetFirstTabInGroup(tab->group().value());
 
diff --git a/chrome/browser/ui/views/user_education/feature_promo_controller_views.cc b/chrome/browser/ui/views/user_education/feature_promo_controller_views.cc
index a241169..603f3042 100644
--- a/chrome/browser/ui/views/user_education/feature_promo_controller_views.cc
+++ b/chrome/browser/ui/views/user_education/feature_promo_controller_views.cc
@@ -242,8 +242,6 @@
                                 snooze_count,
                                 snooze_service_->kUmaMaxSnoozeCount);
 
-  snooze_service_->OnPromoShown(iph_feature);
-
   ShowPromoBubbleImpl(params);
   close_callback_ = std::move(close_callback);
 
diff --git a/chrome/browser/ui/views/user_education/feature_promo_snooze_interactive_uitest.cc b/chrome/browser/ui/views/user_education/feature_promo_snooze_interactive_uitest.cc
index d048fea7..74fa032 100644
--- a/chrome/browser/ui/views/user_education/feature_promo_snooze_interactive_uitest.cc
+++ b/chrome/browser/ui/views/user_education/feature_promo_snooze_interactive_uitest.cc
@@ -83,10 +83,7 @@
 
   void CheckSnoozePrefs(const base::Feature& iph_feature,
                         bool is_dismissed,
-                        int show_count,
                         int snooze_count,
-                        base::Time last_show_time_min,
-                        base::Time last_show_time_max,
                         base::Time last_snooze_time_min,
                         base::Time last_snooze_time_max) {
     auto data = snooze_service_->ReadSnoozeData(iph_feature);
@@ -95,15 +92,8 @@
     ASSERT_TRUE(data.has_value());
 
     EXPECT_EQ(data->is_dismissed, is_dismissed);
-    EXPECT_EQ(data->show_count, show_count);
     EXPECT_EQ(data->snooze_count, snooze_count);
 
-    // last_show_time is only meaningful if a show has occurred.
-    if (data->show_count > 0) {
-      EXPECT_GE(data->last_show_time, last_show_time_min);
-      EXPECT_LE(data->last_show_time, last_show_time_max);
-    }
-
     // last_snooze_time is only meaningful if a snooze has occurred.
     if (data->snooze_count > 0) {
       EXPECT_GE(data->last_snooze_time, last_snooze_time_min);
@@ -113,16 +103,12 @@
 
   void SetSnoozePrefs(const base::Feature& iph_feature,
                       bool is_dismissed,
-                      int show_count,
                       int snooze_count,
-                      base::Time last_show_time,
                       base::Time last_snooze_time,
                       base::TimeDelta last_snooze_duration) {
     FeaturePromoSnoozeService::SnoozeData data;
     data.is_dismissed = is_dismissed;
-    data.show_count = show_count;
     data.snooze_count = snooze_count;
-    data.last_show_time = last_show_time;
     data.last_snooze_time = last_snooze_time;
     data.last_snooze_duration = last_snooze_duration;
     snooze_service_->SaveSnoozeData(iph_feature, data);
@@ -202,27 +188,17 @@
 
 IN_PROC_BROWSER_TEST_F(FeaturePromoSnoozeInteractiveTest,
                        DismissDoesNotSnooze) {
-  base::Time show_time_min = base::Time::Now();
   ASSERT_NO_FATAL_FAILURE(AttemptTabGroupsIPH(true));
-  base::Time show_time_max = base::Time::Now();
 
   FeaturePromoBubbleView* promo = promo_controller_->promo_bubble_for_testing();
   ClickButton(GetDismissButtonForTesting(promo));
   CheckSnoozePrefs(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature,
-                   /* is_dismiss */ true,
-                   /* show_count */ 1,
-                   /* snooze_count */ 0,
-                   /* last_show_time_min */ show_time_min,
-                   /* last_show_time_max */ show_time_max,
-                   /* last_snooze_time_min */ base::Time(),
-                   /* last_snooze_time_max */ base::Time());
+                   true, 0, base::Time(), base::Time());
 }
 
 IN_PROC_BROWSER_TEST_F(FeaturePromoSnoozeInteractiveTest,
                        SnoozeSetsCorrectTime) {
-  base::Time show_time_min = base::Time::Now();
   ASSERT_NO_FATAL_FAILURE(AttemptTabGroupsIPH(true));
-  base::Time show_time_max = base::Time::Now();
 
   FeaturePromoBubbleView* promo = promo_controller_->promo_bubble_for_testing();
 
@@ -231,31 +207,17 @@
   base::Time snooze_time_max = base::Time::Now();
 
   CheckSnoozePrefs(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature,
-                   /* is_dismiss */ false,
-                   /* show_count */ 1,
-                   /* snooze_count */ 1,
-                   /* last_show_time_min */ show_time_min,
-                   /* last_show_time_max */ show_time_max,
-                   /* last_snooze_time_min */ snooze_time_min,
-                   /* last_snooze_time_max */ snooze_time_max);
+                   false, 1, snooze_time_min, snooze_time_max);
 }
 
 IN_PROC_BROWSER_TEST_F(FeaturePromoSnoozeInteractiveTest, CanReSnooze) {
   // Simulate the user snoozing the IPH.
   base::TimeDelta snooze_duration = base::TimeDelta::FromHours(26);
   base::Time snooze_time = base::Time::Now() - snooze_duration;
-  base::Time show_time = snooze_time - base::TimeDelta::FromSeconds(1);
-  SetSnoozePrefs(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature,
-                 /* is_dismiss */ false,
-                 /* show_count */ 1,
-                 /* snooze_count */ 1,
-                 /* last_show_time */ show_time,
-                 /* last_snooze_time */ snooze_time,
-                 /* last_snooze_duration */ snooze_duration);
+  SetSnoozePrefs(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature, false,
+                 1, snooze_time, snooze_duration);
 
-  base::Time show_time_min = base::Time::Now();
   ASSERT_NO_FATAL_FAILURE(AttemptTabGroupsIPH(true));
-  base::Time show_time_max = base::Time::Now();
 
   FeaturePromoBubbleView* promo = promo_controller_->promo_bubble_for_testing();
 
@@ -264,25 +226,14 @@
   base::Time snooze_time_max = base::Time::Now();
 
   CheckSnoozePrefs(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature,
-                   /* is_dismiss */ false,
-                   /* show_count */ 2,
-                   /* snooze_count */ 2,
-                   /* last_show_time_min */ show_time_min,
-                   /* last_show_time_max */ show_time_max,
-                   /* last_snooze_time_min */ snooze_time_min,
-                   /* last_snooze_time_max */ snooze_time_max);
+                   false, 2, snooze_time_min, snooze_time_max);
 }
 
 IN_PROC_BROWSER_TEST_F(FeaturePromoSnoozeInteractiveTest,
                        DoesNotShowIfDismissed) {
   // Simulate the user dismissing the IPH.
-  SetSnoozePrefs(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature,
-                 /* is_dismiss */ true,
-                 /* show_count */ 1,
-                 /* snooze_count */ 0,
-                 /* last_show_time */ base::Time(),
-                 /* last_snooze_time */ base::Time(),
-                 /* last_snooze_duration */ base::TimeDelta());
+  SetSnoozePrefs(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature, true,
+                 0, base::Time(), base::TimeDelta());
 
   AttemptTabGroupsIPH(false);
 }
@@ -292,52 +243,29 @@
   // Simulate a very recent snooze.
   base::TimeDelta snooze_duration = base::TimeDelta::FromHours(26);
   base::Time snooze_time = base::Time::Now();
-  base::Time show_time = snooze_time - base::TimeDelta::FromSeconds(1);
-  SetSnoozePrefs(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature,
-                 /* is_dismiss */ false,
-                 /* show_count */ 1,
-                 /* snooze_count */ 1,
-                 /* last_show_time */ show_time,
-                 /* last_snooze_time */ snooze_time,
-                 /* last_snooze_duration */ snooze_duration);
+  SetSnoozePrefs(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature, false,
+                 1, snooze_time, snooze_duration);
 
   AttemptTabGroupsIPH(false);
 }
 
 IN_PROC_BROWSER_TEST_F(FeaturePromoSnoozeInteractiveTest,
-                       CloseBubbleSetsPrefs) {
-  base::Time show_time_min = base::Time::Now();
+                       CloseBubbleSetsNoPrefs) {
   ASSERT_NO_FATAL_FAILURE(AttemptTabGroupsIPH(true));
-  base::Time show_time_max = base::Time::Now();
 
   promo_controller_->CloseBubble(
       feature_engagement::kIPHDesktopTabGroupsNewGroupFeature);
-
-  CheckSnoozePrefs(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature,
-                   /* is_dismiss */ false,
-                   /* show_count */ 1,
-                   /* snooze_count */ 0,
-                   /* last_show_time_min */ show_time_min,
-                   /* last_show_time_max */ show_time_max,
-                   /* last_snooze_time_min */ base::Time(),
-                   /* last_snooze_time_max */ base::Time());
+  EXPECT_FALSE(
+      HasSnoozePrefs(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature));
 }
 
 IN_PROC_BROWSER_TEST_F(FeaturePromoSnoozeInteractiveTest,
-                       WidgetCloseSetsPrefs) {
-  base::Time show_time_min = base::Time::Now();
+                       WidgetCloseSetsNoPrefs) {
   ASSERT_NO_FATAL_FAILURE(AttemptTabGroupsIPH(true));
-  base::Time show_time_max = base::Time::Now();
 
   FeaturePromoBubbleView* promo = promo_controller_->promo_bubble_for_testing();
   promo->GetWidget()->CloseWithReason(
       views::Widget::ClosedReason::kEscKeyPressed);
-  CheckSnoozePrefs(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature,
-                   /* is_dismiss */ false,
-                   /* show_count */ 1,
-                   /* snooze_count */ 0,
-                   /* last_show_time_min */ show_time_min,
-                   /* last_show_time_max */ show_time_max,
-                   /* last_snooze_time_min */ base::Time(),
-                   /* last_snooze_time_max */ base::Time());
+  EXPECT_FALSE(
+      HasSnoozePrefs(feature_engagement::kIPHDesktopTabGroupsNewGroupFeature));
 }
diff --git a/chrome/browser/ui/webui/device_log_ui.cc b/chrome/browser/ui/webui/device_log_ui.cc
index ef93850..d84db3c 100644
--- a/chrome/browser/ui/webui/device_log_ui.cc
+++ b/chrome/browser/ui/webui/device_log_ui.cc
@@ -34,21 +34,21 @@
   // WebUIMessageHandler implementation.
   void RegisterMessages() override {
     web_ui()->RegisterMessageCallback(
-        "DeviceLog.getLog",
-        base::BindRepeating(&DeviceLogMessageHandler::GetLog,
-                            base::Unretained(this)));
+        "getLog", base::BindRepeating(&DeviceLogMessageHandler::GetLog,
+                                      base::Unretained(this)));
     web_ui()->RegisterMessageCallback(
-        "DeviceLog.clearLog",
-        base::BindRepeating(&DeviceLogMessageHandler::ClearLog,
-                            base::Unretained(this)));
+        "clearLog", base::BindRepeating(&DeviceLogMessageHandler::ClearLog,
+                                        base::Unretained(this)));
   }
 
  private:
-  void GetLog(const base::ListValue* value) const {
+  void GetLog(const base::ListValue* value) {
+    AllowJavascript();
+    std::string callback_id = value->GetList()[0].GetString();
     base::Value data(device_event_log::GetAsString(
         device_event_log::NEWEST_FIRST, "json", "",
         device_event_log::LOG_LEVEL_DEBUG, 0));
-    web_ui()->CallJavascriptFunctionUnsafe("DeviceLogUI.getLogCallback", data);
+    ResolveJavascriptCallback(base::Value(callback_id), data);
   }
 
   void ClearLog(const base::ListValue* value) const {
diff --git a/chrome/browser/ui/webui/feedback/child_web_dialog.cc b/chrome/browser/ui/webui/feedback/child_web_dialog.cc
new file mode 100644
index 0000000..40998bd
--- /dev/null
+++ b/chrome/browser/ui/webui/feedback/child_web_dialog.cc
@@ -0,0 +1,95 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/feedback/child_web_dialog.h"
+
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser_dialogs.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/widget/widget.h"
+
+using content::WebContents;
+using content::WebUIMessageHandler;
+
+namespace {
+// default minimum size of the child dialog
+constexpr gfx::Size kMinSize{400, 120};
+}  // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+// ChildWebDialog, public:
+
+ChildWebDialog::ChildWebDialog(views::Widget* parent_widget,
+                               const GURL& url,
+                               const std::u16string& title,
+                               ui::ModalType modal_type,
+                               int dialog_width,
+                               int dialog_height,
+                               bool can_resize,
+                               bool can_minimize)
+    : parent_widget_(parent_widget),
+      title_(title),
+      url_(url),
+      modal_type_(modal_type),
+      dialog_width_(dialog_width),
+      dialog_height_(dialog_height) {
+  set_can_resize(can_resize);
+  set_can_minimize(can_minimize);
+}
+
+ChildWebDialog::~ChildWebDialog() = default;
+
+void ChildWebDialog::Show() {
+  chrome::ShowWebDialog(parent_widget_->GetNativeView(),
+                        ProfileManager::GetActiveUserProfile(), this);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ChildWebDialog, protected:
+
+bool ChildWebDialog::CanMaximizeDialog() const {
+  return true;
+}
+
+ui::ModalType ChildWebDialog::GetDialogModalType() const {
+  return modal_type_;
+}
+
+std::u16string ChildWebDialog::GetDialogTitle() const {
+  return title_;
+}
+
+GURL ChildWebDialog::GetDialogContentURL() const {
+  return url_;
+}
+
+void ChildWebDialog::GetWebUIMessageHandlers(
+    std::vector<WebUIMessageHandler*>* handlers) const {}
+
+void ChildWebDialog::GetDialogSize(gfx::Size* size) const {
+  size->SetSize(dialog_width_, dialog_height_);
+}
+
+void ChildWebDialog::GetMinimumDialogSize(gfx::Size* size) const {
+  *size = kMinSize;
+}
+
+std::string ChildWebDialog::GetDialogArgs() const {
+  return std::string();
+}
+
+void ChildWebDialog::OnDialogClosed(const std::string& json_retval) {
+  delete this;
+}
+
+void ChildWebDialog::OnCloseContents(WebContents* source,
+                                     bool* out_close_dialog) {
+  *out_close_dialog = true;
+}
+
+bool ChildWebDialog::ShouldShowDialogTitle() const {
+  return true;
+}
diff --git a/chrome/browser/ui/webui/feedback/child_web_dialog.h b/chrome/browser/ui/webui/feedback/child_web_dialog.h
new file mode 100644
index 0000000..06f73682
--- /dev/null
+++ b/chrome/browser/ui/webui/feedback/child_web_dialog.h
@@ -0,0 +1,63 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_FEEDBACK_CHILD_WEB_DIALOG_H_
+#define CHROME_BROWSER_UI_WEBUI_FEEDBACK_CHILD_WEB_DIALOG_H_
+
+#include <string>
+#include <vector>
+
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/web_dialogs/web_dialog_delegate.h"
+#include "url/gurl.h"
+
+namespace views {
+class Widget;
+}
+
+// Launches a child web dialog with specified URL and title.
+class ChildWebDialog : public ui::WebDialogDelegate {
+ public:
+  ChildWebDialog(views::Widget* parent_widget,
+                 const GURL& url,
+                 const std::u16string& title,
+                 ui::ModalType modal_type = ui::MODAL_TYPE_WINDOW,
+                 int dialog_width = 640,
+                 int dialog_height = 400,
+                 bool can_resize = true,
+                 bool can_minimize = false);
+  ChildWebDialog(const ChildWebDialog&) = delete;
+  ChildWebDialog& operator=(const ChildWebDialog&) = delete;
+  ~ChildWebDialog() override;
+
+  void Show();
+
+ protected:
+  // ui::WebDialogDelegate implementation.
+  bool CanMaximizeDialog() const override;
+  std::string GetDialogArgs() const override;
+  GURL GetDialogContentURL() const override;
+  ui::ModalType GetDialogModalType() const override;
+  void GetDialogSize(gfx::Size* size) const override;
+  std::u16string GetDialogTitle() const override;
+  void GetMinimumDialogSize(gfx::Size* size) const override;
+  void GetWebUIMessageHandlers(
+      std::vector<content::WebUIMessageHandler*>* handlers) const override;
+  // NOTE: This function deletes this object at the end.
+  void OnDialogClosed(const std::string& json_retval) override;
+  void OnCloseContents(content::WebContents* source,
+                       bool* out_close_dialog) override;
+  bool ShouldShowDialogTitle() const override;
+
+ private:
+  views::Widget* parent_widget_;
+  const std::u16string title_;
+  const GURL url_;
+  const ui::ModalType modal_type_;
+  const int dialog_width_;
+  const int dialog_height_;
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_FEEDBACK_CHILD_WEB_DIALOG_H_
diff --git a/chrome/browser/ui/webui/feedback/feedback_dialog.cc b/chrome/browser/ui/webui/feedback/feedback_dialog.cc
index 8f443e5..f2ef3d9 100644
--- a/chrome/browser/ui/webui/feedback/feedback_dialog.cc
+++ b/chrome/browser/ui/webui/feedback/feedback_dialog.cc
@@ -114,6 +114,10 @@
     this->widget_->Show();
 }
 
+views::Widget* FeedbackDialog::GetWidget() const {
+  return this->widget_;
+}
+
 void FeedbackDialog::RequestMediaAccessPermission(
     content::WebContents* web_contents,
     const content::MediaStreamRequest& request,
diff --git a/chrome/browser/ui/webui/feedback/feedback_dialog.h b/chrome/browser/ui/webui/feedback/feedback_dialog.h
index d1e7835..b4fb89e 100644
--- a/chrome/browser/ui/webui/feedback/feedback_dialog.h
+++ b/chrome/browser/ui/webui/feedback/feedback_dialog.h
@@ -27,6 +27,7 @@
 
   // Show this web dialog
   void Show() const;
+  views::Widget* GetWidget() const;
 
  private:
   explicit FeedbackDialog(
diff --git a/chrome/browser/ui/webui/feedback/feedback_handler.cc b/chrome/browser/ui/webui/feedback/feedback_handler.cc
index 4261414..9a42e57 100644
--- a/chrome/browser/ui/webui/feedback/feedback_handler.cc
+++ b/chrome/browser/ui/webui/feedback/feedback_handler.cc
@@ -5,23 +5,99 @@
 #include "chrome/browser/ui/webui/feedback/feedback_handler.h"
 
 #include <memory>
+#include <string>
 
 #include "base/bind.h"
+#include "base/strings/strcat.h"
 #include "base/values.h"
+#include "chrome/browser/ui/webui/feedback/child_web_dialog.h"
 #include "chrome/browser/ui/webui/feedback/feedback_dialog.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/common/url_constants.h"
 #include "extensions/common/api/feedback_private.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/widget/widget.h"
+#include "url/gurl.h"
+
+namespace {
+
+void ShowChildPage(const FeedbackDialog* dialog,
+                   const GURL& url,
+                   const std::u16string& title,
+                   int dialog_width = 640,
+                   int dialog_height = 400,
+                   bool can_resize = true,
+                   bool can_minimize = true) {
+  bool isParentModal = dialog->GetWidget()->IsModal();
+  // when the dialog is closed, it will delete itself
+  ChildWebDialog* child_dialog = new ChildWebDialog(
+      dialog->GetWidget(), url, title,
+      /*modal_type=*/
+      isParentModal ? ui::MODAL_TYPE_WINDOW : ui::MODAL_TYPE_NONE, dialog_width,
+      dialog_height, can_resize, can_minimize);
+
+  child_dialog->Show();
+}
+
+GURL ChildPageURL(const std::string& child_page) {
+  return GURL(base::StrCat({chrome::kChromeUIFeedbackURL, child_page}));
+}
+}  // namespace
 
 FeedbackHandler::FeedbackHandler(const FeedbackDialog* dialog)
     : dialog_(dialog) {}
 
 FeedbackHandler::~FeedbackHandler() = default;
 
-void FeedbackHandler::HandleShowDialog(const base::ListValue* args) {
-  dialog_->Show();
-}
-
 void FeedbackHandler::RegisterMessages() {
   web_ui()->RegisterMessageCallback(
       "showDialog", base::BindRepeating(&FeedbackHandler::HandleShowDialog,
                                         base::Unretained(this)));
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+  web_ui()->RegisterMessageCallback(
+      "showAssistantLogsInfo",
+      base::BindRepeating(&FeedbackHandler::HandleShowAssistantLogsInfo,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "showBluetoothLogsInfo",
+      base::BindRepeating(&FeedbackHandler::HandleShowBluetoothLogsInfo,
+                          base::Unretained(this)));
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+  web_ui()->RegisterMessageCallback(
+      "showSystemInfo",
+      base::BindRepeating(&FeedbackHandler::HandleShowSystemInfo,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "showMetrics", base::BindRepeating(&FeedbackHandler::HandleShowMetrics,
+                                         base::Unretained(this)));
+}
+
+void FeedbackHandler::HandleShowDialog(const base::ListValue* args) {
+  dialog_->Show();
+}
+
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+void FeedbackHandler::HandleShowAssistantLogsInfo(const base::ListValue* args) {
+  ShowChildPage(dialog_, ChildPageURL("html/assistant_logs_info.html"),
+                std::u16string(),
+                /*dialog_width=*/400, /*dialog_height=*/120,
+                /*can_resize=*/false, /*can_minimize=*/false);
+}
+void FeedbackHandler::HandleShowBluetoothLogsInfo(const base::ListValue* args) {
+  ShowChildPage(dialog_, ChildPageURL("html/bluetooth_logs_info.html"),
+                std::u16string(),
+                /*dialog_width=*/400, /*dialog_height=*/120,
+                /*can_resize=*/false, /*can_minimize=*/false);
+}
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+
+void FeedbackHandler::HandleShowSystemInfo(const base::ListValue* args) {
+  ShowChildPage(dialog_, ChildPageURL("html/sys_info.html"),
+                l10n_util::GetStringUTF16(IDS_FEEDBACK_SYSINFO_PAGE_TITLE));
+}
+
+void FeedbackHandler::HandleShowMetrics(const base::ListValue* args) {
+  ShowChildPage(dialog_, GURL("chrome://histograms"), std::u16string());
 }
diff --git a/chrome/browser/ui/webui/feedback/feedback_handler.h b/chrome/browser/ui/webui/feedback/feedback_handler.h
index 7fec929..0e131bc 100644
--- a/chrome/browser/ui/webui/feedback/feedback_handler.h
+++ b/chrome/browser/ui/webui/feedback/feedback_handler.h
@@ -25,8 +25,13 @@
   void RegisterMessages() override;
 
  private:
-  // JS message handler for chrome.send("showDialog")
   void HandleShowDialog(const base::ListValue* args);
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+  void HandleShowAssistantLogsInfo(const base::ListValue* args);
+  void HandleShowBluetoothLogsInfo(const base::ListValue* args);
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+  void HandleShowMetrics(const base::ListValue* args);
+  void HandleShowSystemInfo(const base::ListValue* args);
 
   const FeedbackDialog* dialog_;
 };
diff --git a/chrome/browser/ui/webui/memories/memories.mojom b/chrome/browser/ui/webui/memories/memories.mojom
index 7451d63..aee3e02 100644
--- a/chrome/browser/ui/webui/memories/memories.mojom
+++ b/chrome/browser/ui/webui/memories/memories.mojom
@@ -27,12 +27,9 @@
   // The MemoriesBrowserProxy singleton calls this when it's first initialized.
   SetPage(pending_remote<Page> page);
 
-  // Returns sample Memories related to |query| for experimentation with a POC.
-  // TODO(crbug.com/1179069): Remove this when real Memories are available.
-  GetSampleMemories(string query) => (MemoriesResult result);
-
-  // Return memories related to visit history.
-  GetMemories() => (MemoriesResult memories);
+  // Return memories related to |query| created from the user visit history.
+  // Note: Returns mock memories in non-official builds.
+  QueryMemories(string query) => (MemoriesResult result);
 };
 
 // WebUI-side handler for requests from the browser.
diff --git a/chrome/browser/ui/webui/memories/memories_handler.cc b/chrome/browser/ui/webui/memories/memories_handler.cc
index ca1e9e0..1c76725 100644
--- a/chrome/browser/ui/webui/memories/memories_handler.cc
+++ b/chrome/browser/ui/webui/memories/memories_handler.cc
@@ -15,7 +15,7 @@
 #include "content/public/browser/web_contents.h"
 #include "url/gurl.h"
 
-#if !defined(OFFICIAL_BUILD)
+#if !defined(CHROME_BRANDED)
 #include "base/bind.h"
 #include "base/containers/contains.h"
 #include "base/i18n/case_conversion.h"
@@ -69,22 +69,19 @@
   page_.Bind(std::move(pending_page));
 }
 
-void MemoriesHandler::GetSampleMemories(const std::string& query,
-                                        MemoriesResultCallback callback) {
-#if defined(OFFICIAL_BUILD)
-  auto memories_result_mojom = memories::mojom::MemoriesResult::New();
-  std::move(callback).Run(std::move(memories_result_mojom));
-  return;
-#else
-  // If the query is empty and a remote model endpoint is set, then ask the
-  // MemoriesService for memories. The MemoriesService doesn't yet support
-  // filtering memories by query or an on-client clustering, so if either the
-  // query is non-empty or the endpoint is not set, fallback to sample memories
-  // from history.
-  if (query.empty() && memories::RemoteModelEndpoint().is_valid()) {
-    GetMemories(std::move(callback));
+void MemoriesHandler::QueryMemories(const std::string& query,
+                                    QueryMemoriesCallback callback) {
+  auto termination_callback = base::BindOnce(
+      &MemoriesHandler::OnMemoriesQueryResults, weak_ptr_factory_.GetWeakPtr(),
+      std::move(callback), query);
+  if (memories::RemoteModelEndpoint().is_valid()) {
+    auto* memory_service =
+        MemoriesServiceFactory::GetForBrowserContext(profile_);
+    memory_service->QueryMemories(query, std::move(termination_callback));
   } else {
-    // Query HistoryService for URLs containing |query|.
+#if defined(CHROME_BRANDED)
+    std::move(callback).Run(memories::mojom::MemoriesResult::New());
+#else
     history::HistoryService* history_service =
         HistoryServiceFactory::GetForProfile(
             profile_, ServiceAccessType::EXPLICIT_ACCESS);
@@ -94,24 +91,33 @@
     history_service->QueryHistory(
         base::UTF8ToUTF16(query), query_options,
         base::BindOnce(&MemoriesHandler::OnHistoryQueryResults,
-                       weak_ptr_factory_.GetWeakPtr(), query,
-                       std::move(callback)),
+                       weak_ptr_factory_.GetWeakPtr(),
+                       std::move(termination_callback)),
         &history_task_tracker_);
+#endif
   }
 }
 
-void MemoriesHandler::OnHistoryQueryResults(const std::string& query,
-                                            MemoriesResultCallback callback,
-                                            history::QueryResults results) {
-  auto memories_result_mojom = memories::mojom::MemoriesResult::New();
+void MemoriesHandler::OnMemoriesQueryResults(
+    QueryMemoriesCallback callback,
+    const std::string& query,
+    std::vector<memories::mojom::MemoryPtr> memory_mojoms) {
+  auto result_mojom = memories::mojom::MemoriesResult::New();
+  result_mojom->title = base::UTF8ToUTF16(query);
+  result_mojom->thumbnail_url = GetRandomlySizedThumbnailUrl();
+  result_mojom->memories = std::move(memory_mojoms);
+  std::move(callback).Run(std::move(result_mojom));
+}
+
+#if !defined(CHROME_BRANDED)
+void MemoriesHandler::OnHistoryQueryResults(
+    MemoriesQueryResultsCallback callback,
+    history::QueryResults results) {
   if (results.empty()) {
-    std::move(callback).Run(std::move(memories_result_mojom));
+    std::move(callback).Run({});
     return;
   }
 
-  memories_result_mojom->title = base::UTF8ToUTF16(query);
-  memories_result_mojom->thumbnail_url = GetRandomlySizedThumbnailUrl();
-
   auto memory_mojom = memories::mojom::Memory::New();
   memory_mojom->id = base::UnguessableToken::Create();
 
@@ -260,17 +266,8 @@
     }
   }
 
-  memories_result_mojom->memories.push_back(std::move(memory_mojom));
-  std::move(callback).Run(std::move(memories_result_mojom));
+  std::vector<memories::mojom::MemoryPtr> memory_mojoms;
+  memory_mojoms.push_back(std::move(memory_mojom));
+  std::move(callback).Run(std::move(memory_mojoms));
+}
 #endif
-}
-
-void MemoriesHandler::GetMemories(MemoriesResultCallback callback) {
-  auto* memory_service = MemoriesServiceFactory::GetForBrowserContext(profile_);
-  memory_service->GetMemories(base::BindOnce([](memories::Memories memories) {
-                                auto result =
-                                    memories::mojom::MemoriesResult::New();
-                                result->memories = std::move(memories);
-                                return result;
-                              }).Then(std::move(callback)));
-}
diff --git a/chrome/browser/ui/webui/memories/memories_handler.h b/chrome/browser/ui/webui/memories/memories_handler.h
index ed4cd8e2..0f811bb4 100644
--- a/chrome/browser/ui/webui/memories/memories_handler.h
+++ b/chrome/browser/ui/webui/memories/memories_handler.h
@@ -10,7 +10,6 @@
 #include "base/callback.h"
 #include "chrome/browser/ui/webui/memories/memories.mojom.h"
 #include "components/history_clusters/core/memories.mojom.h"
-#include "components/history_clusters/core/memories_remote_model_helper.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
@@ -48,18 +47,19 @@
   // memories::mojom::PageHandler:
   void SetPage(
       mojo::PendingRemote<memories::mojom::Page> pending_page) override;
-
-  using MemoriesResultCallback =
-      base::OnceCallback<void(memories::mojom::MemoriesResultPtr)>;
-  void GetSampleMemories(const std::string& query,
-                         MemoriesResultCallback callback) override;
-
-  void GetMemories(MemoriesResultCallback callback) override;
+  void QueryMemories(const std::string& query,
+                     QueryMemoriesCallback callback) override;
 
  private:
+  void OnMemoriesQueryResults(
+      QueryMemoriesCallback callback,
+      const std::string& query,
+      std::vector<memories::mojom::MemoryPtr> memory_mojoms);
+
 #if !defined(OFFICIAL_BUILD)
-  void OnHistoryQueryResults(const std::string& query,
-                             MemoriesResultCallback callback,
+  using MemoriesQueryResultsCallback =
+      base::OnceCallback<void(std::vector<memories::mojom::MemoryPtr>)>;
+  void OnHistoryQueryResults(MemoriesQueryResultsCallback callback,
                              history::QueryResults results);
 #endif
 
diff --git a/chrome/browser/ui/webui/nearby_internals/nearby_internals_prefs_handler.cc b/chrome/browser/ui/webui/nearby_internals/nearby_internals_prefs_handler.cc
new file mode 100644
index 0000000..23e35bb
--- /dev/null
+++ b/chrome/browser/ui/webui/nearby_internals/nearby_internals_prefs_handler.cc
@@ -0,0 +1,48 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/nearby_internals/nearby_internals_prefs_handler.h"
+#include "base/bind.h"
+#include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h"
+#include "chrome/browser/nearby_sharing/logging/logging.h"
+#include "chrome/browser/profiles/profile.h"
+
+namespace {
+
+const char kNearbySharingPrefPrefix[] = "nearby_sharing";
+
+}  // namespace
+
+NearbyInternalsPrefsHandler::NearbyInternalsPrefsHandler(
+    content::BrowserContext* context) {
+  Profile* profile = Profile::FromBrowserContext(context);
+  pref_service_ = profile->GetPrefs();
+}
+
+NearbyInternalsPrefsHandler::~NearbyInternalsPrefsHandler() = default;
+
+void NearbyInternalsPrefsHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "clearNearbyPrefs",
+      base::BindRepeating(&NearbyInternalsPrefsHandler::HandleClearNearbyPrefs,
+                          base::Unretained(this)));
+}
+
+void NearbyInternalsPrefsHandler::OnJavascriptAllowed() {}
+
+void NearbyInternalsPrefsHandler::OnJavascriptDisallowed() {}
+
+void NearbyInternalsPrefsHandler::HandleClearNearbyPrefs(
+    const base::ListValue* args) {
+  // Turn Nearby feature off.
+  pref_service_->SetBoolean(prefs::kNearbySharingEnabledPrefName, false);
+
+  // Clear all Nearby related prefs.
+  pref_service_->ClearPrefsWithPrefixSilently(kNearbySharingPrefPrefix);
+
+  // Add log message so users who trigger the Clear Pref button on
+  // chrome://nearby-internals know that the Nearby prefs have been cleared.
+  NS_LOG(INFO)
+      << "Nearby Share has been disabled and Nearby prefs have been cleared.";
+}
diff --git a/chrome/browser/ui/webui/nearby_internals/nearby_internals_prefs_handler.h b/chrome/browser/ui/webui/nearby_internals/nearby_internals_prefs_handler.h
new file mode 100644
index 0000000..3aae5e2
--- /dev/null
+++ b/chrome/browser/ui/webui/nearby_internals/nearby_internals_prefs_handler.h
@@ -0,0 +1,40 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef CHROME_BROWSER_UI_WEBUI_NEARBY_INTERNALS_NEARBY_INTERNALS_PREFS_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_NEARBY_INTERNALS_NEARBY_INTERNALS_PREFS_HANDLER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+// WebUIMessageHandler for Nearby Prefs to allow users to Clear Prefs from the
+// chrome://nearby-internals logging tab.
+class NearbyInternalsPrefsHandler : public content::WebUIMessageHandler {
+ public:
+  explicit NearbyInternalsPrefsHandler(content::BrowserContext* context);
+  NearbyInternalsPrefsHandler(const NearbyInternalsPrefsHandler&) = delete;
+  NearbyInternalsPrefsHandler& operator=(const NearbyInternalsPrefsHandler&) =
+      delete;
+  ~NearbyInternalsPrefsHandler() override;
+
+  // content::WebUIMessageHandler
+  void RegisterMessages() override;
+  void OnJavascriptAllowed() override;
+  void OnJavascriptDisallowed() override;
+
+ private:
+  // Message handler callback that clears Nearby prefs in order to put the user
+  // back into a state of before they have touched the feature.
+  void HandleClearNearbyPrefs(const base::ListValue* args);
+
+  PrefService* pref_service_ = nullptr;
+
+  base::WeakPtrFactory<NearbyInternalsPrefsHandler> weak_ptr_factory_{this};
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_NEARBY_INTERNALS_NEARBY_INTERNALS_PREFS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/nearby_internals/nearby_internals_ui.cc b/chrome/browser/ui/webui/nearby_internals/nearby_internals_ui.cc
index 5da4c436..ad5ef685 100644
--- a/chrome/browser/ui/webui/nearby_internals/nearby_internals_ui.cc
+++ b/chrome/browser/ui/webui/nearby_internals/nearby_internals_ui.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/ui/webui/nearby_internals/nearby_internals_contact_handler.h"
 #include "chrome/browser/ui/webui/nearby_internals/nearby_internals_http_handler.h"
 #include "chrome/browser/ui/webui/nearby_internals/nearby_internals_logs_handler.h"
+#include "chrome/browser/ui/webui/nearby_internals/nearby_internals_prefs_handler.h"
 #include "chrome/browser/ui/webui/nearby_internals/nearby_internals_ui_trigger_handler.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/webui_url_constants.h"
@@ -49,6 +50,8 @@
   web_ui->AddMessageHandler(
       std::make_unique<NearbyInternalsHttpHandler>(context));
   web_ui->AddMessageHandler(
+      std::make_unique<NearbyInternalsPrefsHandler>(context));
+  web_ui->AddMessageHandler(
       std::make_unique<NearbyInternalsUiTriggerHandler>(context));
 }
 
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 3a95d34..b02d0b4 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1618228674-d1a41e0dc1567eec25d78ff5cc9b93c446a0d10e.profdata
+chrome-mac-master-1618250085-ffa805180ec9d754cf5c51687ddbda93b14e3cf0.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 9aa1c2f..c2339ac 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1618217937-4c8c8e157b8445d00f932d7fb939b1b4ced4c414.profdata
+chrome-win32-master-1618239101-c343067f4fe42b5b9cbeed20dc8eca6f73065154.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index fc05037e..b71e497e 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1618228674-2c141039227ed78d05ea16cf41fc55a7decb0e10.profdata
+chrome-win64-master-1618239101-e7b61466f28cf062475da83a36fc060169831deb.profdata
diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc
index b040408..99a80dc4 100644
--- a/chrome/installer/setup/install_worker.cc
+++ b/chrome/installer/setup/install_worker.cc
@@ -7,10 +7,7 @@
 
 #include "chrome/installer/setup/install_worker.h"
 
-#include "base/win/atl.h"
-
 #include <oaidl.h>
-#include <sddl.h>
 #include <shlobj.h>
 #include <stddef.h>
 #include <stdint.h>
@@ -74,6 +71,7 @@
 constexpr wchar_t kLpacChromeInstallFilesCapabilitySid[] =
     L"S-1-15-3-1024-2302894289-466761758-1166120688-1039016420-2430351297-"
     L"4240214049-4028510897-3317428798";
+constexpr wchar_t kAuthenticatedUsersSid[] = L"AU";
 
 void AddInstallerCopyTasks(const InstallParams& install_params,
                            WorkItemList* install_list) {
@@ -293,93 +291,6 @@
       ->set_best_effort(true);
 }
 
-// Adds an ACE from a trustee SID, access mask and flags to an existing DACL.
-// If the exact ACE already exists then the DACL is not modified and true is
-// returned.
-bool AddAceToDacl(const ATL::CSid& trustee,
-                  ACCESS_MASK access_mask,
-                  BYTE ace_flags,
-                  ATL::CDacl* dacl) {
-  // Check if the requested access already exists and return if so.
-  for (UINT i = 0; i < dacl->GetAceCount(); ++i) {
-    ATL::CSid sid;
-    ACCESS_MASK mask = 0;
-    BYTE type = 0;
-    BYTE flags = 0;
-    dacl->GetAclEntry(i, &sid, &mask, &type, &flags);
-    if (sid == trustee && type == ACCESS_ALLOWED_ACE_TYPE &&
-        (flags & ace_flags) == ace_flags &&
-        (mask & access_mask) == access_mask) {
-      return true;
-    }
-  }
-
-  // Add the new access to the DACL.
-  return dacl->AddAllowedAce(trustee, access_mask, ace_flags);
-}
-
-// Add to the ACL of an object on disk. This follows the method from MSDN:
-// https://msdn.microsoft.com/en-us/library/windows/desktop/aa379283.aspx
-// This is done using explicit flags rather than the "security string" format
-// because strings do not necessarily read what is written which makes it
-// difficult to de-dup. Working with the binary format is always exact and the
-// system libraries will properly ignore duplicate ACL entries.
-bool AddAclToPath(const base::FilePath& path,
-                  const std::vector<ATL::CSid>& trustees,
-                  ACCESS_MASK access_mask,
-                  BYTE ace_flags) {
-  DCHECK(!path.empty());
-
-  // Get the existing DACL.
-  ATL::CDacl dacl;
-  if (!ATL::AtlGetDacl(path.value().c_str(), SE_FILE_OBJECT, &dacl)) {
-    DPLOG(ERROR) << "Failed getting DACL for path \"" << path.value() << "\"";
-    return false;
-  }
-
-  for (const auto& trustee : trustees) {
-    DCHECK(trustee.IsValid());
-    if (!AddAceToDacl(trustee, access_mask, ace_flags, &dacl)) {
-      DPLOG(ERROR) << "Failed adding ACE to DACL for trustee " << trustee.Sid();
-      return false;
-    }
-  }
-
-  // Attach the updated ACL as the object's DACL.
-  if (!ATL::AtlSetDacl(path.value().c_str(), SE_FILE_OBJECT, dacl)) {
-    DPLOG(ERROR) << "Failed setting DACL for path \"" << path.value() << "\"";
-    return false;
-  }
-
-  return true;
-}
-
-bool AddAclToPath(const base::FilePath& path,
-                  const CSid& trustee,
-                  ACCESS_MASK access_mask,
-                  BYTE ace_flags) {
-  std::vector<ATL::CSid> trustees = {trustee};
-  return AddAclToPath(path, trustees, access_mask, ace_flags);
-}
-
-bool AddAclToPath(const base::FilePath& path,
-                  const std::vector<const wchar_t*>& trustees,
-                  ACCESS_MASK access_mask,
-                  BYTE ace_flags) {
-  std::vector<ATL::CSid> converted_trustees;
-  for (const wchar_t* trustee : trustees) {
-    PSID sid;
-    if (!::ConvertStringSidToSid(trustee, &sid)) {
-      DPLOG(ERROR) << "Failed to convert SID \"" << trustee << "\"";
-      return false;
-    }
-    converted_trustees.emplace_back(static_cast<SID*>(sid));
-    ::LocalFree(sid);
-  }
-
-  return AddAclToPath(path, converted_trustees, access_mask, ace_flags);
-}
-
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 // Adds work items to register the Elevation Service with Windows. Only for
 // system level installs.
@@ -796,10 +707,10 @@
             std::vector<const wchar_t*> sids = {
                 kChromeInstallFilesCapabilitySid,
                 kLpacChromeInstallFilesCapabilitySid};
-            bool success_target = AddAclToPath(
+            bool success_target = GrantAccessToPath(
                 target_path, sids, FILE_GENERIC_READ | FILE_GENERIC_EXECUTE,
                 CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
-            bool success_temp = AddAclToPath(
+            bool success_temp = GrantAccessToPath(
                 temp_path, sids, FILE_GENERIC_READ | FILE_GENERIC_EXECUTE,
                 CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
 
@@ -824,8 +735,8 @@
             base::BindOnce(
                 [](const base::FilePath& histogram_storage_dir,
                    const CallbackWorkItem& work_item) {
-                  return AddAclToPath(
-                      histogram_storage_dir, ATL::Sids::AuthenticatedUser(),
+                  return GrantAccessToPath(
+                      histogram_storage_dir, {kAuthenticatedUsersSid},
                       FILE_GENERIC_READ | FILE_DELETE_CHILD,
                       CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
                 },
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index f4bc0a7..ab3b5f1 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -6,7 +6,9 @@
 
 #include "chrome/installer/setup/setup_util.h"
 
+#include <aclapi.h>
 #include <objbase.h>
+#include <sddl.h>
 #include <stddef.h>
 #include <windows.h>
 #include <wtsapi32.h>
@@ -18,6 +20,7 @@
 #include <set>
 #include <string>
 #include <utility>
+#include <vector>
 
 #include "base/base64.h"
 #include "base/bind.h"
@@ -188,6 +191,12 @@
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }
 
+struct LocalFreeDeleter {
+  void operator()(void* ptr) const { ::LocalFree(ptr); }
+};
+
+typedef std::unique_ptr<void, LocalFreeDeleter> LocalFreeUniquePtr;
+
 }  // namespace
 
 const char kUnPackStatusMetricsName[] = "Setup.Install.LzmaUnPackStatus";
@@ -826,4 +835,66 @@
   }
 }
 
+bool GrantAccessToPath(const base::FilePath& path,
+                       const std::vector<const wchar_t*>& sids,
+                       ACCESS_MASK access_mask,
+                       DWORD inheritance) {
+  DCHECK(!path.empty());
+  if (sids.empty())
+    return true;
+
+  std::wstring object_name = path.value();
+  PSECURITY_DESCRIPTOR sd = nullptr;
+  PACL dacl = nullptr;
+
+  // Get the existing DACL.
+  DWORD error = ::GetNamedSecurityInfo(object_name.c_str(), SE_FILE_OBJECT,
+                                       DACL_SECURITY_INFORMATION, nullptr,
+                                       nullptr, &dacl, nullptr, &sd);
+  if (error != ERROR_SUCCESS) {
+    ::SetLastError(error);
+    DPLOG(ERROR) << "Failed getting DACL for path \"" << path.value() << "\"";
+    return false;
+  }
+  LocalFreeUniquePtr sd_ptr(sd);
+
+  std::vector<LocalFreeUniquePtr> sid_lifetime;
+  sid_lifetime.reserve(sids.size());
+  std::vector<EXPLICIT_ACCESS> access_entries(sids.size());
+  auto entries_interator = access_entries.begin();
+  for (const wchar_t* sid : sids) {
+    EXPLICIT_ACCESS& new_access = *entries_interator++;
+    new_access.grfAccessMode = GRANT_ACCESS;
+    new_access.grfAccessPermissions = access_mask;
+    new_access.grfInheritance = inheritance;
+    PSID psid;
+    if (!::ConvertStringSidToSid(sid, &psid))
+      return false;
+    sid_lifetime.emplace_back(psid);
+    ::BuildTrusteeWithSid(&new_access.Trustee, psid);
+  }
+
+  PACL new_dacl = nullptr;
+  error = ::SetEntriesInAcl(access_entries.size(), access_entries.data(), dacl,
+                            &new_dacl);
+  if (error != ERROR_SUCCESS) {
+    ::SetLastError(error);
+    DPLOG(ERROR) << "Failed adding ACEs to DACL for path \"" << path.value()
+                 << "\"";
+    return false;
+  }
+  LocalFreeUniquePtr new_dacl_ptr(new_dacl);
+
+  error = ::SetNamedSecurityInfo(&object_name[0], SE_FILE_OBJECT,
+                                 DACL_SECURITY_INFORMATION, nullptr, nullptr,
+                                 new_dacl, nullptr);
+  if (error != ERROR_SUCCESS) {
+    ::SetLastError(error);
+    DPLOG(ERROR) << "Failed setting DACL for path \"" << path.value() << "\"";
+    return false;
+  }
+
+  return true;
+}
+
 }  // namespace installer
diff --git a/chrome/installer/setup/setup_util.h b/chrome/installer/setup/setup_util.h
index 52368f9..4d35549 100644
--- a/chrome/installer/setup/setup_util.h
+++ b/chrome/installer/setup/setup_util.h
@@ -17,6 +17,7 @@
 
 #include "base/optional.h"
 #include "base/time/time.h"
+#include "base/win/windows_types.h"
 #include "chrome/installer/util/lzma_util.h"
 #include "chrome/installer/util/util_constants.h"
 
@@ -162,6 +163,13 @@
                                    const base::Version& new_version,
                                    WorkItemList* list);
 
+// Adds allowed ACE entries to a file or directory |path| from a list of SIDs
+// with allowed |access_mask| and |inheritance| flags.
+bool GrantAccessToPath(const base::FilePath& path,
+                       const std::vector<const wchar_t*>& sids,
+                       ACCESS_MASK access_mask,
+                       DWORD inheritance);
+
 }  // namespace installer
 
 #endif  // CHROME_INSTALLER_SETUP_SETUP_UTIL_H_
diff --git a/chrome/installer/setup/setup_util_unittest.cc b/chrome/installer/setup/setup_util_unittest.cc
index ee0bd00..0170d19 100644
--- a/chrome/installer/setup/setup_util_unittest.cc
+++ b/chrome/installer/setup/setup_util_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/installer/setup/setup_util_unittest.h"
 
+#include <aclapi.h>
+#include <sddl.h>
 #include <shlobj.h>
 #include <windows.h>
 
@@ -875,4 +877,113 @@
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }
 
+namespace {
+
+constexpr wchar_t kBaseDacl[] = L"D:P(A;;FA;;;WD)";
+constexpr wchar_t kTest1Dacl[] = L"D:PAI(A;;FR;;;AU)(A;;FA;;;WD)";
+constexpr wchar_t kTest2Dacl[] = L"D:PAI(A;;FA;;;BA)(A;;FA;;;AU)(A;;FA;;;WD)";
+
+constexpr wchar_t kBaseDirDacl[] = L"D:P(A;OICI;FA;;;WD)";
+constexpr wchar_t kTest1InheritedDacl[] = L"D:(A;ID;FA;;;WD)";
+constexpr wchar_t kBaseDir2Dacl[] = L"D:PAI(A;OICI;FR;;;AU)(A;OICI;FA;;;WD)";
+constexpr wchar_t kTest2InheritedDacl[] = L"D:AI(A;ID;FR;;;AU)(A;ID;FA;;;WD)";
+
+constexpr wchar_t kNoWriteDacDacl[] = L"D:(D;;WD;;;OW)(A;;FRSD;;;WD)";
+
+constexpr wchar_t kAuthenticatedUsersSid[] = L"AU";
+
+struct LocalFreeDeleter {
+  void operator()(void* ptr) const { ::LocalFree(ptr); }
+};
+
+std::wstring GetFileDacl(const base::FilePath& path) {
+  PSECURITY_DESCRIPTOR sd;
+  if (::GetNamedSecurityInfo(path.value().c_str(), SE_FILE_OBJECT,
+                             DACL_SECURITY_INFORMATION, nullptr, nullptr,
+                             nullptr, nullptr, &sd) != ERROR_SUCCESS) {
+    return std::wstring();
+  }
+  auto sd_ptr = std::unique_ptr<void, LocalFreeDeleter>(sd);
+  LPWSTR sddl;
+  if (!::ConvertSecurityDescriptorToStringSecurityDescriptor(
+          sd, SDDL_REVISION_1, DACL_SECURITY_INFORMATION, &sddl, nullptr)) {
+    return std::wstring();
+  }
+  auto sddl_ptr = std::unique_ptr<void, LocalFreeDeleter>(sddl);
+  return sddl;
+}
+
+bool CreateWithDacl(const base::FilePath& path,
+                    const wchar_t* sddl,
+                    bool directory) {
+  PSECURITY_DESCRIPTOR sd;
+  if (!::ConvertStringSecurityDescriptorToSecurityDescriptor(
+          sddl, SDDL_REVISION_1, &sd, nullptr)) {
+    return false;
+  }
+  auto sd_ptr = std::unique_ptr<void, LocalFreeDeleter>(sd);
+  SECURITY_ATTRIBUTES security_attr = {};
+  security_attr.nLength = sizeof(security_attr);
+  security_attr.lpSecurityDescriptor = sd;
+  if (directory)
+    return !!::CreateDirectory(path.value().c_str(), &security_attr);
+
+  return base::win::ScopedHandle(::CreateFile(path.value().c_str(), GENERIC_ALL,
+                                              0, &security_attr, CREATE_ALWAYS,
+                                              0, nullptr))
+      .IsValid();
+}
+
+}  // namespace
+
+TEST(SetupUtilTest, GrantAccessToPathErrorCase) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path = temp_dir.GetPath().Append(L"test");
+  EXPECT_FALSE(GrantAccessToPath(path, {kAuthenticatedUsersSid},
+                                 FILE_GENERIC_READ, NO_INHERITANCE));
+  ASSERT_TRUE(CreateWithDacl(path, kBaseDacl, false));
+  EXPECT_TRUE(GrantAccessToPath(path, {kAuthenticatedUsersSid},
+                                FILE_GENERIC_READ, NO_INHERITANCE));
+  EXPECT_FALSE(
+      GrantAccessToPath(path, {L"X-1-2-3"}, FILE_GENERIC_READ, NO_INHERITANCE));
+  path = temp_dir.GetPath().Append(L"test_nowritedac");
+  ASSERT_TRUE(CreateWithDacl(path, kNoWriteDacDacl, false));
+  EXPECT_FALSE(GrantAccessToPath(path, {kAuthenticatedUsersSid},
+                                 FILE_GENERIC_READ, NO_INHERITANCE));
+}
+
+TEST(SetupUtilTest, GrantAccessToPathFile) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path = temp_dir.GetPath().Append(L"test");
+  ASSERT_TRUE(CreateWithDacl(path, kBaseDacl, false));
+  EXPECT_EQ(kBaseDacl, GetFileDacl(path));
+  EXPECT_TRUE(GrantAccessToPath(path, {kAuthenticatedUsersSid},
+                                FILE_GENERIC_READ, NO_INHERITANCE));
+  EXPECT_EQ(kTest1Dacl, GetFileDacl(path));
+  EXPECT_TRUE(GrantAccessToPath(path, {L"S-1-5-11", L"BA"}, GENERIC_ALL,
+                                NO_INHERITANCE));
+  EXPECT_EQ(kTest2Dacl, GetFileDacl(path));
+}
+
+TEST(SetupUtilTest, GrantAccessToPathDirectory) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path = temp_dir.GetPath().Append(L"testdir");
+  ASSERT_TRUE(CreateWithDacl(path, kBaseDirDacl, true));
+  EXPECT_EQ(kBaseDirDacl, GetFileDacl(path));
+  base::FilePath file_path = path.Append(L"test");
+  base::File file(file_path,
+                  base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+  ASSERT_TRUE(file.IsValid());
+  file.Close();
+  EXPECT_EQ(kTest1InheritedDacl, GetFileDacl(file_path));
+  EXPECT_TRUE(GrantAccessToPath(path, {kAuthenticatedUsersSid},
+                                FILE_GENERIC_READ,
+                                OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE));
+  EXPECT_EQ(kBaseDir2Dacl, GetFileDacl(path));
+  EXPECT_EQ(kTest2InheritedDacl, GetFileDacl(file_path));
+}
+
 }  // namespace installer
diff --git a/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn b/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn
index 0f87f98..6f86143e 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn
@@ -23,7 +23,8 @@
 js_library("personalization_app_test_utils") {
   deps = [
     ":test_mojo_interface_provider",
-    "//chromeos/components/personalization_app/resources:mojo_interface_provider",
+    "../..:chai_assert",
+    "//chromeos/components/personalization_app/resources/trusted:mojo_interface_provider",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
 }
@@ -39,9 +40,10 @@
 js_library("wallpaper_collections_element_test") {
   deps = [
     ":personalization_app_test_utils",
+    ":test_mojo_interface_provider",
     "../..:chai_assert",
     "../..:test_util.m",
-    "//chromeos/components/personalization_app/resources:wallpaper_collections_element",
+    "//chromeos/components/personalization_app/resources/trusted:wallpaper_collections_element",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
   externs_list = [ "$externs_path/mocha-2.5.js" ]
@@ -50,9 +52,10 @@
 js_library("wallpaper_images_element_test") {
   deps = [
     ":personalization_app_test_utils",
+    ":test_mojo_interface_provider",
     "../..:chai_assert",
     "../..:test_util.m",
-    "//chromeos/components/personalization_app/resources:wallpaper_images_element",
+    "//chromeos/components/personalization_app/resources/trusted:wallpaper_images_element",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
   externs_list = [ "$externs_path/mocha-2.5.js" ]
@@ -62,5 +65,6 @@
   deps = [
     "../..:chai_assert",
     "../..:test_browser_proxy.m",
+    "//chromeos/components/personalization_app/mojom:mojom_js_library_for_compile",
   ]
 }
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_test_utils.js b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_test_utils.js
index 5d3f5aed..14353ab 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_test_utils.js
+++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_test_utils.js
@@ -7,7 +7,7 @@
  * SWA.
  */
 
-import {setWallpaperProviderForTesting} from 'chrome://personalization/mojo_interface_provider.js';
+import {setWallpaperProviderForTesting} from 'chrome://personalization/trusted/mojo_interface_provider.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {TestWallpaperProvider} from './test_mojo_interface_provider.js';
 
diff --git a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_unified_test.js b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_unified_test.js
index 2a9681ae..49d0b0f 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/personalization_app_unified_test.js
+++ b/chrome/test/data/webui/chromeos/personalization_app/personalization_app_unified_test.js
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 import {WallpaperCollectionsTest} from './wallpaper_collections_element_test.js';
 import {WallpaperImagesTest} from './wallpaper_images_element_test.js';
 
diff --git a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.js b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.js
index 6f15d19..be91094 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.js
+++ b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.js
@@ -2,10 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://personalization/personalization_app.js';
-import 'chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-lite.js';
-import 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-lite.js';
-import {WallpaperCollections} from 'chrome://personalization/wallpaper_collections_element.js';
+import {WallpaperCollections} from 'chrome://personalization/trusted/wallpaper_collections_element.js';
 import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
 import {waitAfterNextRender} from '../../test_util.m.js';
 import {baseSetup, initElement} from './personalization_app_test_utils.js';
diff --git a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_images_element_test.js b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_images_element_test.js
index e56275f..0ab73dc8 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_images_element_test.js
+++ b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_images_element_test.js
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://personalization/personalization_app.js';
-import {WallpaperImages} from 'chrome://personalization/wallpaper_images_element.js';
+import {WallpaperImages} from 'chrome://personalization/trusted/wallpaper_images_element.js';
 import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
 import {waitAfterNextRender} from '../../test_util.m.js';
 import {baseSetup, initElement} from './personalization_app_test_utils.js';
diff --git a/chrome/test/data/webui/new_tab_page/modules/module_registry_test.js b/chrome/test/data/webui/new_tab_page/modules/module_registry_test.js
index 29ec0c67..b86a336 100644
--- a/chrome/test/data/webui/new_tab_page/modules/module_registry_test.js
+++ b/chrome/test/data/webui/new_tab_page/modules/module_registry_test.js
@@ -53,16 +53,17 @@
     const bazModule =
         /** @type {!HTMLElement} */ (document.createElement('div'));
     const bazModuleResolver = new PromiseResolver();
-    ModuleRegistry.getInstance().registerModules([
+    const descriptors = [
       new ModuleDescriptor('foo', 'bli', () => Promise.resolve(fooModule)),
       new ModuleDescriptor('bar', 'blu', () => Promise.resolve(null)),
       new ModuleDescriptor('baz', 'bla', () => bazModuleResolver.promise),
       new ModuleDescriptor('buz', 'blo', () => Promise.resolve(fooModule)),
-    ]);
+    ];
     windowProxy.setResultFor('now', 5.0);
 
     // Act.
-    const modulesPromise = ModuleRegistry.getInstance().initializeModules(0);
+    const moduleRegistry = new ModuleRegistry(descriptors);
+    const modulesPromise = moduleRegistry.initializeModules(0);
     callbackRouterRemote.setDisabledModules(false, ['buz']);
     // Wait for first batch of modules.
     await flushTasks();
diff --git a/chromeos/components/personalization_app/personalization_app_ui.cc b/chromeos/components/personalization_app/personalization_app_ui.cc
index 9fc64b63..caf4bbe 100644
--- a/chromeos/components/personalization_app/personalization_app_ui.cc
+++ b/chromeos/components/personalization_app/personalization_app_ui.cc
@@ -4,6 +4,7 @@
 
 #include "chromeos/components/personalization_app/personalization_app_ui.h"
 
+#include "base/strings/string_util.h"
 #include "chromeos/components/personalization_app/personalization_app_ui_delegate.h"
 #include "chromeos/components/personalization_app/personalization_app_url_constants.h"
 #include "chromeos/grit/chromeos_personalization_app_resources.h"
@@ -11,6 +12,7 @@
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui_data_source.h"
+#include "services/network/public/mojom/content_security_policy.mojom-shared.h"
 #include "ui/resources/grit/webui_generated_resources.h"
 #include "ui/webui/mojo_web_ui_controller.h"
 
@@ -18,11 +20,24 @@
 
 namespace {
 
+bool ShouldIncludeResource(const webui::ResourcePath& resource) {
+  return base::StartsWith(resource.path, "trusted") ||
+         base::StartsWith(resource.path, "common") ||
+         resource.id == IDR_CHROMEOS_PERSONALIZATION_APP_ICON_192_PNG;
+}
+
 void AddResources(content::WebUIDataSource* source) {
-  source->AddResourcePath("", IDR_CHROMEOS_PERSONALIZATION_APP_INDEX_HTML);
-  source->AddResourcePaths(
+  source->AddResourcePath("",
+                          IDR_CHROMEOS_PERSONALIZATION_APP_TRUSTED_INDEX_HTML);
+
+  const auto resources =
       base::make_span(kChromeosPersonalizationAppResources,
-                      kChromeosPersonalizationAppResourcesSize));
+                      kChromeosPersonalizationAppResourcesSize);
+
+  for (const auto& resource : resources) {
+    if (ShouldIncludeResource(resource))
+      source->AddResourcePath(resource.path, resource.id);
+  }
 
   source->AddResourcePath("test_loader.html", IDR_WEBUI_HTML_TEST_LOADER_HTML);
   source->AddResourcePath("test_loader.js", IDR_WEBUI_JS_TEST_LOADER_JS);
@@ -30,7 +45,9 @@
                           IDR_WEBUI_JS_TEST_LOADER_UTIL_JS);
 
 #if !DCHECK_IS_ON()
-  source->SetDefaultResource(IDR_CHROMEOS_PERSONALIZATION_APP_INDEX_HTML);
+  // Add a default path to avoid crash when not debugging.
+  source->SetDefaultResource(
+      IDR_CHROMEOS_PERSONALIZATION_APP_TRUSTED_INDEX_HTML);
 #endif  // !DCHECK_IS_ON()
 }
 
diff --git a/chromeos/components/personalization_app/resources/BUILD.gn b/chromeos/components/personalization_app/resources/BUILD.gn
index 73face2..d4b6879 100644
--- a/chromeos/components/personalization_app/resources/BUILD.gn
+++ b/chromeos/components/personalization_app/resources/BUILD.gn
@@ -8,102 +8,24 @@
 import("//tools/polymer/html_to_js.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-preprocessed_dir = "preprocessed"
-preprocessed_manifest = "manifest.json"
-preprocess_mojo_manifest = "preprocessed_mojo_manifest.json"
-
-polymer_element_files = [
-  "wallpaper_collections_element.js",
-  "wallpaper_images_element.js",
-  "personalization_router_element.js",
-]
-
 generate_grd("build_grd") {
   deps = [
-    ":preprocess_generated",
-    ":preprocess_mojo",
+    "common:preprocess",
+    "trusted:preprocess",
   ]
   input_files_base_dir = rebase_path(".", "//")
-  input_files = [
-    "index.html",
-    "icon_192.png",
-    "personalization_app.js",
-    "mojo_interface_provider.js",
-  ]
+  input_files = [ "icon_192.png" ]
   manifest_files = [
-    "$target_gen_dir/$preprocessed_manifest",
-    "$target_gen_dir/$preprocess_mojo_manifest",
+    "$target_gen_dir/common/manifest.json",
+    "$target_gen_dir/trusted/manifest.json",
   ]
   grd_prefix = "chromeos_personalization_app"
   out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
 }
 
-# Mojo files, for generating grdp
-preprocess_if_expr("preprocess_mojo") {
-  deps = [ "//chromeos/components/personalization_app/mojom:mojom_js" ]
-  in_folder = "$target_gen_dir/../mojom"
-  out_folder = "$target_gen_dir/$preprocessed_dir"
-  out_manifest = "$target_gen_dir/$preprocess_mojo_manifest"
-  in_files = [ "personalization_app.mojom-lite.js" ]
-}
-
-js_type_check("closure_compile") {
-  is_polymer3 = true
-  deps = [
-    ":mojo_interface_provider",
-    ":personalization_app",
-    ":personalization_router_element",
-    ":wallpaper_collections_element",
-    ":wallpaper_images_element",
+group("closure_compile") {
+  public_deps = [
+    "common:closure_compile",
+    "trusted:closure_compile",
   ]
 }
-
-js_library("mojo_interface_provider") {
-  deps = [ "//chromeos/components/personalization_app/mojom:mojom_js_library_for_compile" ]
-}
-
-js_library("personalization_app") {
-  deps = [
-    ":personalization_router_element",
-    ":wallpaper_collections_element",
-    ":wallpaper_images_element",
-  ]
-}
-
-js_library("wallpaper_collections_element") {
-  deps = [
-    ":mojo_interface_provider",
-    "//third_party/polymer/v3_0/components-chromium/iron-list:iron-list",
-    "//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
-
-js_library("wallpaper_images_element") {
-  deps = [
-    ":mojo_interface_provider",
-    "//third_party/polymer/v3_0/components-chromium/iron-list:iron-list",
-    "//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
-
-js_library("personalization_router_element") {
-  deps = [
-    "//third_party/polymer/v3_0/components-chromium/iron-location:iron-location",
-    "//third_party/polymer/v3_0/components-chromium/iron-location:iron-query-params",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
-
-preprocess_if_expr("preprocess_generated") {
-  deps = [ ":web_components" ]
-  in_folder = target_gen_dir
-  out_folder = "$target_gen_dir/$preprocessed_dir"
-  out_manifest = "$target_gen_dir/$preprocessed_manifest"
-  in_files = polymer_element_files
-}
-
-html_to_js("web_components") {
-  js_files = polymer_element_files
-}
diff --git a/chromeos/components/personalization_app/resources/common/BUILD.gn b/chromeos/components/personalization_app/resources/common/BUILD.gn
new file mode 100644
index 0000000..50a6246
--- /dev/null
+++ b/chromeos/components/personalization_app/resources/common/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/grit/preprocess_if_expr.gni")
+
+js_library("utils") {
+}
+
+js_type_check("closure_compile") {
+  deps = [ ":utils" ]
+}
+
+preprocess_if_expr("preprocess") {
+  deps = []
+  in_folder = ".."
+  out_folder = "$target_gen_dir/processed"
+  out_manifest = "$target_gen_dir/manifest.json"
+  in_files = [ "common/utils.js" ]
+}
diff --git a/chromeos/components/personalization_app/resources/common/utils.js b/chromeos/components/personalization_app/resources/common/utils.js
new file mode 100644
index 0000000..d90416ca
--- /dev/null
+++ b/chromeos/components/personalization_app/resources/common/utils.js
@@ -0,0 +1,17 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Utility functions to be shared between trusted and untrusted
+ * code.
+ */
+
+/**
+ * Checks if argument is an array with non-zero length.
+ * @param {?Object} maybeArray
+ * @return {boolean}
+ */
+export function isNonEmptyArray(maybeArray) {
+  return Array.isArray(maybeArray) && maybeArray.length > 0;
+}
diff --git a/chromeos/components/personalization_app/resources/trusted/BUILD.gn b/chromeos/components/personalization_app/resources/trusted/BUILD.gn
new file mode 100644
index 0000000..de72a1e
--- /dev/null
+++ b/chromeos/components/personalization_app/resources/trusted/BUILD.gn
@@ -0,0 +1,111 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/grit/preprocess_if_expr.gni")
+import("//tools/polymer/html_to_js.gni")
+
+polymer_element_files = [
+  "wallpaper_collections_element.js",
+  "wallpaper_images_element.js",
+  "personalization_router_element.js",
+]
+
+static_files = [
+  "index.html",
+  "mojo_interface_provider.js",
+  "personalization_app.js",
+  "styles.js",
+]
+
+js_library("mojo_interface_provider") {
+  deps = [
+    "../../mojom:mojom_js_library_for_compile",
+    "../common:utils",
+  ]
+}
+
+js_library("personalization_app") {
+  deps = [
+    ":personalization_router_element",
+    ":styles",
+    ":wallpaper_collections_element",
+    ":wallpaper_images_element",
+  ]
+}
+
+js_library("personalization_router_element") {
+  deps = [
+    "//third_party/polymer/v3_0/components-chromium/iron-location:iron-location",
+    "//third_party/polymer/v3_0/components-chromium/iron-location:iron-query-params",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+  ]
+}
+
+js_library("styles") {
+}
+
+js_library("wallpaper_collections_element") {
+  deps = [
+    ":mojo_interface_provider",
+    "//third_party/polymer/v3_0/components-chromium/iron-list:iron-list",
+    "//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+  ]
+}
+
+js_library("wallpaper_images_element") {
+  deps = [
+    ":mojo_interface_provider",
+    "//third_party/polymer/v3_0/components-chromium/iron-list:iron-list",
+    "//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+  ]
+}
+
+js_type_check("closure_compile") {
+  is_polymer3 = true
+  deps = [
+    ":mojo_interface_provider",
+    ":personalization_app",
+    ":personalization_router_element",
+    ":styles",
+    ":wallpaper_collections_element",
+    ":wallpaper_images_element",
+  ]
+}
+
+html_to_js("web_components") {
+  js_files = polymer_element_files
+}
+
+copy("copy_static") {
+  sources = static_files
+  outputs = [ "$target_gen_dir/{{source_file_part}}" ]
+}
+
+copy("copy_mojo_to_trusted") {
+  deps = [ "../../mojom:mojom_js" ]
+  sources = [ "$target_gen_dir/../../mojom/personalization_app.mojom-lite.js" ]
+  outputs = [ "$target_gen_dir/personalization_app.mojom-lite.js" ]
+}
+
+preprocess_if_expr("preprocess") {
+  deps = [
+    ":copy_mojo_to_trusted",
+    ":copy_static",
+    ":web_components",
+  ]
+  in_folder = "$target_gen_dir/.."
+  out_folder = "$target_gen_dir/processed"
+  out_manifest = "$target_gen_dir/manifest.json"
+  in_files = []
+  foreach(file, polymer_element_files) {
+    in_files += [ "trusted/$file" ]
+  }
+  foreach(file, static_files) {
+    in_files += [ "trusted/$file" ]
+  }
+  in_files += [ "trusted/personalization_app.mojom-lite.js" ]
+}
diff --git a/chromeos/components/personalization_app/resources/index.html b/chromeos/components/personalization_app/resources/trusted/index.html
similarity index 68%
rename from chromeos/components/personalization_app/resources/index.html
rename to chromeos/components/personalization_app/resources/trusted/index.html
index 251ad06..1c0f446 100644
--- a/chromeos/components/personalization_app/resources/index.html
+++ b/chromeos/components/personalization_app/resources/trusted/index.html
@@ -7,9 +7,7 @@
     <title>$i18n{title}</title>
     <link rel="icon" type="image/png" sizes="192x192" href="icon_192.png">
     <meta charset="utf-8">
-    <!-- Below mojo script required to run browser tests -->
-    <script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script>
-    <script type="module" src="personalization_app.js" defer></script>
+    <script type="module" src="/trusted/personalization_app.js" defer></script>
   </head>
   <body>
     <personalization-router></personalization-router>
diff --git a/chromeos/components/personalization_app/resources/mojo_interface_provider.js b/chromeos/components/personalization_app/resources/trusted/mojo_interface_provider.js
similarity index 80%
rename from chromeos/components/personalization_app/resources/mojo_interface_provider.js
rename to chromeos/components/personalization_app/resources/trusted/mojo_interface_provider.js
index 568cca9..853f592 100644
--- a/chromeos/components/personalization_app/resources/mojo_interface_provider.js
+++ b/chromeos/components/personalization_app/resources/trusted/mojo_interface_provider.js
@@ -8,11 +8,11 @@
  * mojom data and mocking out the implementation for testing.
  */
 
+import {assert} from 'chrome://resources/js/assert.m.js';
 import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 import 'chrome://resources/mojo/url/mojom/url.mojom-lite.js';
-import 'chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-lite.js';
-import 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-lite.js';
 import './personalization_app.mojom-lite.js';
+import {isNonEmptyArray} from '../common/utils.js';
 
 /** @type {?chromeos.personalizationApp.mojom.WallpaperProviderInterface} */
 let wallpaperProvider = null;
@@ -38,6 +38,17 @@
 }
 
 /**
+ * Utility function to check if array has data and cast to non-null.
+ * @param {?Array<!T>} items
+ * @return {!Array<!T>}
+ * @template T
+ */
+function assertArrayHasData(items) {
+  assert(isNonEmptyArray(items), 'No data available');
+  return /** @type {!Array<!T>} */ (items);
+}
+
+/**
  * A helper function to fetch collections and throw on error.
  * @param {!chromeos.personalizationApp.mojom.WallpaperProviderInterface}
  *     provider
@@ -46,10 +57,7 @@
  */
 export async function fetchCollectionsHelper(provider) {
   const {collections} = await provider.fetchCollections();
-  if (!Array.isArray(collections)) {
-    throw new Error('No collections available')
-  }
-  return {collections};
+  return {collections: assertArrayHasData(collections)};
 }
 
 /**
@@ -58,12 +66,9 @@
  *     provider
  * @param {!string} collectionId
  * @return {!Promise<{images:
- *     !Array<!chromeos.personalizationApp.mojom.WallpaperImage>,}>}
+ *     !Array<!chromeos.personalizationApp.mojom.WallpaperImage>}>}
  */
 export async function fetchImagesForCollectionHelper(provider, collectionId) {
   const {images} = await provider.fetchImagesForCollection(collectionId);
-  if (!Array.isArray(images)) {
-    throw new Error('No images available');
-  }
-  return {images};
+  return {images: assertArrayHasData(images)};
 }
diff --git a/chromeos/components/personalization_app/resources/personalization_app.js b/chromeos/components/personalization_app/resources/trusted/personalization_app.js
similarity index 95%
rename from chromeos/components/personalization_app/resources/personalization_app.js
rename to chromeos/components/personalization_app/resources/trusted/personalization_app.js
index 3522f193..d932cf7 100644
--- a/chromeos/components/personalization_app/resources/personalization_app.js
+++ b/chromeos/components/personalization_app/resources/trusted/personalization_app.js
@@ -12,3 +12,4 @@
 import './personalization_router_element.js';
 import './wallpaper_collections_element.js';
 import './wallpaper_images_element.js';
+import './styles.js';
diff --git a/chromeos/components/personalization_app/resources/personalization_router_element.html b/chromeos/components/personalization_app/resources/trusted/personalization_router_element.html
similarity index 82%
rename from chromeos/components/personalization_app/resources/personalization_router_element.html
rename to chromeos/components/personalization_app/resources/trusted/personalization_router_element.html
index 953dbd7b..96f9ecfd 100644
--- a/chromeos/components/personalization_app/resources/personalization_router_element.html
+++ b/chromeos/components/personalization_app/resources/trusted/personalization_router_element.html
@@ -1,4 +1,4 @@
-<iron-location path="{{path_}}" query="{{query_}}" path-changed="pathChanged_">
+<iron-location path="{{path_}}" query="{{query_}}">
 </iron-location>
 <iron-query-params params-object="{{queryParams_}}" params-string="{{query_}}">
 </iron-query-params>
diff --git a/chromeos/components/personalization_app/resources/personalization_router_element.js b/chromeos/components/personalization_app/resources/trusted/personalization_router_element.js
similarity index 100%
rename from chromeos/components/personalization_app/resources/personalization_router_element.js
rename to chromeos/components/personalization_app/resources/trusted/personalization_router_element.js
diff --git a/chromeos/components/personalization_app/resources/trusted/styles.js b/chromeos/components/personalization_app/resources/trusted/styles.js
new file mode 100644
index 0000000..28a5d8df
--- /dev/null
+++ b/chromeos/components/personalization_app/resources/trusted/styles.js
@@ -0,0 +1,22 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+const styles = document.createElement('dom-module');
+
+styles.innerHTML = `<template>
+    <style>
+      paper-spinner-lite {
+        display: none;
+        height: 28px;
+        margin: 150px auto;
+      }
+      paper-spinner-lite[active] {
+        display: block;
+      }
+    </style>
+  </template>`;
+
+styles.register('shared-style');
diff --git a/chromeos/components/personalization_app/resources/wallpaper_collections_element.html b/chromeos/components/personalization_app/resources/trusted/wallpaper_collections_element.html
similarity index 93%
rename from chromeos/components/personalization_app/resources/wallpaper_collections_element.html
rename to chromeos/components/personalization_app/resources/trusted/wallpaper_collections_element.html
index bea3432..052f4c0 100644
--- a/chromeos/components/personalization_app/resources/wallpaper_collections_element.html
+++ b/chromeos/components/personalization_app/resources/trusted/wallpaper_collections_element.html
@@ -1,3 +1,4 @@
+<style include="shared-style"></style>
 <paper-spinner-lite active="[[isLoading_]]"></paper-spinner-lite>
 <!-- TODO(b/181697575) handle error cases and update error string to UI spec -->
 <p hidden="[[!hasError_]]" id="error">error</p>
diff --git a/chromeos/components/personalization_app/resources/wallpaper_collections_element.js b/chromeos/components/personalization_app/resources/trusted/wallpaper_collections_element.js
similarity index 96%
rename from chromeos/components/personalization_app/resources/wallpaper_collections_element.js
rename to chromeos/components/personalization_app/resources/trusted/wallpaper_collections_element.js
index 73225c0..746e734 100644
--- a/chromeos/components/personalization_app/resources/wallpaper_collections_element.js
+++ b/chromeos/components/personalization_app/resources/trusted/wallpaper_collections_element.js
@@ -11,6 +11,7 @@
 import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
 import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js';
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {isNonEmptyArray} from '../common/utils.js';
 import {fetchCollectionsHelper, getWallpaperProvider} from './mojo_interface_provider.js';
 
 export class WallpaperCollections extends PolymerElement {
@@ -98,7 +99,7 @@
    * @return {boolean}
    */
   computeShowCollections_(collections, loading) {
-    return !loading && Array.isArray(collections) && collections.length > 0;
+    return !loading && isNonEmptyArray(collections);
   }
 
   /**
diff --git a/chromeos/components/personalization_app/resources/wallpaper_images_element.html b/chromeos/components/personalization_app/resources/trusted/wallpaper_images_element.html
similarity index 92%
rename from chromeos/components/personalization_app/resources/wallpaper_images_element.html
rename to chromeos/components/personalization_app/resources/trusted/wallpaper_images_element.html
index 9f854f21..7bd843b 100644
--- a/chromeos/components/personalization_app/resources/wallpaper_images_element.html
+++ b/chromeos/components/personalization_app/resources/trusted/wallpaper_images_element.html
@@ -1,3 +1,4 @@
+<style include="shared-style"></style>
 <paper-spinner-lite active="[[isLoading_]]"></paper-spinner-lite>
 <!-- TODO(b/181697575) handle error cases and update error string to UI spec -->
 <p hidden="[[!hasError_]]" id="error">error</p>
diff --git a/chromeos/components/personalization_app/resources/wallpaper_images_element.js b/chromeos/components/personalization_app/resources/trusted/wallpaper_images_element.js
similarity index 97%
rename from chromeos/components/personalization_app/resources/wallpaper_images_element.js
rename to chromeos/components/personalization_app/resources/trusted/wallpaper_images_element.js
index 70bdedf4..7f47b6f1 100644
--- a/chromeos/components/personalization_app/resources/wallpaper_images_element.js
+++ b/chromeos/components/personalization_app/resources/trusted/wallpaper_images_element.js
@@ -13,6 +13,7 @@
 import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js';
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {isNonEmptyArray} from '../common/utils.js';
 import {fetchImagesForCollectionHelper, getWallpaperProvider} from './mojo_interface_provider.js';
 
 export class WallpaperImages extends PolymerElement {
@@ -136,7 +137,7 @@
    * @return {boolean}
    */
   computeShowImages_(images, loading) {
-    return !loading && Array.isArray(images) && images.length > 0;
+    return !loading && isNonEmptyArray(images);
   }
 
   /**
diff --git a/chromeos/dbus/shill/fake_shill_service_client.cc b/chromeos/dbus/shill/fake_shill_service_client.cc
index 9853853..87581bf 100644
--- a/chromeos/dbus/shill/fake_shill_service_client.cc
+++ b/chromeos/dbus/shill/fake_shill_service_client.cc
@@ -166,6 +166,8 @@
     // Remove credentials that Shill wouldn't send.
     result_properties->RemoveKey(shill::kPassphraseProperty);
   } else {
+    DCHECK(!require_service_to_get_properties_);
+
     // This may happen if we remove services from the list.
     VLOG(2) << "Properties not found for: " << service_path.value();
   }
@@ -646,6 +648,11 @@
                                                   std::move(property_update));
 }
 
+void FakeShillServiceClient::SetRequireServiceToGetProperties(
+    bool require_service_to_get_properties) {
+  require_service_to_get_properties_ = require_service_to_get_properties;
+}
+
 void FakeShillServiceClient::NotifyObserversPropertyChanged(
     const dbus::ObjectPath& service_path,
     const std::string& property) {
diff --git a/chromeos/dbus/shill/fake_shill_service_client.h b/chromeos/dbus/shill/fake_shill_service_client.h
index 0bc04b1..196df0ca 100644
--- a/chromeos/dbus/shill/fake_shill_service_client.h
+++ b/chromeos/dbus/shill/fake_shill_service_client.h
@@ -109,6 +109,8 @@
   void SetConnectBehavior(const std::string& service_path,
                           const base::RepeatingClosure& behavior) override;
   void SetHoldBackServicePropertyUpdates(bool hold_back) override;
+  void SetRequireServiceToGetProperties(
+      bool require_service_to_get_properties) override;
 
  private:
   typedef base::ObserverList<ShillPropertyChangedObserver>::Unchecked
@@ -144,6 +146,10 @@
   // |hold_back_service_property_updates_| was true.
   std::vector<base::OnceClosure> recorded_property_updates_;
 
+  // Whether or not this class should fail if GetProperties() is called for an
+  // unknown service.
+  bool require_service_to_get_properties_ = false;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<FakeShillServiceClient> weak_ptr_factory_{this};
diff --git a/chromeos/dbus/shill/shill_service_client.h b/chromeos/dbus/shill/shill_service_client.h
index c4b351d2..adaa6e0c 100644
--- a/chromeos/dbus/shill/shill_service_client.h
+++ b/chromeos/dbus/shill/shill_service_client.h
@@ -106,6 +106,11 @@
     // |hold_back| == false, sends all recorded property updates.
     virtual void SetHoldBackServicePropertyUpdates(bool hold_back) = 0;
 
+    // Sets whether the fake should fail if requested to fetch properties for a
+    // service that is not known by Shill.
+    virtual void SetRequireServiceToGetProperties(
+        bool require_service_to_get_properties) = 0;
+
    protected:
     virtual ~TestInterface() {}
   };
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc
index 5af5c38..bf85789 100644
--- a/chromeos/network/network_state_handler.cc
+++ b/chromeos/network/network_state_handler.cc
@@ -1096,8 +1096,8 @@
     const std::string& service_path) {
   NetworkState* network = GetModifiableNetworkState(service_path);
   if (network) {
-    // Tether networks are not managed by Shill; do not request properties.
-    if (network->type() == kTypeTether)
+    // Do not request properties for networks which are not backed by Shill.
+    if (network->IsNonProfileType())
       return;
     // Do not request properties if a condition has already triggered a request.
     if (network->update_requested())
@@ -1308,6 +1308,11 @@
        iter != network_list_.end(); ++iter) {
     const NetworkState* network = (*iter)->AsNetworkState();
     DCHECK(network);
+
+    // Do not request properties for networks which are not backed by Shill.
+    if (network->IsNonProfileType())
+      continue;
+
     shill_property_handler_->RequestProperties(
         ManagedState::MANAGED_TYPE_NETWORK, network->path());
   }
diff --git a/chromeos/network/network_state_handler.h b/chromeos/network/network_state_handler.h
index 92a4dd4..979b2b08 100644
--- a/chromeos/network/network_state_handler.h
+++ b/chromeos/network/network_state_handler.h
@@ -515,6 +515,7 @@
   FRIEND_TEST_ALL_PREFIXES(NetworkStateHandlerTest, BlockedByPolicyOnlyManaged);
   FRIEND_TEST_ALL_PREFIXES(NetworkStateHandlerTest,
                            BlockedByPolicyOnlyManagedIfAvailable);
+  FRIEND_TEST_ALL_PREFIXES(NetworkStateHandlerTest, SyncStubCellularNetworks);
 
   // Implementation for GetNetworkListByType and GetActiveNetworkListByType.
   void GetNetworkListByTypeImpl(const NetworkTypePattern& type,
diff --git a/chromeos/network/network_state_handler_unittest.cc b/chromeos/network/network_state_handler_unittest.cc
index eee627a..668a928 100644
--- a/chromeos/network/network_state_handler_unittest.cc
+++ b/chromeos/network/network_state_handler_unittest.cc
@@ -2212,6 +2212,14 @@
   EXPECT_EQ(kStubCellularIccid, cellular->iccid());
   EXPECT_EQ(1u, test_observer_->network_list_changed_count());
 
+  // Set the test to fail if properties are requested from a service not backed
+  // by Shill, then update the profiles property and very that no test failure
+  // occurs. This verifies that stub networks do not have properties requested
+  // on profile change.
+  service_test_->SetRequireServiceToGetProperties(true);
+  network_state_handler_->shill_property_handler_->OnPropertyChanged(
+      shill::kProfilesProperty, base::Value(base::Value::Type::LIST));
+
   // Verify that StubCellularNetworksProvider can remove existing
   // networks.
   test_observer_->reset_change_counts();
diff --git a/chromeos/network/onc/variable_expander.cc b/chromeos/network/onc/variable_expander.cc
index 1df4464..63d7ea3 100644
--- a/chromeos/network/onc/variable_expander.cc
+++ b/chromeos/network/onc/variable_expander.cc
@@ -147,12 +147,6 @@
       // Nothing to do here.
       break;
     }
-
-    // TODO(crbug.com/859477): Remove after root cause is found.
-    case base::Value::Type::DEAD: {
-      CHECK(false);
-      break;
-    }
   }
   return no_error;
 }
diff --git a/components/enterprise/common/proto/connectors.proto b/components/enterprise/common/proto/connectors.proto
index 21b4b64..eb1eb0b 100644
--- a/components/enterprise/common/proto/connectors.proto
+++ b/components/enterprise/common/proto/connectors.proto
@@ -43,6 +43,40 @@
   optional string email = 5;
 }
 
+message ClientMetadata {
+  // Describes the browser uploading a scan request.
+  message Browser {
+    optional string browser_id = 1;
+    optional string user_agent = 2;
+    optional string chrome_version = 3;
+
+    // This is omitted on scans triggered at the profile level.
+    optional string machine_user = 4;
+  };
+  optional Browser browser = 1;
+
+  // Describes the device uploading a scan request. This is omitted on scans
+  // triggered at the profile level.
+  message Device {
+    optional string dm_token = 1;
+    optional string client_id = 2;
+    optional string os_version = 3;
+    optional string os_platform = 4;
+    optional string name = 5;
+  };
+  optional Device device = 2;
+
+  // Describes the profile uploading a scan request.
+  message Profile {
+    optional string dm_token = 1;
+    optional string gaia_email = 2;
+    optional string profile_path = 3;
+    optional string profile_name = 4;
+    optional string client_id = 5;
+  };
+  optional Profile profile = 3;
+};
+
 // Analysis request sent from chrome to backend.
 message ContentAnalysisRequest {
   // The TokenID for Enterprise-enrolled devices.  This identifies a specific
@@ -66,6 +100,10 @@
   // The tags configured for the URL that triggered the content analysis.
   repeated string tags = 11;
 
+  // Additional information about the browser, device or profile so events can
+  // be reported with device/user identifiable information.
+  optional ClientMetadata client_metadata = 12;
+
   // Reserved to make sure there is no overlap with DeepScanningClientRequest.
   reserved 3, 4, 6 to 8;
 }
diff --git a/components/feed/core/common/pref_names.cc b/components/feed/core/common/pref_names.cc
index 7ca3d2e..073722f2 100644
--- a/components/feed/core/common/pref_names.cc
+++ b/components/feed/core/common/pref_names.cc
@@ -41,6 +41,7 @@
 const char kDiscoverAPIEndpointOverride[] = "feedv2.actions_endpoint_override";
 const char kExperiments[] = "feedv2.experiments";
 const char kEnableWebFeedUI[] = "webfeed_ui.enable";
+const char kReliabilityLoggingIdSalt[] = "feedv2.reliability_logging_id_salt";
 
 }  // namespace prefs
 
@@ -98,6 +99,7 @@
   registry->RegisterIntegerPref(feed::prefs::kNoticeCardClicksCount, 0);
   registry->RegisterDictionaryPref(feed::prefs::kExperiments);
   registry->RegisterBooleanPref(feed::prefs::kEnableWebFeedUI, false);
+  registry->RegisterUint64Pref(feed::prefs::kReliabilityLoggingIdSalt, 0);
 
 #if defined(OS_IOS)
   registry->RegisterBooleanPref(feed::prefs::kLastFetchHadLoggingEnabled,
diff --git a/components/feed/core/common/pref_names.h b/components/feed/core/common/pref_names.h
index 4c92c7bbe..bfdde097 100644
--- a/components/feed/core/common/pref_names.h
+++ b/components/feed/core/common/pref_names.h
@@ -69,6 +69,8 @@
 extern const char kExperiments[];
 // If set to false, the WebFeed UI is disabled.
 extern const char kEnableWebFeedUI[];
+// Random bytes used in generating reliability logging ID.
+extern const char kReliabilityLoggingIdSalt[];
 
 }  // namespace prefs
 
diff --git a/components/feed/core/v2/api_test/feed_api_stream_unittest.cc b/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
index 1598f1f6..a59fbbd 100644
--- a/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
+++ b/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
@@ -5,11 +5,13 @@
 #include "base/callback_helpers.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/metrics/user_action_tester.h"
+#include "components/feed/core/common/pref_names.h"
 #include "components/feed/core/v2/api_test/feed_api_test.h"
 #include "components/feed/core/v2/config.h"
 #include "components/feed/core/v2/feed_stream.h"
 #include "components/feed/core/v2/feedstore_util.h"
 #include "components/feed/core/v2/public/feed_api.h"
+#include "components/feed/core/v2/public/feed_service.h"
 #include "components/feed/core/v2/test/callback_receiver.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -2009,6 +2011,35 @@
   EXPECT_EQ("new-frame-data", stored_data->content[0].frame());
 }
 
+TEST_F(FeedApiTest, ReliabilityLoggingId_GetAndReset) {
+  // If nothing changes between two calls to GetReliabilityLoggingId(), it
+  // should return the same ID.
+  uint64_t first_id =
+      FeedService::GetReliabilityLoggingId(/*metrics_id=*/"", &profile_prefs_);
+  EXPECT_EQ(first_id, FeedService::GetReliabilityLoggingId(/*metrics_id=*/"",
+                                                           &profile_prefs_));
+
+  profile_prefs_.ClearPref(prefs::kReliabilityLoggingIdSalt);
+  EXPECT_NE(first_id, FeedService::GetReliabilityLoggingId(/*metrics_id=*/"",
+                                                           &profile_prefs_));
+}
+
+TEST_F(FeedApiTest, ReliabilityLoggingId_ChangeOnMetricsIdChange) {
+  const char kSomeMetricsId[] = "metrics-id-1";
+  uint64_t first_id =
+      FeedService::GetReliabilityLoggingId(kSomeMetricsId, &profile_prefs_);
+  EXPECT_NE(first_id, FeedService::GetReliabilityLoggingId("metrics-id-2",
+                                                           &profile_prefs_));
+
+  // If we use the original metrics ID, we should get the original ID unless
+  // the salt is cleared.
+  EXPECT_EQ(first_id, FeedService::GetReliabilityLoggingId(kSomeMetricsId,
+                                                           &profile_prefs_));
+  profile_prefs_.ClearPref(prefs::kReliabilityLoggingIdSalt);
+  EXPECT_NE(first_id, FeedService::GetReliabilityLoggingId(kSomeMetricsId,
+                                                           &profile_prefs_));
+}
+
 // Keep instantiations at the bottom.
 INSTANTIATE_TEST_SUITE_P(FeedApiTest,
                          FeedStreamTestForAllStreamTypes,
diff --git a/components/feed/core/v2/public/feed_service.cc b/components/feed/core/v2/public/feed_service.cc
index c120ff2b..df42568 100644
--- a/components/feed/core/v2/public/feed_service.cc
+++ b/components/feed/core/v2/public/feed_service.cc
@@ -7,8 +7,12 @@
 #include <utility>
 
 #include "base/command_line.h"
+#include "base/hash/hash.h"
+#include "base/rand_util.h"
 #include "base/scoped_observation.h"
+#include "base/strings/strcat.h"
 #include "build/build_config.h"
+#include "components/feed/core/common/pref_names.h"
 #include "components/feed/core/shared_prefs/pref_names.h"
 #include "components/feed/core/v2/feed_network_impl.h"
 #include "components/feed/core/v2/feed_store.h"
@@ -253,6 +257,24 @@
   return pref_service.GetBoolean(feed::prefs::kEnableSnippets);
 }
 
+// static
+uint64_t FeedService::GetReliabilityLoggingId(const std::string& metrics_id,
+                                              PrefService* prefs) {
+  // The reliability logging ID is generated from the UMA client ID so that it
+  // changes whenever the UMA client ID changes. We hash the UMA client ID with
+  // a random salt so that the UMA client ID can't be guessed from the
+  // reliability logging ID. The salt never leaves the client.
+  uint64_t salt;
+  if (!prefs->HasPrefPath(prefs::kReliabilityLoggingIdSalt)) {
+    salt = base::RandUint64();
+    prefs->SetUint64(prefs::kReliabilityLoggingIdSalt, salt);
+  } else {
+    salt = prefs->GetUint64(prefs::kReliabilityLoggingIdSalt);
+  }
+  return base::FastHash(base::StrCat(
+      {metrics_id, std::string(reinterpret_cast<char*>(&salt), sizeof(salt))}));
+}
+
 #if defined(OS_ANDROID)
 void FeedService::OnApplicationStateChange(
     base::android::ApplicationState state) {
diff --git a/components/feed/core/v2/public/feed_service.h b/components/feed/core/v2/public/feed_service.h
index ff5e7ed53..07981ad 100644
--- a/components/feed/core/v2/public/feed_service.h
+++ b/components/feed/core/v2/public/feed_service.h
@@ -113,6 +113,10 @@
   // Whether Feedv2 is enabled. If false, the FeedService should not be created.
   static bool IsEnabled(const PrefService& pref_service);
 
+  // Returns the client ID for reliability logging.
+  static uint64_t GetReliabilityLoggingId(const std::string& metrics_id,
+                                          PrefService* pref_service);
+
  private:
   class StreamDelegateImpl;
   class NetworkDelegateImpl;
diff --git a/components/history_clusters/core/memories_remote_model_helper.cc b/components/history_clusters/core/memories_remote_model_helper.cc
index 6be5ae3..c5ae9ac8 100644
--- a/components/history_clusters/core/memories_remote_model_helper.cc
+++ b/components/history_clusters/core/memories_remote_model_helper.cc
@@ -136,8 +136,10 @@
     const std::vector<MemoriesVisit>& visits,
     MemoriesCallback callback) {
   const GURL endpoint(memories::RemoteModelEndpoint());
-  if (!endpoint.is_valid())
-    NOTREACHED();
+  if (!endpoint.is_valid() || visits.empty()) {
+    std::move(callback).Run({});
+    return;
+  }
   StopPendingRequests();
 
   std::string request_body;
diff --git a/components/history_clusters/core/memories_service.cc b/components/history_clusters/core/memories_service.cc
index 6ae6b00d..eb231ea 100644
--- a/components/history_clusters/core/memories_service.cc
+++ b/components/history_clusters/core/memories_service.cc
@@ -51,11 +51,9 @@
   }
 }
 
-void MemoriesService::GetMemories(MemoriesCallback callback) {
-  if (visits_.empty())
-    std::move(callback).Run({});
-  else
-    remote_model_helper_->GetMemories(visits_, std::move(callback));
+void MemoriesService::QueryMemories(const std::string& query,
+                                    MemoriesCallback callback) {
+  remote_model_helper_->GetMemories(visits_, std::move(callback));
 }
 
 }  // namespace memories
diff --git a/components/history_clusters/core/memories_service.h b/components/history_clusters/core/memories_service.h
index 49cf983..c9619535 100644
--- a/components/history_clusters/core/memories_service.h
+++ b/components/history_clusters/core/memories_service.h
@@ -7,6 +7,7 @@
 
 #include <map>
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "base/macros.h"
@@ -46,7 +47,8 @@
   void CompleteVisitIfReady(int64_t nav_id);
 
   // Asks |remote_model_helper_| to construct memories from |visits_|.
-  void GetMemories(MemoriesCallback callback);
+  // Note: |query| is ignored at the moment.
+  void QueryMemories(const std::string& query, MemoriesCallback callback);
 
  private:
   friend class MemoriesServiceTestApi;
diff --git a/components/history_clusters/core/memories_service_unittest.cc b/components/history_clusters/core/memories_service_unittest.cc
index 5777491..cea2d470 100644
--- a/components/history_clusters/core/memories_service_unittest.cc
+++ b/components/history_clusters/core/memories_service_unittest.cc
@@ -105,7 +105,7 @@
   int64_t next_navigation_id_ = 0;
 };
 
-TEST_F(MemoriesServiceTest, GetMemories) {
+TEST_F(MemoriesServiceTest, QueryMemories) {
   const char endpoint[] = "https://endpoint.com/";
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeatureWithParameters(
@@ -127,8 +127,8 @@
   AddVisitWithDetails(4, GURL{"https://github.com"}, u"Github title", 4, 5);
 
   EXPECT_FALSE(test_url_loader_factory_.IsPending(endpoint));
-  memories_service_->GetMemories(
-      base::BindLambdaForTesting([&](memories::Memories memories) {
+  memories_service_->QueryMemories(
+      "", base::BindLambdaForTesting([&](memories::Memories memories) {
         // Verify the parsed response.
         ASSERT_EQ(memories.size(), 2u);
         EXPECT_FALSE(memories[0]->id.is_empty());
@@ -216,14 +216,14 @@
   run_loop_.Run();
 }
 
-TEST_F(MemoriesServiceTest, GetMemoriesWithEmptyVisits) {
+TEST_F(MemoriesServiceTest, QueryMemoriesWithEmptyVisits) {
   const char endpoint[] = "https://endpoint.com/";
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeatureWithParameters(
       memories::kMemories, {{memories::kRemoteModelEndpointParam, endpoint}});
 
-  memories_service_->GetMemories(
-      base::BindLambdaForTesting([&](memories::Memories memories) {
+  memories_service_->QueryMemories(
+      "", base::BindLambdaForTesting([&](memories::Memories memories) {
         // Verify the parsed response.
         EXPECT_TRUE(memories.empty());
         run_loop_quit_.Run();
@@ -236,7 +236,7 @@
   run_loop_.Run();
 }
 
-TEST_F(MemoriesServiceTest, GetMemoriesWithEmptyEndpoint) {
+TEST_F(MemoriesServiceTest, QueryMemoriesWithEmptyEndpoint) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeatureWithParameters(
       memories::kMemories, {{memories::kRemoteModelEndpointParam, ""}});
@@ -244,14 +244,22 @@
   AddVisit(0, GURL{"google.com"});
   AddVisit(1, GURL{"github.com"});
 
-  EXPECT_DCHECK_DEATH(memories_service_->GetMemories(base::BindLambdaForTesting(
-      [&](memories::Memories memories) { NOTREACHED(); })));
+  EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
+  memories_service_->QueryMemories(
+      "", base::BindLambdaForTesting([&](memories::Memories memories) {
+        // Verify the empty response.
+        EXPECT_TRUE(memories.empty());
+        run_loop_quit_.Run();
+      }));
 
   // Verify no request is made.
   EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
+
+  // Verify the callback is invoked.
+  run_loop_.Run();
 }
 
-TEST_F(MemoriesServiceTest, GetMemoriesWithEmptyResponse) {
+TEST_F(MemoriesServiceTest, QueryMemoriesWithEmptyResponse) {
   const char endpoint[] = "https://endpoint.com/";
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeatureWithParameters(
@@ -261,8 +269,8 @@
   AddVisit(1, GURL{"github.com"});
 
   EXPECT_FALSE(test_url_loader_factory_.IsPending(endpoint));
-  memories_service_->GetMemories(
-      base::BindLambdaForTesting([&](memories::Memories memories) {
+  memories_service_->QueryMemories(
+      "", base::BindLambdaForTesting([&](memories::Memories memories) {
         // Verify the parsed response.
         EXPECT_TRUE(memories.empty());
         run_loop_quit_.Run();
@@ -279,7 +287,7 @@
   run_loop_.Run();
 }
 
-TEST_F(MemoriesServiceTest, GetMemoriesWithInvalidJsonResponse) {
+TEST_F(MemoriesServiceTest, QueryMemoriesWithInvalidJsonResponse) {
   const char endpoint[] = "https://endpoint.com/";
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeatureWithParameters(
@@ -289,8 +297,8 @@
   AddVisit(1, GURL{"github.com"});
 
   EXPECT_FALSE(test_url_loader_factory_.IsPending(endpoint));
-  memories_service_->GetMemories(
-      base::BindLambdaForTesting([&](memories::Memories memories) {
+  memories_service_->QueryMemories(
+      "", base::BindLambdaForTesting([&](memories::Memories memories) {
         // Verify the parsed response.
         EXPECT_TRUE(memories.empty());
         run_loop_quit_.Run();
@@ -307,7 +315,7 @@
   run_loop_.Run();
 }
 
-TEST_F(MemoriesServiceTest, GetMemoriesWithEmptyJsonResponse) {
+TEST_F(MemoriesServiceTest, QueryMemoriesWithEmptyJsonResponse) {
   const char endpoint[] = "https://endpoint.com/";
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeatureWithParameters(
@@ -317,8 +325,8 @@
   AddVisit(1, GURL{"github.com"});
 
   EXPECT_FALSE(test_url_loader_factory_.IsPending(endpoint));
-  memories_service_->GetMemories(
-      base::BindLambdaForTesting([&](memories::Memories memories) {
+  memories_service_->QueryMemories(
+      "", base::BindLambdaForTesting([&](memories::Memories memories) {
         // Verify the parsed response.
         EXPECT_TRUE(memories.empty());
         run_loop_quit_.Run();
@@ -335,7 +343,7 @@
   run_loop_.Run();
 }
 
-TEST_F(MemoriesServiceTest, GetMemoriesWithPendingRequest) {
+TEST_F(MemoriesServiceTest, QueryMemoriesWithPendingRequest) {
   const char endpoint[] = "https://endpoint.com/";
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeatureWithParameters(
@@ -345,15 +353,15 @@
   AddVisit(1, GURL{"github.com"});
 
   EXPECT_FALSE(test_url_loader_factory_.IsPending(endpoint));
-  memories_service_->GetMemories(
-      base::BindLambdaForTesting([&](memories::Memories memories) {
+  memories_service_->QueryMemories(
+      "", base::BindLambdaForTesting([&](memories::Memories memories) {
         // Verify not reached.
         EXPECT_TRUE(false);
       }));
 
   EXPECT_TRUE(test_url_loader_factory_.IsPending(endpoint));
-  memories_service_->GetMemories(
-      base::BindLambdaForTesting([&](memories::Memories memories) {
+  memories_service_->QueryMemories(
+      "", base::BindLambdaForTesting([&](memories::Memories memories) {
         // Verify the parsed response.
         EXPECT_EQ(memories.size(), 2u);
         run_loop_quit_.Run();
diff --git a/components/page_info/page_info_ui.cc b/components/page_info/page_info_ui.cc
index 79430dc..604c8c3 100644
--- a/components/page_info/page_info_ui.cc
+++ b/components/page_info/page_info_ui.cc
@@ -826,6 +826,14 @@
       vector_icons::kVrHeadsetIcon, kVectorIconSize,
       color_utils::DeriveDefaultIconColor(related_text_color));
 }
+
+// static
+const gfx::ImageSkia PageInfoUI::GetLaunchIcon(
+    const SkColor related_text_color) {
+  return gfx::CreateVectorIcon(
+      vector_icons::kLaunchIcon, kVectorIconSize,
+      color_utils::DeriveDefaultIconColor(related_text_color));
+}
 #endif
 
 // static
diff --git a/components/page_info/page_info_ui.h b/components/page_info/page_info_ui.h
index 8ede15684..d4ef1a0 100644
--- a/components/page_info/page_info_ui.h
+++ b/components/page_info/page_info_ui.h
@@ -215,6 +215,10 @@
 
   // Returns the icon for VR settings.
   static const gfx::ImageSkia GetVrSettingsIcon(SkColor related_text_color);
+
+  // Returns the icon for a button which opens an external dialog or page (ex.
+  // cookies dialog or site settings page).
+  static const gfx::ImageSkia GetLaunchIcon(const SkColor related_text_color);
 #endif
 
   // Return true if the given ContentSettingsType is in PageInfoUI.
diff --git a/components/page_info_strings.grdp b/components/page_info_strings.grdp
index 1ea97d9..8653f8d 100644
--- a/components/page_info_strings.grdp
+++ b/components/page_info_strings.grdp
@@ -276,6 +276,9 @@
       <message name="IDS_PAGE_INFO_NUM_COOKIES_PARENTHESIZED" desc="The label of the counts for allowed cookies that are in use on the page. This text will be used in IDS_PAGE_INFO_COOKIES_BUTTON_TEXT.">
         {NUM_COOKIES, plural, =1 {(1 in use)} other {(# in use)}}
       </message>
+      <message name="IDS_PAGE_INFO_NUM_COOKIES" desc="The label of the counts for allowed cookies that are in use on the page. This text will be shown next to IDS_PAGE_INFO_COOKIES_BUTTON_TEXT. It is the same as IDS_PAGE_INFO_NUM_COOKIES_PARENTHESIZED, but without parenthesis">
+        {NUM_COOKIES, plural, =1 {1 in use} other {# in use}}
+      </message>
       <message name="IDS_PAGE_INFO_COOKIES_TOOLTIP" desc="The text of the tooltip on IDS_PAGE_INFO_NUM_COOKIES_PARENTHESIZED.">
         Show cookies
       </message>
diff --git a/components/page_info_strings_grdp/IDS_PAGE_INFO_NUM_COOKIES.png.sha1 b/components/page_info_strings_grdp/IDS_PAGE_INFO_NUM_COOKIES.png.sha1
new file mode 100644
index 0000000..5a9520f
--- /dev/null
+++ b/components/page_info_strings_grdp/IDS_PAGE_INFO_NUM_COOKIES.png.sha1
@@ -0,0 +1 @@
+51a0015c5a3a3addcc049b806e938c932b3b948a
\ No newline at end of file
diff --git a/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc b/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
index 53b357b4..ed804ef 100644
--- a/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
+++ b/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
@@ -800,12 +800,13 @@
 
 void PageLoadMetricsUpdateDispatcher::MaybeDispatchTimingUpdates(
     bool should_buffer_timing_update_callback) {
-  // If we merged a new timing value, then we should buffer updates for
-  // |kBufferTimerDelayMillis|, to allow for any other out of order timings to
-  // arrive before we dispatch the minimum observed timings to observers.
+  // If we merged a new timing value, then we should buffer updates to allow for
+  // any other out of order timings to arrive before we dispatch to observers.
   if (should_buffer_timing_update_callback) {
     timer_->Start(
-        FROM_HERE, base::TimeDelta::FromMilliseconds(kBufferTimerDelayMillis),
+        FROM_HERE,
+        base::TimeDelta::FromMilliseconds(
+            GetBufferTimerDelayMillis(TimerType::kBrowser)),
         base::BindOnce(&PageLoadMetricsUpdateDispatcher::DispatchTimingUpdates,
                        base::Unretained(this)));
   } else if (!timer_->IsRunning()) {
diff --git a/components/page_load_metrics/common/page_load_metrics_constants.h b/components/page_load_metrics/common/page_load_metrics_constants.h
index 221bc58..2eea75c 100644
--- a/components/page_load_metrics/common/page_load_metrics_constants.h
+++ b/components/page_load_metrics/common/page_load_metrics_constants.h
@@ -9,11 +9,6 @@
 
 namespace page_load_metrics {
 
-// Amount of time to delay dispatch of metrics. This allows us to batch and send
-// fewer cross-process updates, given that cross-process updates can be
-// expensive.
-const int kBufferTimerDelayMillis = 1000;
-
 const base::Feature kPageLoadMetricsTimerDelayFeature{
     "PageLoadMetricsTimerDelay", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/components/page_load_metrics/common/page_load_metrics_util.cc b/components/page_load_metrics/common/page_load_metrics_util.cc
index 8768df8c..56cab7f 100644
--- a/components/page_load_metrics/common/page_load_metrics_util.cc
+++ b/components/page_load_metrics/common/page_load_metrics_util.cc
@@ -6,11 +6,31 @@
 
 #include <algorithm>
 
+#include "base/metrics/field_trial_params.h"
 #include "base/strings/string_util.h"
+#include "components/page_load_metrics/common/page_load_metrics_constants.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 
 namespace page_load_metrics {
 
+namespace {
+
+// Default timer delay value. Can be overridden by field trial.
+const int kDefaultBufferTimerDelayMillis = 1000;
+
+// Maximum timer delay value.
+const int kMaxBufferTimerDelayMillis = 1000;
+
+// Additional delay for the browser timer relative to the renderer timer, to
+// allow for some variability in task queuing duration and IPC latency.
+const int kExtraBufferTimerDelayMillis = 50;
+
+// Parameter for the PageLoadMetricsTimerDelay feature which specifies a custom
+// timer delay value.
+const char* kBufferTimerDelayParamName = "BufferTimerDelayMillis";
+
+}  // namespace
+
 base::Optional<std::string> GetGoogleHostnamePrefix(const GURL& url) {
   const size_t registry_length =
       net::registry_controlled_domains::GetRegistryLength(
@@ -62,4 +82,18 @@
   return base::Optional<base::TimeDelta>(std::min(a.value(), b.value()));
 }
 
+int GetBufferTimerDelayMillis(TimerType timer_type) {
+  int result = base::GetFieldTrialParamByFeatureAsInt(
+      kPageLoadMetricsTimerDelayFeature, kBufferTimerDelayParamName,
+      kDefaultBufferTimerDelayMillis /* default value */);
+
+  DCHECK(timer_type == TimerType::kBrowser ||
+         timer_type == TimerType::kRenderer);
+  if (timer_type == TimerType::kBrowser) {
+    result += kExtraBufferTimerDelayMillis;
+  }
+
+  return std::min(result, kMaxBufferTimerDelayMillis);
+}
+
 }  // namespace page_load_metrics
diff --git a/components/page_load_metrics/common/page_load_metrics_util.h b/components/page_load_metrics/common/page_load_metrics_util.h
index 3958bd4..4419c58 100644
--- a/components/page_load_metrics/common/page_load_metrics_util.h
+++ b/components/page_load_metrics/common/page_load_metrics_util.h
@@ -35,6 +35,13 @@
 //   https://a.b.c.google.com/foo => returns 'a.b.c'
 base::Optional<std::string> GetGoogleHostnamePrefix(const GURL& url);
 
+// Distinguishes the renderer-side timer from the browser-side timer.
+enum class TimerType { kRenderer = 0, kBrowser = 1 };
+
+// Returns the maximum amount of time to delay dispatch of metrics updates
+// from the renderer process.
+int GetBufferTimerDelayMillis(TimerType timer_type);
+
 }  // namespace page_load_metrics
 
 #endif  // COMPONENTS_PAGE_LOAD_METRICS_COMMON_PAGE_LOAD_METRICS_UTIL_H_
diff --git a/components/page_load_metrics/renderer/page_timing_metrics_sender.cc b/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
index d7be2af7..27523ff 100644
--- a/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
+++ b/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
@@ -10,11 +10,10 @@
 #include "base/callback.h"
 #include "base/containers/contains.h"
 #include "base/feature_list.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "components/page_load_metrics/common/page_load_metrics.mojom.h"
-#include "components/page_load_metrics/common/page_load_metrics_constants.h"
+#include "components/page_load_metrics/common/page_load_metrics_util.h"
 #include "components/page_load_metrics/renderer/page_timing_sender.h"
 #include "services/network/public/cpp/url_loader_completion_status.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
@@ -46,15 +45,12 @@
       metadata_(mojom::FrameMetadata::New()),
       new_features_(mojom::PageLoadFeatures::New()),
       new_deferred_resource_data_(mojom::DeferredResourceCounts::New()),
-      buffer_timer_delay_ms_(kBufferTimerDelayMillis),
+      buffer_timer_delay_ms_(GetBufferTimerDelayMillis(TimerType::kRenderer)),
       metadata_recorder_(initial_monotonic_timing) {
   const auto resource_id = initial_request->resource_id();
   page_resource_data_use_.emplace(
       std::piecewise_construct, std::forward_as_tuple(resource_id),
       std::forward_as_tuple(std::move(initial_request)));
-  buffer_timer_delay_ms_ = base::GetFieldTrialParamByFeatureAsInt(
-      kPageLoadMetricsTimerDelayFeature, "BufferTimerDelayMillis",
-      kBufferTimerDelayMillis /* default value */);
   if (!IsEmpty(*last_timing_)) {
     EnsureSendTimer();
   }
diff --git a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmap.java b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmap.java
index eafe4eac..7bbea4e6 100644
--- a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmap.java
+++ b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmap.java
@@ -12,6 +12,8 @@
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffXfermode;
 
+import androidx.annotation.VisibleForTesting;
+
 import org.chromium.base.Callback;
 import org.chromium.base.task.SequencedTaskRunner;
 
@@ -19,7 +21,6 @@
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.zip.DataFormatException;
 import java.util.zip.Deflater;
 import java.util.zip.Inflater;
 
@@ -39,13 +40,15 @@
     private Bitmap mBitmap;
     private int mWidth;
     private int mHeight;
+    private boolean mIgnoreMissingAlpha;
 
     // Compression by this class achieves a compression ratio of about 20.
 
     // Compressed as a JPEG.
     private byte[] mCompressedData;
     // Compressed with zip.
-    private byte[] mCompressedAlphaBytes;
+    @VisibleForTesting
+    byte[] mCompressedAlphaBytes;
     private SequencedTaskRunner mTaskRunner;
     private AtomicBoolean mInUse = new AtomicBoolean();
 
@@ -60,13 +63,25 @@
         mBitmap = bitmap;
         mWidth = mBitmap.getWidth();
         mHeight = mBitmap.getHeight();
-        // The alpha flag isn't always set even though it should be.
+        mIgnoreMissingAlpha = false;
+        // The alpha flag isn't always set even though it should be as the input bitmap is
+        // ARGB8888 AKA N32Premultiplied.
         mBitmap.setHasAlpha(true);
         mTaskRunner = taskRunner;
         compressInBackground(visible);
     }
 
     /**
+     * Permits missing alpha channel to be ignored when inflating. If this is set to true, the
+     * compressed JPEG will be used without alpha. This will result in black or white backing
+     * to transparent/translucent pixels. Default is false causing the inflation to fail.
+     * @param shouldIgnore whether to ignore missing alpha channel on inflation.
+     */
+    void setIgnoreMissingAlphaForTesting(boolean shouldIgnore) {
+        mIgnoreMissingAlpha = shouldIgnore;
+    }
+
+    /**
      * Locks modifying {@link mBitmap} to prevent use/discard from happening in parallel.
      */
     boolean lock() {
@@ -129,13 +144,26 @@
                 BitmapFactory.decodeByteArray(mCompressedData, 0, mCompressedData.length, options);
         if (mBitmap == null) return false;
 
-        // The alpha flag isn't set by default despite requesting ARGB_8888.
-        mBitmap.setHasAlpha(true);
         // Decompress the alpha channel and apply the alpha mask.
         Bitmap alphaChannel = decompressAlpha(mCompressedAlphaBytes, mWidth, mHeight);
         if (alphaChannel != null) {
+            // The alpha flag isn't set by default despite requesting ARGB_8888.Set it only if alpha
+            // inflation succeeded.
+            mBitmap.setHasAlpha(true);
             applyAlpha(mBitmap, alphaChannel);
             alphaChannel.recycle();
+
+            // The bitmap must be premultiplied if alpha is true and is ARGB_8888.
+            if (!mBitmap.isPremultiplied()) {
+                mBitmap.recycle();
+                mBitmap = null;
+                return false;
+            }
+        } else if (!mIgnoreMissingAlpha) {
+            // Abort if alpha inflation failed and we ignoring it is unacceptable.
+            mBitmap.recycle();
+            mBitmap = null;
+            return false;
         }
         return true;
     }
@@ -218,12 +246,16 @@
         inflater.setInput(alpha, 0, alpha.length);
 
         Bitmap alphaBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
+        if (alphaBitmap == null) return null;
+
         ByteBuffer byteBuffer = ByteBuffer.allocate(width * height);
         try {
             inflater.inflate(byteBuffer.array());
             alphaBitmap.copyPixelsFromBuffer(byteBuffer);
-        } catch (DataFormatException e) {
-            // Should never happen.
+        } catch (Exception e) {
+            // This can happen if the inflated content is the wrong size or the inflation fails.
+            // This can happen if the device is under memory pressure or some sort of corruption
+            // occurs. When this happens we should return a null bitmap.
             alphaBitmap.recycle();
             alphaBitmap = null;
         }
diff --git a/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmapTest.java b/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmapTest.java
index 181c9b9..e28690dce 100644
--- a/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmapTest.java
+++ b/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/CompressibleBitmapTest.java
@@ -150,6 +150,8 @@
 
         FakeShadowBitmapFactory.setBitmap(bitmap);
 
+        // The alpha bitmap is mocked. Just ignore it for the purposes of this test.
+        compressibleBitmap.setIgnoreMissingAlphaForTesting(true);
         CallbackHelper helper = new CallbackHelper();
         compressibleBitmap.inflateInBackground(compressible -> { helper.notifyCalled(); });
         helper.waitForFirst();
@@ -168,6 +170,39 @@
     }
 
     @Test
+    public void testInflateAlphaFails() throws TimeoutException {
+        Bitmap bitmap = Mockito.mock(Bitmap.class);
+        Bitmap alphaBitmap = Mockito.mock(Bitmap.class);
+        when(bitmap.compress(any(), anyInt(), any())).thenReturn(true);
+        when(bitmap.getWidth()).thenReturn(4);
+        when(bitmap.getHeight()).thenReturn(4);
+        when(bitmap.extractAlpha()).thenReturn(alphaBitmap);
+
+        SequencedTaskRunner taskRunner = Mockito.mock(SequencedTaskRunner.class);
+        doAnswer(invocation -> {
+            ((Runnable) invocation.getArgument(0)).run();
+            return null;
+        })
+                .when(taskRunner)
+                .postTask(any());
+
+        CompressibleBitmap compressibleBitmap = new CompressibleBitmap(bitmap, taskRunner, false);
+        verify(bitmap, times(1)).compress(any(), eq(100), any());
+        verify(bitmap, times(1)).extractAlpha();
+        Assert.assertNull(compressibleBitmap.getBitmap());
+
+        FakeShadowBitmapFactory.setBitmap(bitmap);
+
+        CallbackHelper helper = new CallbackHelper();
+        compressibleBitmap.mCompressedAlphaBytes = new byte[] {0x12, 0x34, 0x56};
+        compressibleBitmap.inflateInBackground(compressible -> { helper.notifyCalled(); });
+        helper.waitForFirst();
+
+        // Inflation will fail as the bitmap is bad.
+        Assert.assertNull(compressibleBitmap.getBitmap());
+    }
+
+    @Test
     public void testLocking() throws TimeoutException {
         Bitmap bitmap = Mockito.mock(Bitmap.class);
         Bitmap alphaBitmap = Mockito.mock(Bitmap.class);
diff --git a/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapPainterTest.java b/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapPainterTest.java
index 2d16f4eb..c931e1b 100644
--- a/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapPainterTest.java
+++ b/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapPainterTest.java
@@ -292,16 +292,22 @@
         CompressibleBitmap[][] bitmaps = new CompressibleBitmap[3][2];
         CompressibleBitmap compressibleBitmap00 =
                 new CompressibleBitmap(bitmap00, taskRunner, false);
+        compressibleBitmap00.setIgnoreMissingAlphaForTesting(true);
         CompressibleBitmap compressibleBitmap10 =
                 new CompressibleBitmap(bitmap10, taskRunner, false);
+        compressibleBitmap10.setIgnoreMissingAlphaForTesting(true);
         CompressibleBitmap compressibleBitmap01 =
                 new CompressibleBitmap(bitmap01, taskRunner, false);
+        compressibleBitmap01.setIgnoreMissingAlphaForTesting(true);
         CompressibleBitmap compressibleBitmap11 =
                 new CompressibleBitmap(bitmap11, taskRunner, false);
+        compressibleBitmap11.setIgnoreMissingAlphaForTesting(true);
         CompressibleBitmap compressibleBitmap20 =
                 new CompressibleBitmap(bitmap20, taskRunner, false);
+        compressibleBitmap20.setIgnoreMissingAlphaForTesting(true);
         CompressibleBitmap compressibleBitmap21 =
                 new CompressibleBitmap(bitmap21, taskRunner, false);
+        compressibleBitmap21.setIgnoreMissingAlphaForTesting(true);
         bitmaps[0][0] = compressibleBitmap00;
         bitmaps[1][0] = compressibleBitmap10;
         bitmaps[0][1] = compressibleBitmap01;
diff --git a/components/policy/core/common/android/policy_converter.cc b/components/policy/core/common/android/policy_converter.cc
index 8092d809..763c121 100644
--- a/components/policy/core/common/android/policy_converter.cc
+++ b/components/policy/core/common/android/policy_converter.cc
@@ -177,16 +177,9 @@
       }
       return value;
     }
-
-    // TODO(crbug.com/859477): Remove after root cause is found.
-    case base::Value::Type::DEAD: {
-      CHECK(false);
-      return base::nullopt;
-    }
   }
 
-  // TODO(crbug.com/859477): Revert to NOTREACHED() after root cause is found.
-  CHECK(false);
+  NOTREACHED();
   return base::nullopt;
 }
 
diff --git a/components/policy/core/common/policy_loader_win_unittest.cc b/components/policy/core/common/policy_loader_win_unittest.cc
index da41512..17e29a0c 100644
--- a/components/policy/core/common/policy_loader_win_unittest.cc
+++ b/components/policy/core/common/policy_loader_win_unittest.cc
@@ -132,14 +132,8 @@
 
     case base::Value::Type::BINARY:
       return false;
-
-    // TODO(crbug.com/859477): Remove after root cause is found.
-    case base::Value::Type::DEAD:
-      CHECK(false);
-      return false;
   }
-  // TODO(crbug.com/859477): Revert to NOTREACHED() after root cause is found.
-  CHECK(false);
+  NOTREACHED();
   return false;
 }
 
diff --git a/components/policy/core/common/policy_test_utils.cc b/components/policy/core/common/policy_test_utils.cc
index 41d7eda..5677495 100644
--- a/components/policy/core/common/policy_test_utils.cc
+++ b/components/policy/core/common/policy_test_utils.cc
@@ -137,11 +137,6 @@
       // because there's no equivalent JSON type, and policy values can only
       // take valid JSON values.
       break;
-
-    // TODO(crbug.com/859477): Remove after root cause is found.
-    case base::Value::Type::DEAD:
-      CHECK(false);
-      break;
   }
 
   return NULL;
diff --git a/components/policy/core/common/registry_dict.cc b/components/policy/core/common/registry_dict.cc
index 8b9e9051..f7dd2c5 100644
--- a/components/policy/core/common/registry_dict.cc
+++ b/components/policy/core/common/registry_dict.cc
@@ -132,10 +132,6 @@
     case base::Value::Type::BINARY:
       // No conversion possible.
       break;
-    // TODO(crbug.com/859477): Remove after root cause is found.
-    case base::Value::Type::DEAD:
-      CHECK(false);
-      return base::nullopt;
   }
 
   LOG(WARNING) << "Failed to convert " << value.type() << " to "
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 7538dfe..286ffc5 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -18879,7 +18879,7 @@
       'deprecated': True,
       'example_value': ['https://www.example.com', '[*.]example.edu'],
       'id': 431,
-      'caption': '''Allow media autoplay on a allowlist of URL patterns''',
+      'caption': '''Allow media autoplay on a whitelist of URL patterns''',
       'tags': [],
       'desc': '''This policy is deprecated, please use the '<ph name="AUTOPLAY_ALLOWLIST_POLICY_NAME">AutoplayAllowlist</ph>' policy instead.
 
@@ -18902,7 +18902,7 @@
       },
       'example_value': ['https://www.example.com', '[*.]example.edu'],
       'id': 742,
-      'caption': '''Allow media autoplay on a whitelist of URL patterns''',
+      'caption': '''Allow media autoplay on a allowlist of URL patterns''',
       'tags': [],
       'desc': '''Setting the policy lets videos play automatically (without user consent) with audio content in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>. If <ph name="AUTOPLAY_ALLOWED_POLICY_NAME">AutoplayAllowed</ph> policy is set to True, then this policy has no effect. If <ph name="AUTOPLAY_ALLOWED_POLICY_NAME">AutoplayAllowed</ph> is set to False, then any URL patterns set in this policy can still play. If this policy changes while <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> is running, it only applies to newly opened tabs.
 
diff --git a/components/power_scheduler/power_mode_arbiter.cc b/components/power_scheduler/power_mode_arbiter.cc
index cb9b5915..a91ae27 100644
--- a/components/power_scheduler/power_mode_arbiter.cc
+++ b/components/power_scheduler/power_mode_arbiter.cc
@@ -51,6 +51,8 @@
 
 PowerModeArbiter::Observer::~Observer() = default;
 
+constexpr base::TimeDelta PowerModeArbiter::kResetVoteTimeResolution;
+
 // static
 PowerModeArbiter* PowerModeArbiter::GetInstance() {
   static base::NoDestructor<PowerModeArbiter> arbiter;
@@ -84,30 +86,10 @@
                                std::make_unique<ChargingPowerModeVoter>();
                          }));
 
-  // Check if we need to post a task to update pending votes.
-  base::TimeTicks next_effective_time;
-  {
-    base::AutoLock lock(lock_);
-    for (const auto& entry : pending_resets_) {
-      base::TimeTicks effective_time = entry.second;
-      if (next_effective_time.is_null() ||
-          effective_time < next_effective_time) {
-        next_effective_time = effective_time;
-      }
-    }
-    next_pending_vote_update_time_ = next_effective_time;
-  }
-
-  if (!next_effective_time.is_null()) {
-    base::TimeTicks now = base::TimeTicks::Now();
-    if (next_effective_time < now)
-      next_effective_time = now;
-    task_runner_->PostDelayedTask(
-        FROM_HERE,
-        base::BindOnce(&PowerModeArbiter::UpdatePendingResets,
-                       base::Unretained(this)),
-        next_effective_time - now);
-  }
+  // Check if there are any actionable resets and post another task to handle
+  // future ones if necessary. |update_task_sequence_number_| is initialized to
+  // 0 and incremented in UpdatePendingResets for the first time.
+  UpdatePendingResets(/*sequence_number=*/0);
 }
 
 std::unique_ptr<PowerModeVoter> PowerModeArbiter::NewVoter(const char* name) {
@@ -156,9 +138,13 @@
 void PowerModeArbiter::ResetVoteAfterTimeout(PowerModeVoter* voter,
                                              base::TimeDelta timeout) {
   bool should_post_update_task = false;
+  int sequence_number = 0;
   {
     base::AutoLock lock(lock_);
     base::TimeTicks scheduled_time = base::TimeTicks::Now() + timeout;
+    // Align to the reset task's resolution.
+    scheduled_time = scheduled_time.SnappedToNextTick(base::TimeTicks(),
+                                                      kResetVoteTimeResolution);
     pending_resets_[voter] = scheduled_time;
     // Only post a new task if there isn't one scheduled to run earlier yet.
     // This reduces the number of posted callbacks in situations where the
@@ -167,6 +153,8 @@
                          scheduled_time < next_pending_vote_update_time_)) {
       next_pending_vote_update_time_ = scheduled_time;
       should_post_update_task = true;
+      ++update_task_sequence_number_;
+      sequence_number = update_task_sequence_number_;
     }
   }
 
@@ -174,20 +162,27 @@
     task_runner_->PostDelayedTask(
         FROM_HERE,
         base::BindOnce(&PowerModeArbiter::UpdatePendingResets,
-                       base::Unretained(this)),
+                       base::Unretained(this), sequence_number),
         timeout);
   }
 }
 
-void PowerModeArbiter::UpdatePendingResets() {
-  // Note: This method may run at any point. Do not assume that there are any
-  // resets that have expired, or that any other UpdatePendingResets() task is
-  // scheduled.
+void PowerModeArbiter::UpdatePendingResets(int sequence_number) {
+  // Note: This method may run at any point and on any thread. Do not assume
+  // that there are any resets that have expired, or that any other
+  // UpdatePendingResets() task is scheduled.
   bool did_change = false;
   base::TimeTicks now = base::TimeTicks::Now();
   base::TimeTicks next_task_time;
+  int next_sequence_number = 0;
   {
     base::AutoLock lock(lock_);
+
+    // Check if this task was cancelled and replaced by another one.
+    if (update_task_sequence_number_ != sequence_number)
+      return;
+
+    now = base::TimeTicks::Now();
     for (auto it = pending_resets_.begin(); it != pending_resets_.end();) {
       base::TimeTicks task_time = it->second;
       if (task_time <= now) {
@@ -204,13 +199,18 @@
         ++it;
       }
     }
+
     next_pending_vote_update_time_ = next_task_time;
+    if (!next_task_time.is_null()) {
+      ++update_task_sequence_number_;
+      next_sequence_number = update_task_sequence_number_;
+    }
   }
   if (!next_task_time.is_null()) {
     task_runner_->PostDelayedTask(
         FROM_HERE,
         base::BindOnce(&PowerModeArbiter::UpdatePendingResets,
-                       base::Unretained(this)),
+                       base::Unretained(this), next_sequence_number),
         next_task_time - now);
   }
   if (did_change)
diff --git a/components/power_scheduler/power_mode_arbiter.h b/components/power_scheduler/power_mode_arbiter.h
index 69cefe4e..809a1f1 100644
--- a/components/power_scheduler/power_mode_arbiter.h
+++ b/components/power_scheduler/power_mode_arbiter.h
@@ -9,6 +9,7 @@
 #include <memory>
 
 #include "base/component_export.h"
+#include "base/gtest_prod_util.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/no_destructor.h"
 #include "base/observer_list_threadsafe.h"
@@ -69,14 +70,21 @@
   PowerMode GetActiveModeForTesting();
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(PowerModeArbiterTest, ResetVoteAfterTimeout);
+
   class ChargingPowerModeVoter;
 
+  // Limits the frequency at which we can run the UpdatePendingResets() task.
+  // All pending resets are aligned to this time resolution.
+  static constexpr base::TimeDelta kResetVoteTimeResolution =
+      base::TimeDelta::FromMilliseconds(100);
+
   // PowerModeVoter::Delegate implementation:
   void OnVoterDestroyed(PowerModeVoter*) override;
   void SetVote(PowerModeVoter*, PowerMode) override;
   void ResetVoteAfterTimeout(PowerModeVoter*, base::TimeDelta timeout) override;
 
-  void UpdatePendingResets();
+  void UpdatePendingResets(int sequence_number);
   void OnVotesUpdated();
 
   PowerMode ComputeActiveModeLocked() EXCLUSIVE_LOCKS_REQUIRED(lock_);
@@ -94,6 +102,7 @@
       GUARDED_BY(lock_);
   base::TimeTicks next_pending_vote_update_time_ GUARDED_BY(lock_);
   TracedPowerMode active_mode_ GUARDED_BY(lock_);
+  int update_task_sequence_number_ GUARDED_BY(lock_) = 0;
 
   // Owned by the arbiter but otherwise behaves like a regular voter.
   std::unique_ptr<ChargingPowerModeVoter> charging_voter_;
diff --git a/components/power_scheduler/power_mode_arbiter_unittest.cc b/components/power_scheduler/power_mode_arbiter_unittest.cc
index eb394e7..57740c53 100644
--- a/components/power_scheduler/power_mode_arbiter_unittest.cc
+++ b/components/power_scheduler/power_mode_arbiter_unittest.cc
@@ -148,6 +148,12 @@
 TEST(PowerModeArbiterTest, ResetVoteAfterTimeout) {
   base::test::TaskEnvironment env(
       base::test::TaskEnvironment::TimeSource::MOCK_TIME);
+
+  // Align the mock clock with the phase of the reset tasks.
+  base::TimeTicks target_time = env.NowTicks().SnappedToNextTick(
+      base::TimeTicks(), PowerModeArbiter::kResetVoteTimeResolution);
+  env.AdvanceClock(target_time - env.NowTicks());
+
   PowerModeArbiter arbiter;
 
   base::TimeDelta delta1s = base::TimeDelta::FromSeconds(1);
@@ -211,6 +217,20 @@
   env.FastForwardBy(delta1s);  // Execute the second reset task.
   EXPECT_EQ(arbiter.GetActiveModeForTesting(), PowerMode::kIdle);
 
+  // Unaligned reset timeouts get aligned to the resolution.
+  voter1->VoteFor(PowerMode::kAnimation);
+  voter2->VoteFor(PowerMode::kCharging);
+  EXPECT_EQ(arbiter.GetActiveModeForTesting(), PowerMode::kCharging);
+  voter2->ResetVoteAfterTimeout(PowerModeArbiter::kResetVoteTimeResolution / 3);
+  voter1->ResetVoteAfterTimeout(PowerModeArbiter::kResetVoteTimeResolution / 2);
+  base::TimeDelta first_half = PowerModeArbiter::kResetVoteTimeResolution / 2;
+  env.FastForwardBy(first_half);
+  // No change, since the timeouts were aligned to kResetVoteTimeResolution.
+  EXPECT_EQ(arbiter.GetActiveModeForTesting(), PowerMode::kCharging);
+  // Executes the resets.
+  env.FastForwardBy(PowerModeArbiter::kResetVoteTimeResolution - first_half);
+  EXPECT_EQ(arbiter.GetActiveModeForTesting(), PowerMode::kIdle);
+
   // If the voter is destroyed, the task doesn't cause crashes.
   voter1->VoteFor(PowerMode::kAnimation);
   voter1->ResetVoteAfterTimeout(delta1s);
diff --git a/components/prefs/pref_service.cc b/components/prefs/pref_service.cc
index e15c2d5..4c3ee88 100644
--- a/components/prefs/pref_service.cc
+++ b/components/prefs/pref_service.cc
@@ -559,20 +559,10 @@
     return value;
   }
 
-  // TODO(crbug.com/859477): Remove once root cause has been found.
-  if (value && value->type() != type) {
-    DEBUG_ALIAS_FOR_CSTR(path_copy, path.c_str(), 1024);
-    base::debug::DumpWithoutCrashing();
-  }
-
   // If no user preference of the correct type exists, clone default value.
   const base::Value* default_value = nullptr;
   pref_registry_->defaults()->GetValue(path, &default_value);
-  // TODO(crbug.com/859477): Revert to DCHECK once root cause has been found.
-  if (default_value->type() != type) {
-    DEBUG_ALIAS_FOR_CSTR(path_copy, path.c_str(), 1024);
-    base::debug::DumpWithoutCrashing();
-  }
+  DCHECK_EQ(default_value->type(), type);
   user_pref_store_->SetValueSilently(path, default_value->CreateDeepCopy(),
                                      GetWriteFlags(pref));
   user_pref_store_->GetMutableValue(path, &value);
diff --git a/components/safe_browsing/content/web_ui/safe_browsing_ui.cc b/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
index dd3eee458e..ee3c2a7 100644
--- a/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
+++ b/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
@@ -1545,6 +1545,44 @@
     request_dict.SetStringKey("tab_url", tab_url.spec());
   }
 
+  if (request.has_client_metadata()) {
+    base::DictionaryValue metadata;
+
+    if (request.client_metadata().has_browser()) {
+      const auto& browser = request.client_metadata().browser();
+      base::DictionaryValue browser_metadata;
+      browser_metadata.SetStringKey("browser_id", browser.browser_id());
+      browser_metadata.SetStringKey("user_agent", browser.user_agent());
+      browser_metadata.SetStringKey("chrome_version", browser.chrome_version());
+      browser_metadata.SetStringKey("machine_user", browser.machine_user());
+      metadata.SetKey("browser", std::move(browser_metadata));
+    }
+
+    if (request.client_metadata().has_device()) {
+      base::DictionaryValue device_metadata;
+      const auto& device = request.client_metadata().device();
+      device_metadata.SetStringKey("dm_token", device.dm_token());
+      device_metadata.SetStringKey("client_id", device.client_id());
+      device_metadata.SetStringKey("os_version", device.os_version());
+      device_metadata.SetStringKey("os_platform", device.os_platform());
+      device_metadata.SetStringKey("name", device.name());
+      metadata.SetKey("device", std::move(device_metadata));
+    }
+
+    if (request.client_metadata().has_profile()) {
+      base::DictionaryValue profile_metadata;
+      const auto& profile = request.client_metadata().profile();
+      profile_metadata.SetStringKey("dm_token", profile.dm_token());
+      profile_metadata.SetStringKey("gaia_email", profile.gaia_email());
+      profile_metadata.SetStringKey("profile_path", profile.profile_path());
+      profile_metadata.SetStringKey("profile_name", profile.profile_name());
+      profile_metadata.SetStringKey("client_id", profile.client_id());
+      metadata.SetKey("profile", std::move(profile_metadata));
+    }
+
+    request_dict.SetKey("client_metadata", std::move(metadata));
+  }
+
   base::ListValue tags;
   for (const std::string& tag : request.tags())
     tags.Append(base::Value(tag));
diff --git a/components/ui_devtools/viz/dom_agent_viz.cc b/components/ui_devtools/viz/dom_agent_viz.cc
index 543b9cee..35631be 100644
--- a/components/ui_devtools/viz/dom_agent_viz.cc
+++ b/components/ui_devtools/viz/dom_agent_viz.cc
@@ -107,7 +107,7 @@
   DestroyElementAndRemoveSubtree(it->second.get());
 }
 
-// TODO(sgilhuly): Add support for elements to have multiple parents. Currently,
+// TODO(rivr): Add support for elements to have multiple parents. Currently,
 // when a reference is added to a surface, the SurfaceElement is moved to be a
 // child of only its most recent referrer. When a reference is removed from a
 // surface, this is ignored unless the reference is to the SurfaceElement's
@@ -151,7 +151,7 @@
   // happen when we have Surface A referencing Surface B, then we create
   // Surface C and ask it to reference Surface B. When A asks to remove
   // the reference to B, do nothing because B is already referenced by C.
-  // TODO(sgilhuly): Add support for elements to have multiple parents so this
+  // TODO(rivr): Add support for elements to have multiple parents so this
   // case can be correctly handled.
   UIElement* old_parent = child->parent();
   if (SurfaceElement::From(old_parent) != parent_id)
diff --git a/components/ui_devtools/viz/viz_devtools_unittest.cc b/components/ui_devtools/viz/viz_devtools_unittest.cc
index ce8472c..69d0791 100644
--- a/components/ui_devtools/viz/viz_devtools_unittest.cc
+++ b/components/ui_devtools/viz/viz_devtools_unittest.cc
@@ -417,7 +417,7 @@
 
 // Verify that a surface with multiple references is only a child of its most
 // recent referrer.
-// TODO(sgilhuly): This test follows the current behaviour of surfaces with
+// TODO(rivr): This test follows the current behaviour of surfaces with
 // multiple references, and should be changed if support for nodes to have
 // multiple parents is added.
 TEST_F(VizDevToolsTest, MultipleSurfaceReferences) {
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index ae09dd69..a424619 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -44,7 +44,7 @@
   }
 }
 
-# TODO(sgilhuly): To reduce link times, merge these context provider components
+# TODO(rivr): To reduce link times, merge these context provider components
 # into a single gr_context_provider component.
 if (is_mac) {
   viz_component("metal_context_provider") {
diff --git a/components/viz/common/gpu/dawn_context_provider.cc b/components/viz/common/gpu/dawn_context_provider.cc
index 2e54f91..d4004c1 100644
--- a/components/viz/common/gpu/dawn_context_provider.cc
+++ b/components/viz/common/gpu/dawn_context_provider.cc
@@ -38,7 +38,7 @@
 }
 
 DawnContextProvider::DawnContextProvider() {
-  // TODO(sgilhuly): This may return a GPU that is not the active one. Currently
+  // TODO(rivr): This may return a GPU that is not the active one. Currently
   // the only known way to avoid this is platform-specific; e.g. on Mac, create
   // a Dawn device, get the actual Metal device from it, and compare against
   // MTLCreateSystemDefaultDevice().
diff --git a/components/viz/service/display_embedder/skia_output_device_dawn.cc b/components/viz/service/display_embedder/skia_output_device_dawn.cc
index 0b25885..6673cfe 100644
--- a/components/viz/service/display_embedder/skia_output_device_dawn.cc
+++ b/components/viz/service/display_embedder/skia_output_device_dawn.cc
@@ -77,7 +77,7 @@
   CreateSwapChainImplementation();
   wgpu::SwapChainDescriptor desc;
   desc.implementation = reinterpret_cast<int64_t>(&swap_chain_implementation_);
-  // TODO(sgilhuly): Use a wgpu::Surface in this call once the Surface-based
+  // TODO(rivr): Use a wgpu::Surface in this call once the Surface-based
   // SwapChain API is ready.
   swap_chain_ = context_provider_->GetDevice().CreateSwapChain(nullptr, &desc);
   if (!swap_chain_)
@@ -98,7 +98,7 @@
   base::TimeTicks vsync_timebase;
   base::TimeDelta vsync_interval;
   uint32_t flags = 0;
-  // TODO(sgilhuly): Add an async path for getting vsync parameters. The sync
+  // TODO(rivr): Add an async path for getting vsync parameters. The sync
   // path is sufficient for VSyncProviderWin.
   if (vsync_provider_ && vsync_provider_->GetVSyncParametersIfAvailable(
                              &vsync_timebase, &vsync_interval)) {
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index 199491a..3c75af5 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -1488,7 +1488,7 @@
         GetDidSwapBuffersCompleteCallback());
   } else {
 #if defined(USE_X11) || defined(USE_OZONE_PLATFORM_X11)
-    // TODO(sgilhuly): Set up a Vulkan swapchain so that Linux can also use
+    // TODO(rivr): Set up a Vulkan swapchain so that Linux can also use
     // SkiaOutputDeviceDawn.
     if (MayFallBackToSkiaOutputDeviceX11()) {
       output_device_ = SkiaOutputDeviceX11::Create(
diff --git a/components/viz/test/fake_skia_output_surface.cc b/components/viz/test/fake_skia_output_surface.cc
index e6ae003..1982055 100644
--- a/components/viz/test/fake_skia_output_surface.cc
+++ b/components/viz/test/fake_skia_output_surface.cc
@@ -265,7 +265,7 @@
   }
 
   if (request->result_format() == CopyOutputResult::Format::RGBA_TEXTURE) {
-    // TODO(sgilhuly): This implementation is incomplete and doesn't copy
+    // TODO(rivr): This implementation is incomplete and doesn't copy
     // anything into the mailbox, but currently the only tests that use this
     // don't actually check the returned texture data.
     auto* sii = context_provider_->SharedImageInterface();
diff --git a/components/viz/test/test_gpu_service_holder.cc b/components/viz/test/test_gpu_service_holder.cc
index 7f03e44..9bf8044e 100644
--- a/components/viz/test/test_gpu_service_holder.cc
+++ b/components/viz/test/test_gpu_service_holder.cc
@@ -220,7 +220,7 @@
   gpu_feature_info.status_values[gpu::GPU_FEATURE_TYPE_OOP_RASTERIZATION] =
       gpu::kGpuFeatureStatusEnabled;
 
-  // TODO(sgilhuly): Investigate why creating a GPUInfo and GpuFeatureInfo from
+  // TODO(rivr): Investigate why creating a GPUInfo and GpuFeatureInfo from
   // the command line causes the test SkiaOutputSurfaceImplTest.SubmitPaint to
   // fail on Android.
   gpu_service_ = std::make_unique<GpuServiceImpl>(
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index e6d66b5..6ce6d19 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -793,6 +793,10 @@
   RunAriaTest(FILE_PATH_LITERAL("aria-generic.html"));
 }
 
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityAriaGlobal) {
+  RunAriaTest(FILE_PATH_LITERAL("aria-global.html"));
+}
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityAriaGrabbed) {
   RunAriaTest(FILE_PATH_LITERAL("aria-grabbed.html"));
 }
diff --git a/content/browser/android/java/gin_java_script_to_java_types_coercion.cc b/content/browser/android/java/gin_java_script_to_java_types_coercion.cc
index 2e72f74..dda75575 100644
--- a/content/browser/android/java/gin_java_script_to_java_types_coercion.cc
+++ b/content/browser/android/java/gin_java_script_to_java_types_coercion.cc
@@ -731,14 +731,9 @@
     case base::Value::Type::BINARY:
       return CoerceGinJavaBridgeValueToJavaValue(
           env, value, target_type, coerce_to_string, object_refs, error);
-    // TODO(crbug.com/859477): Remove after root cause is found.
-    case base::Value::Type::DEAD:
-      CHECK(false);
-      return jvalue();
   }
 
-  // TODO(crbug.com/859477): Revert to NOTREACHED() after root cause is found.
-  CHECK(false);
+  NOTREACHED();
   return jvalue();
 }
 
diff --git a/content/browser/compositor/viz_process_transport_factory.cc b/content/browser/compositor/viz_process_transport_factory.cc
index 2d80f842..b1d4cf3 100644
--- a/content/browser/compositor/viz_process_transport_factory.cc
+++ b/content/browser/compositor/viz_process_transport_factory.cc
@@ -495,7 +495,7 @@
 
   const auto& gpu_feature_info = gpu_channel_host->gpu_feature_info();
   // Fallback to software compositing if GPU compositing is blacklisted.
-  // TODO(sgilhuly): For now assume that if GL is blacklisted, then Vulkan is
+  // TODO(rivr): For now assume that if GL is blacklisted, then Vulkan is
   // also. Just check GL to see if GPU compositing is disabled.
   auto gpu_compositing_status =
       gpu_feature_info.status_values[gpu::GPU_FEATURE_TYPE_ACCELERATED_GL];
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index cc59a49e..2f29c71b 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -105,7 +105,7 @@
          "via blocklist or the command line."),
      true},
     {"gpu_compositing",
-     // TODO(sgilhuly): Replace with a check to see which backend is used for
+     // TODO(rivr): Replace with a check to see which backend is used for
      // compositing; do the same for GPU rasterization if it's enabled. For now
      // assume that if GL is blocklisted, then Vulkan is also. Check GL to see
      // if GPU compositing is disabled.
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index 4c67be38..d4a667b7 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -1110,7 +1110,7 @@
   if (gpu_mode_ == gpu::GpuMode::HARDWARE_VULKAN &&
       gpu_feature_info_.status_values[gpu::GPU_FEATURE_TYPE_VULKAN] !=
           gpu::GpuFeatureStatus::kGpuFeatureStatusEnabled) {
-    // TODO(sgilhuly): The GpuMode in GpuProcessHost will still be
+    // TODO(rivr): The GpuMode in GpuProcessHost will still be
     // HARDWARE_VULKAN. This isn't a big issue right now because both GPU modes
     // report to the same histogram. The first fallback will occur after 4
     // crashes, instead of 3.
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 9b18e1b5..b826594d0 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -137,7 +137,7 @@
 // Returns the UMA histogram name for the given GPU mode.
 const char* GetProcessLifetimeUmaName(gpu::GpuMode gpu_mode) {
   switch (gpu_mode) {
-    // TODO(sgilhuly): Add separate histograms for the different hardware modes.
+    // TODO(rivr): Add separate histograms for the different hardware modes.
     case gpu::GpuMode::HARDWARE_GL:
     case gpu::GpuMode::HARDWARE_METAL:
     case gpu::GpuMode::HARDWARE_VULKAN:
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue.cc b/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
index 513ee12..a792bd7 100644
--- a/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
+++ b/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
@@ -207,10 +207,6 @@
     bool needs_update = scroll_update.data.scroll_update.delta_x != 0 ||
                         scroll_update.data.scroll_update.delta_y != 0;
 
-    // For every GSU event record whether it is latched or not.
-    if (needs_update)
-      RecordLatchingUmaMetric(client_->IsWheelScrollInProgress());
-
     bool synthetic = event_sent_for_gesture_ack_->event.has_synthetic_phase;
 
     // Generally, there should always be a non-zero delta with kPhaseBegan
@@ -327,8 +323,4 @@
       scroll_begin, ui::LatencyInfo(ui::SourceEventType::WHEEL));
 }
 
-void MouseWheelEventQueue::RecordLatchingUmaMetric(bool latched) {
-  UMA_HISTOGRAM_BOOLEAN("WheelScrolling.WasLatched", latched);
-}
-
 }  // namespace content
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue.h b/content/browser/renderer_host/input/mouse_wheel_event_queue.h
index 3e4414b3..72804ad 100644
--- a/content/browser/renderer_host/input/mouse_wheel_event_queue.h
+++ b/content/browser/renderer_host/input/mouse_wheel_event_queue.h
@@ -112,7 +112,6 @@
   void SendScrollEnd(blink::WebGestureEvent update_event, bool synthetic);
   void SendScrollBegin(const blink::WebGestureEvent& gesture_update,
                        bool synthetic);
-  void RecordLatchingUmaMetric(bool latched);
 
   // True if gesture scroll events can be generated for the wheel event sent for
   // ack.
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc b/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
index d84e820..1ac2dce2 100644
--- a/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
+++ b/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/location.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
-#include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
@@ -669,26 +668,6 @@
   EXPECT_EQ(1U, GetAndResetSentEventCount());
 }
 
-TEST_F(MouseWheelEventQueueTest, WheelScrollingWasLatchedHistogramCheck) {
-  base::HistogramTester histogram_tester;
-  const char latching_histogram_name[] = "WheelScrolling.WasLatched";
-
-  SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
-                 kWheelScrollGlobalY, 1, 1, 0, false,
-                 WebMouseWheelEvent::kPhaseBegan,
-                 WebMouseWheelEvent::kPhaseNone);
-  SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
-  histogram_tester.ExpectBucketCount(latching_histogram_name, 0, 1);
-
-  SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
-                 kWheelScrollGlobalY, 1, 1, 0, false,
-                 WebMouseWheelEvent::kPhaseChanged,
-                 WebMouseWheelEvent::kPhaseNone);
-  SendMouseWheelEventAck(blink::mojom::InputEventResultState::kNotConsumed);
-  histogram_tester.ExpectBucketCount(latching_histogram_name, 0, 1);
-  histogram_tester.ExpectBucketCount(latching_histogram_name, 1, 1);
-}
-
 #if defined(OS_MAC)
 TEST_F(MouseWheelEventQueueTest, DoNotSwapXYForShiftScroll) {
   // Send an event with shift modifier, zero value for delta X, and no direction
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index a0e7d4a..a430e5d 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1496,10 +1496,10 @@
   } else if (gesture_event.GetType() ==
              blink::WebInputEvent::Type::kGestureFlingStart) {
     if (gesture_event.SourceDevice() == blink::WebGestureDevice::kTouchpad) {
-      // TODO(sahel): Remove the VR specific case when motion events are used
-      // for Android VR event processing and VR touchpad scrolling is handled by
-      // sending wheel events rather than directly injecting Gesture Scroll
-      // Events. https://crbug.com/797322
+      // TODO(crbug.com/797322): Remove the VR specific case when motion events
+      // are used for Android VR event processing and VR touchpad scrolling is
+      // handled by sending wheel events rather than directly injecting Gesture
+      // Scroll Events.
       if (GetView()->IsInVR()) {
         // Regardless of the state of the wheel scroll latching
         // WebContentsEventForwarder doesn't inject any GSE events before GFS.
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 3022023..9b5f90a 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -303,7 +303,7 @@
     "java/src/org/chromium/content/browser/selection/SelectionInsertionHandleObserver.java",
     "java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java",
     "java/src/org/chromium/content/browser/selection/SmartSelectionClient.java",
-    "java/src/org/chromium/content/browser/selection/SmartSelectionMetricsLogger.java",
+    "java/src/org/chromium/content/browser/selection/SmartSelectionEventProcessor.java",
     "java/src/org/chromium/content/browser/selection/SmartSelectionProvider.java",
     "java/src/org/chromium/content/browser/sms/SmsProviderGms.java",
     "java/src/org/chromium/content/browser/sms/SmsUserConsentReceiver.java",
@@ -350,7 +350,7 @@
     "java/src/org/chromium/content_public/browser/ScreenOrientationDelegate.java",
     "java/src/org/chromium/content_public/browser/ScreenOrientationProvider.java",
     "java/src/org/chromium/content_public/browser/SelectionClient.java",
-    "java/src/org/chromium/content_public/browser/SelectionMetricsLogger.java",
+    "java/src/org/chromium/content_public/browser/SelectionEventProcessor.java",
     "java/src/org/chromium/content_public/browser/SelectionPopupController.java",
     "java/src/org/chromium/content_public/browser/SmartClipProvider.java",
     "java/src/org/chromium/content_public/browser/SpeechRecognition.java",
@@ -613,7 +613,7 @@
     "junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectRegistryTest.java",
     "junit/src/org/chromium/content/browser/selection/MagnifierAnimatorTest.java",
     "junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java",
-    "junit/src/org/chromium/content/browser/selection/SmartSelectionMetricsLoggerTest.java",
+    "junit/src/org/chromium/content/browser/selection/SmartSelectionEventProcessorTest.java",
   ]
   deps = [
     ":content_java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java
index 8389943..615c785 100644
--- a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java
@@ -204,16 +204,28 @@
             // flag that indicates that we have kicked off starting the browser process.
             mHasStartedInitializingBrowserProcess = true;
             sShouldStartGpuProcessOnBrowserStartup = startGpuProcess;
-            prepareToStartBrowserProcess(false);
 
-            if (!mHasCalledContentStart) {
-                mCurrentBrowserStartType = startMinimalBrowser ? BrowserStartType.MINIMAL_BROWSER
-                                                               : BrowserStartType.FULL_BROWSER;
-                if (contentStart() > 0) {
-                    // Failed. The callbacks may not have run, so run them.
-                    enqueueCallbackExecution(STARTUP_FAILURE);
+            // Start-up at this point occurs before the first frame of the app is drawn. Although
+            // contentStart() can be called eagerly, deferring it would allow a frame to be drawn,
+            // so that Android reports Chrome to start before our SurfaceView has rendered. Our
+            // metrics have also adapted to this. Therefore we wrap contentStart() into Runnable,
+            // and let prepareToStartBrowserProcess() decide whether to defer it by a frame (in
+            // production) or not (overridden in tests). http://b/181151614#comment6
+            prepareToStartBrowserProcess(false, new Runnable() {
+                @Override
+                public void run() {
+                    ThreadUtils.assertOnUiThread();
+                    if (mHasCalledContentStart) return;
+                    mCurrentBrowserStartType = startMinimalBrowser
+                            ? BrowserStartType.MINIMAL_BROWSER
+                            : BrowserStartType.FULL_BROWSER;
+                    if (contentStart() > 0) {
+                        // Failed. The callbacks may not have run, so run them.
+                        enqueueCallbackExecution(STARTUP_FAILURE);
+                    }
                 }
-            }
+            });
+
         } else if (mMinimalBrowserStarted && mLaunchFullBrowserAfterMinimalBrowserStart) {
             // If we missed the minimalBrowserStarted() call, launch the full browser now if needed.
             // Otherwise, minimalBrowserStarted() will handle the full browser launch.
@@ -232,22 +244,18 @@
 
         // If already started skip to checking the result
         if (!mFullBrowserStartupDone) {
-            prepareToStartBrowserProcess(singleProcess);
+            // contentStart() need not be deferred, so passing null.
+            prepareToStartBrowserProcess(singleProcess, null /* deferrableTask */);
 
             boolean startedSuccessfully = true;
-            if (!mHasCalledContentStart) {
+            if (!mHasCalledContentStart
+                    || mCurrentBrowserStartType == BrowserStartType.MINIMAL_BROWSER) {
                 mCurrentBrowserStartType = BrowserStartType.FULL_BROWSER;
                 if (contentStart() > 0) {
                     // Failed. The callbacks may not have run, so run them.
                     enqueueCallbackExecution(STARTUP_FAILURE);
                     startedSuccessfully = false;
                 }
-            } else if (mCurrentBrowserStartType == BrowserStartType.MINIMAL_BROWSER) {
-                mCurrentBrowserStartType = BrowserStartType.FULL_BROWSER;
-                if (contentStart() > 0) {
-                    enqueueCallbackExecution(STARTUP_FAILURE);
-                    startedSuccessfully = false;
-                }
             }
             if (startedSuccessfully) {
                 flushStartupTasks();
@@ -422,7 +430,7 @@
     }
 
     @VisibleForTesting
-    void prepareToStartBrowserProcess(final boolean singleProcess) {
+    void prepareToStartBrowserProcess(final boolean singleProcess, final Runnable deferrableTask) {
         if (mPrepareToStartCompleted) {
             return;
         }
@@ -448,6 +456,10 @@
             DeviceUtilsImpl.addDeviceSpecificUserAgentSwitch();
             BrowserStartupControllerImplJni.get().setCommandLineFlags(singleProcess);
         }
+
+        if (deferrableTask != null) {
+            PostTask.postTask(UiThreadTaskTraits.USER_BLOCKING, deferrableTask);
+        }
     }
 
     /**
diff --git a/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
index 7b12e4d5..e597626e 100644
--- a/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
@@ -167,8 +167,8 @@
      */
     private SelectionClient mSelectionClient;
 
-    // SelectionMetricsLogger, could be null.
-    private SmartSelectionMetricsLogger mSelectionMetricsLogger;
+    @Nullable
+    private SmartSelectionEventProcessor mSmartSelectionEventProcessor;
 
     private PopupController mPopupController;
 
@@ -410,21 +410,21 @@
         mUnselectAllOnDismiss = true;
 
         if (hasSelection()) {
-            if (mSelectionMetricsLogger != null) {
+            if (mSmartSelectionEventProcessor != null) {
                 switch (sourceType) {
                     case MenuSourceType.MENU_SOURCE_ADJUST_SELECTION:
-                        mSelectionMetricsLogger.logSelectionModified(
+                        mSmartSelectionEventProcessor.onSelectionModified(
                                 mLastSelectedText, mLastSelectionOffset, mClassificationResult);
                         break;
                     case MenuSourceType.MENU_SOURCE_ADJUST_SELECTION_RESET:
-                        mSelectionMetricsLogger.logSelectionAction(mLastSelectedText,
+                        mSmartSelectionEventProcessor.onSelectionAction(mLastSelectedText,
                                 mLastSelectionOffset, SelectionEvent.ACTION_RESET,
                                 /* SelectionClient.Result = */ null);
                         break;
                     case MenuSourceType.MENU_SOURCE_TOUCH_HANDLE:
                         break;
                     default:
-                        mSelectionMetricsLogger.logSelectionStarted(
+                        mSmartSelectionEventProcessor.onSelectionStarted(
                                 mLastSelectedText, mLastSelectionOffset, isEditable);
                 }
             }
@@ -917,8 +917,8 @@
         int id = item.getItemId();
         int groupId = item.getGroupId();
 
-        if (hasSelection() && mSelectionMetricsLogger != null) {
-            mSelectionMetricsLogger.logSelectionAction(mLastSelectedText, mLastSelectionOffset,
+        if (hasSelection() && mSmartSelectionEventProcessor != null) {
+            mSmartSelectionEventProcessor.onSelectionAction(mLastSelectedText, mLastSelectionOffset,
                     getActionType(id, groupId), mClassificationResult);
         }
 
@@ -1441,9 +1441,9 @@
     /* package */ void onSelectionChanged(String text) {
         final boolean unSelected = TextUtils.isEmpty(text) && hasSelection();
         if (unSelected) {
-            if (mSelectionMetricsLogger != null) {
-                mSelectionMetricsLogger.logSelectionAction(mLastSelectedText, mLastSelectionOffset,
-                        SelectionEvent.ACTION_ABANDON,
+            if (mSmartSelectionEventProcessor != null) {
+                mSmartSelectionEventProcessor.onSelectionAction(mLastSelectedText,
+                        mLastSelectionOffset, SelectionEvent.ACTION_ABANDON,
                         /* SelectionClient.Result = */ null);
             }
             destroyActionModeAndKeepSelection();
@@ -1460,9 +1460,9 @@
     @Override
     public void setSelectionClient(@Nullable SelectionClient selectionClient) {
         mSelectionClient = selectionClient;
-        mSelectionMetricsLogger = mSelectionClient == null
+        mSmartSelectionEventProcessor = mSelectionClient == null
                 ? null
-                : (SmartSelectionMetricsLogger) mSelectionClient.getSelectionMetricsLogger();
+                : (SmartSelectionEventProcessor) mSelectionClient.getSelectionEventProcessor();
 
         mClassificationResult = null;
 
@@ -1573,8 +1573,8 @@
             // We won't do expansion here, however, we want to 1) for starting a new logging
             // session, log non selection expansion event to match the behavior of expansion case.
             // 2) log selection handle dragging triggered selection change.
-            if (mSelectionMetricsLogger != null) {
-                mSelectionMetricsLogger.logSelectionModified(
+            if (mSmartSelectionEventProcessor != null) {
+                mSmartSelectionEventProcessor.onSelectionModified(
                         mLastSelectedText, mLastSelectionOffset, mClassificationResult);
             }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionClient.java b/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionClient.java
index 6f95c03..ddba7fa 100644
--- a/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionClient.java
+++ b/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionClient.java
@@ -16,7 +16,7 @@
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.content_public.browser.SelectionClient;
-import org.chromium.content_public.browser.SelectionMetricsLogger;
+import org.chromium.content_public.browser.SelectionEventProcessor;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.touch_selection.SelectionEventType;
@@ -51,7 +51,7 @@
     private long mNativeSmartSelectionClient;
     private SmartSelectionProvider mProvider;
     private ResultCallback mCallback;
-    private SmartSelectionMetricsLogger mSmartSelectionMetricsLogger;
+    private SmartSelectionEventProcessor mSmartSelectionEventProcessor;
 
     /**
      * Creates the SmartSelectionClient. Returns null in case SmartSelectionProvider does not exist
@@ -71,11 +71,12 @@
 
     private SmartSelectionClient(ResultCallback callback, WebContents webContents) {
         assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
-        mProvider = new SmartSelectionProvider(callback, webContents);
         mCallback = callback;
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
-            mSmartSelectionMetricsLogger = SmartSelectionMetricsLogger.create(webContents);
+            mSmartSelectionEventProcessor = SmartSelectionEventProcessor.create(webContents);
         }
+        mProvider =
+                new SmartSelectionProvider(callback, webContents, mSmartSelectionEventProcessor);
         mNativeSmartSelectionClient =
                 SmartSelectionClientJni.get().init(SmartSelectionClient.this, webContents);
     }
@@ -115,8 +116,8 @@
     }
 
     @Override
-    public SelectionMetricsLogger getSelectionMetricsLogger() {
-        return mSmartSelectionMetricsLogger;
+    public SelectionEventProcessor getSelectionEventProcessor() {
+        return mSmartSelectionEventProcessor;
     }
 
     @Override
diff --git a/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionMetricsLogger.java b/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionEventProcessor.java
similarity index 89%
rename from content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionMetricsLogger.java
rename to content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionEventProcessor.java
index f7a7e63..06658ec 100644
--- a/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionMetricsLogger.java
+++ b/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionEventProcessor.java
@@ -12,17 +12,19 @@
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textclassifier.TextClassifier;
 
+import androidx.annotation.Nullable;
+
 import org.chromium.base.Log;
 import org.chromium.base.annotations.VerifiesOnP;
 import org.chromium.content.browser.WindowEventObserver;
 import org.chromium.content.browser.WindowEventObserverManager;
 import org.chromium.content_public.browser.SelectionClient;
-import org.chromium.content_public.browser.SelectionMetricsLogger;
+import org.chromium.content_public.browser.SelectionEventProcessor;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.WindowAndroid;
 
 /**
- * Smart Selection logger, wrapper of Android logger methods.
+ * Logs various selection events and manages the lifecycle of a text classifier session.
  * We are logging word indices here. For one example:
  *     New York City , NY
  *    -1   0    1    2 3  4
@@ -33,7 +35,7 @@
  */
 @VerifiesOnP
 @TargetApi(Build.VERSION_CODES.P)
-public class SmartSelectionMetricsLogger implements SelectionMetricsLogger {
+public class SmartSelectionEventProcessor implements SelectionEventProcessor {
     private static final String TAG = "SmartSelectionLogger";
     private static final boolean DEBUG = false;
 
@@ -44,14 +46,14 @@
 
     private SelectionIndicesConverter mConverter;
 
-    public static SmartSelectionMetricsLogger create(WebContents webContents) {
+    public static SmartSelectionEventProcessor create(WebContents webContents) {
         if (webContents.getTopLevelNativeWindow().getContext().get() == null) {
             return null;
         }
-        return new SmartSelectionMetricsLogger(webContents);
+        return new SmartSelectionEventProcessor(webContents);
     }
 
-    private SmartSelectionMetricsLogger(WebContents webContents) {
+    private SmartSelectionEventProcessor(WebContents webContents) {
         mWindowAndroid = webContents.getTopLevelNativeWindow();
         WindowEventObserverManager manager = WindowEventObserverManager.from(webContents);
         if (manager != null) {
@@ -64,7 +66,7 @@
         }
     }
 
-    public void logSelectionStarted(String selectionText, int startOffset, boolean editable) {
+    public void onSelectionStarted(String selectionText, int startOffset, boolean editable) {
         if (mWindowAndroid == null) return;
 
         Context context = mWindowAndroid.getContext().get();
@@ -79,7 +81,7 @@
         logEvent(SelectionEvent.createSelectionStartedEvent(SelectionEvent.INVOCATION_MANUAL, 0));
     }
 
-    public void logSelectionModified(
+    public void onSelectionModified(
             String selectionText, int startOffset, SelectionClient.Result result) {
         if (mSession == null) return;
         if (!mConverter.updateSelectionState(selectionText, startOffset)) {
@@ -108,7 +110,7 @@
         }
     }
 
-    public void logSelectionAction(
+    public void onSelectionAction(
             String selectionText, int startOffset, int action, SelectionClient.Result result) {
         if (mSession == null) {
             return;
@@ -167,4 +169,9 @@
     public void logEvent(SelectionEvent selectionEvent) {
         mSession.onSelectionEvent(selectionEvent);
     }
-}
+
+    @Nullable
+    public TextClassifier getTextClassifierSession() {
+        return mSession;
+    }
+}
\ No newline at end of file
diff --git a/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionProvider.java b/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionProvider.java
index cb93ef35..a560c38 100644
--- a/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionProvider.java
+++ b/content/public/android/java/src/org/chromium/content/browser/selection/SmartSelectionProvider.java
@@ -16,7 +16,9 @@
 import android.view.textclassifier.TextSelection;
 
 import androidx.annotation.IntDef;
+import androidx.annotation.Nullable;
 
+import org.chromium.base.Log;
 import org.chromium.base.task.AsyncTask;
 import org.chromium.content.browser.WindowEventObserver;
 import org.chromium.content.browser.WindowEventObserverManager;
@@ -47,9 +49,11 @@
 
     private Handler mHandler;
     private Runnable mFailureResponseRunnable;
+    @Nullable
+    private final SmartSelectionEventProcessor mSelectionEventProcessor;
 
-    public SmartSelectionProvider(
-            SelectionClient.ResultCallback callback, WebContents webContents) {
+    public SmartSelectionProvider(SelectionClient.ResultCallback callback, WebContents webContents,
+            @Nullable SmartSelectionEventProcessor selectionEventProcessor) {
         mResultCallback = callback;
         mWindowAndroid = webContents.getTopLevelNativeWindow();
         WindowEventObserverManager manager = WindowEventObserverManager.from(webContents);
@@ -69,6 +73,7 @@
                 mResultCallback.onClassified(new SelectionClient.Result());
             }
         };
+        mSelectionEventProcessor = selectionEventProcessor;
     }
 
     public void sendSuggestAndClassifyRequest(CharSequence text, int start, int end) {
@@ -117,9 +122,25 @@
     }
 
     @TargetApi(Build.VERSION_CODES.O)
+    private TextClassifier getTextClassificationSession() {
+        Context context = mWindowAndroid.getContext().get();
+        if (context == null) {
+            return null;
+        }
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P || mSelectionEventProcessor == null) {
+            return getTextClassifier();
+        }
+        TextClassifier textClassifierSession = mSelectionEventProcessor.getTextClassifierSession();
+        if (textClassifierSession == null || textClassifierSession.isDestroyed()) {
+            return getTextClassifier();
+        }
+        return textClassifierSession;
+    }
+
+    @TargetApi(Build.VERSION_CODES.O)
     private void sendSmartSelectionRequest(
             @RequestType int requestType, CharSequence text, int start, int end) {
-        TextClassifier classifier = getTextClassifier();
+        TextClassifier classifier = getTextClassificationSession();
         if (classifier == null || classifier == TextClassifier.NO_OP) {
             mHandler.post(mFailureResponseRunnable);
             return;
@@ -163,17 +184,27 @@
 
             TextSelection textSelection = null;
 
-            if (mRequestType == RequestType.SUGGEST_AND_CLASSIFY) {
-                textSelection = mTextClassifier.suggestSelection(
-                        mText, start, end, LocaleList.getAdjustedDefault());
-                start = Math.max(0, textSelection.getSelectionStartIndex());
-                end = Math.min(mText.length(), textSelection.getSelectionEndIndex());
-                if (isCancelled()) return new SelectionClient.Result();
-            }
+            try {
+                if (mRequestType == RequestType.SUGGEST_AND_CLASSIFY) {
+                    textSelection = mTextClassifier.suggestSelection(
+                            mText, start, end, LocaleList.getAdjustedDefault());
+                    start = Math.max(0, textSelection.getSelectionStartIndex());
+                    end = Math.min(mText.length(), textSelection.getSelectionEndIndex());
+                    if (isCancelled()) {
+                        return new SelectionClient.Result();
+                    }
+                }
 
-            TextClassification tc = mTextClassifier.classifyText(
-                    mText, start, end, LocaleList.getAdjustedDefault());
-            return makeResult(start, end, tc, textSelection);
+                TextClassification tc = mTextClassifier.classifyText(
+                        mText, start, end, LocaleList.getAdjustedDefault());
+                return makeResult(start, end, tc, textSelection);
+            } catch (IllegalStateException ex) {
+                // An IllegalStateException will be thrown if the text classifier session is
+                // destroyed. This could happen if the selection is ended before text classifier
+                // finishes processing the text.
+                Log.e(TAG, "Failed to use text classifier for smart selection", ex);
+                return new SelectionClient.Result();
+            }
         }
 
         private SelectionClient.Result makeResult(
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/SelectionClient.java b/content/public/android/java/src/org/chromium/content_public/browser/SelectionClient.java
index 1d7ed58..7c95bd3 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/SelectionClient.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/SelectionClient.java
@@ -128,9 +128,9 @@
     void cancelAllRequests();
 
     /**
-     * Returns a SelectionMetricsLogger associated with the SelectionClient or null.
+     * Returns a SelectionEventProcessor associated with the SelectionClient or null.
      */
-    default SelectionMetricsLogger getSelectionMetricsLogger() {
+    default SelectionEventProcessor getSelectionEventProcessor() {
         return null;
     }
 
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/SelectionMetricsLogger.java b/content/public/android/java/src/org/chromium/content_public/browser/SelectionEventProcessor.java
similarity index 85%
rename from content/public/android/java/src/org/chromium/content_public/browser/SelectionMetricsLogger.java
rename to content/public/android/java/src/org/chromium/content_public/browser/SelectionEventProcessor.java
index e1b88c9c..c0106c8 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/SelectionMetricsLogger.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/SelectionEventProcessor.java
@@ -7,4 +7,4 @@
 /**
  * Interface for selection event logging.
  */
-public interface SelectionMetricsLogger {}
+public interface SelectionEventProcessor {}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java
index 381a62a..23b1618d 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java
@@ -37,10 +37,13 @@
         private boolean mMinimalBrowserStarted;
 
         @Override
-        void prepareToStartBrowserProcess(boolean singleProcess) {
+        void prepareToStartBrowserProcess(boolean singleProcess, final Runnable deferrableTask) {
             if (!mLibraryLoadSucceeds) {
                 throw new ProcessInitException(LoaderErrors.NATIVE_LIBRARY_LOAD_FAILED);
             }
+            if (deferrableTask != null) {
+                deferrableTask.run();
+            }
         }
 
         private TestBrowserStartupController() {}
diff --git a/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java b/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java
index 26ebc23..c292fda 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java
@@ -53,7 +53,7 @@
 import org.chromium.content.browser.RenderWidgetHostViewImpl;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
 import org.chromium.content_public.browser.SelectionClient;
-import org.chromium.content_public.browser.SelectionMetricsLogger;
+import org.chromium.content_public.browser.SelectionEventProcessor;
 import org.chromium.content_public.browser.SelectionPopupController;
 import org.chromium.ui.base.MenuSourceType;
 import org.chromium.ui.base.ViewAndroidDelegate;
@@ -80,7 +80,7 @@
     private ViewAndroidDelegate mViewAndroidDelegate;
     private ActionMode mActionMode;
     private PackageManager mPackageManager;
-    private SmartSelectionMetricsLogger mLogger;
+    private SmartSelectionEventProcessor mLogger;
     private RenderWidgetHostViewImpl mRenderWidgetHostViewImpl;
     private RenderCoordinatesImpl mRenderCoordinates;
     private ContentResolver mContentResolver;
@@ -96,7 +96,7 @@
     private static class TestSelectionClient implements SelectionClient {
         private SelectionClient.Result mResult;
         private SelectionClient.ResultCallback mResultCallback;
-        private SmartSelectionMetricsLogger mLogger;
+        private SmartSelectionEventProcessor mLogger;
 
         @Override
         public void onSelectionChanged(String selection) {}
@@ -117,7 +117,7 @@
         public void cancelAllRequests() {}
 
         @Override
-        public SelectionMetricsLogger getSelectionMetricsLogger() {
+        public SelectionEventProcessor getSelectionEventProcessor() {
             return mLogger;
         }
 
@@ -129,7 +129,7 @@
             mResultCallback = callback;
         }
 
-        public void setLogger(SmartSelectionMetricsLogger logger) {
+        public void setLogger(SmartSelectionEventProcessor logger) {
             mLogger = logger;
         }
     }
@@ -156,7 +156,7 @@
         mPackageManager = Mockito.mock(PackageManager.class);
         mRenderWidgetHostViewImpl = Mockito.mock(RenderWidgetHostViewImpl.class);
         mRenderCoordinates = Mockito.mock(RenderCoordinatesImpl.class);
-        mLogger = Mockito.mock(SmartSelectionMetricsLogger.class);
+        mLogger = Mockito.mock(SmartSelectionEventProcessor.class);
         mPopupController = Mockito.mock(PopupController.class);
         mGestureStateListenerManager = Mockito.mock(GestureListenerManagerImpl.class);
 
@@ -387,7 +387,7 @@
         when(mView.startActionMode(any(FloatingActionModeCallback.class), anyInt()))
                 .thenReturn(mActionMode);
 
-        order.verify(mLogger).logSelectionStarted(AMPHITHEATRE, 5, true);
+        order.verify(mLogger).onSelectionStarted(AMPHITHEATRE, 5, true);
 
         mController.getResultCallback().onClassified(result);
 
@@ -398,7 +398,7 @@
                 /* canRichlyEdit = */ true, /* shouldSuggest = */ true,
                 MenuSourceType.MENU_SOURCE_ADJUST_SELECTION);
 
-        order.verify(mLogger).logSelectionModified(
+        order.verify(mLogger).onSelectionModified(
                 eq(AMPHITHEATRE_FULL), eq(0), isA(SelectionClient.Result.class));
 
         // Dragging selection handle, select "1600 Amphitheatre".
@@ -410,11 +410,11 @@
                 MenuSourceType.MENU_SOURCE_TOUCH_HANDLE);
 
         order.verify(mLogger, never())
-                .logSelectionModified(anyString(), anyInt(), any(SelectionClient.Result.class));
+                .onSelectionModified(anyString(), anyInt(), any(SelectionClient.Result.class));
 
         mController.getResultCallback().onClassified(resultForNoChange());
 
-        order.verify(mLogger).logSelectionModified(
+        order.verify(mLogger).onSelectionModified(
                 eq("1600 Amphitheatre"), eq(0), isA(SelectionClient.Result.class));
     }
 
@@ -440,11 +440,11 @@
 
         when(mView.startActionMode(any(FloatingActionModeCallback.class), anyInt()))
                 .thenReturn(mActionMode);
-        order.verify(mLogger).logSelectionStarted(AMPHITHEATRE, 5, true);
+        order.verify(mLogger).onSelectionStarted(AMPHITHEATRE, 5, true);
 
         // No expansion.
         mController.getResultCallback().onClassified(result);
-        order.verify(mLogger).logSelectionModified(
+        order.verify(mLogger).onSelectionModified(
                 eq(AMPHITHEATRE), eq(5), any(SelectionClient.Result.class));
 
         // Dragging selection handle, select "1600 Amphitheatre".
@@ -456,9 +456,9 @@
                 MenuSourceType.MENU_SOURCE_TOUCH_HANDLE);
 
         order.verify(mLogger, never())
-                .logSelectionModified(anyString(), anyInt(), any(SelectionClient.Result.class));
+                .onSelectionModified(anyString(), anyInt(), any(SelectionClient.Result.class));
         mController.getResultCallback().onClassified(resultForNoChange());
-        order.verify(mLogger).logSelectionModified(
+        order.verify(mLogger).onSelectionModified(
                 eq("1600 Amphitheatre"), eq(0), isA(SelectionClient.Result.class));
     }
 
diff --git a/content/public/android/junit/src/org/chromium/content/browser/selection/SmartSelectionMetricsLoggerTest.java b/content/public/android/junit/src/org/chromium/content/browser/selection/SmartSelectionEventProcessorTest.java
similarity index 89%
rename from content/public/android/junit/src/org/chromium/content/browser/selection/SmartSelectionMetricsLoggerTest.java
rename to content/public/android/junit/src/org/chromium/content/browser/selection/SmartSelectionEventProcessorTest.java
index 6466f227..e029d30 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/selection/SmartSelectionMetricsLoggerTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/selection/SmartSelectionEventProcessorTest.java
@@ -39,11 +39,11 @@
 import java.text.BreakIterator;
 
 /**
- * Unit tests for the {@link SmartSelectionMetricsLogger}.
+ * Unit tests for the {@link SmartSelectionEventProcessor}.
  */
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
-public class SmartSelectionMetricsLoggerTest {
+public class SmartSelectionEventProcessorTest {
     private WebContentsImpl mWebContents;
     private WindowAndroid mWindowAndroid;
 
@@ -318,25 +318,25 @@
     @Test
     @Feature({"TextInput", "SmartSelection"})
     public void testNormalLoggingFlow() {
-        SmartSelectionMetricsLogger logger = SmartSelectionMetricsLogger.create(mWebContents);
+        SmartSelectionEventProcessor logger = SmartSelectionEventProcessor.create(mWebContents);
         ArgumentCaptor<SelectionEvent> captor = ArgumentCaptor.forClass(SelectionEvent.class);
         InOrder inOrder = inOrder(mTextClassifier);
 
         // Start to select, selected "thou" in row#1.
-        logger.logSelectionStarted("thou", 30, /* editable = */ false);
+        logger.onSelectionStarted("thou", 30, /* editable = */ false);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         SelectionEvent selectionEvent = captor.getValue();
         assertSelectionStartedEvent(selectionEvent);
 
         // Smart Selection, expand to "Wherefore art thou Romeo?".
-        logger.logSelectionModified("Wherefore art thou Romeo?", 16, null);
+        logger.onSelectionModified("Wherefore art thou Romeo?", 16, null);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertEvent(selectionEvent, SelectionEvent.EVENT_SELECTION_MODIFIED, /*expectedStart=*/-2,
                 /*expectedEnd=*/3);
 
         // Smart Selection reset, to the last Romeo in row#1.
-        logger.logSelectionAction("Romeo", 35, SelectionEvent.ACTION_RESET, null);
+        logger.onSelectionAction("Romeo", 35, SelectionEvent.ACTION_RESET, null);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertEquals(SelectionEvent.ACTION_RESET, selectionEvent.getEventType());
@@ -344,40 +344,39 @@
                 /*expectedEnd=*/2);
 
         // User clear selection.
-        logger.logSelectionAction("Romeo", 35, SelectionEvent.ACTION_ABANDON, null);
+        logger.onSelectionAction("Romeo", 35, SelectionEvent.ACTION_ABANDON, null);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertEvent(selectionEvent, SelectionEvent.ACTION_ABANDON, /*expectedStart=*/1,
                 /*expectedEnd=*/2);
 
         // User start a new selection without abandon.
-        logger.logSelectionStarted("thou", 30, /* editable = */ false);
+        logger.onSelectionStarted("thou", 30, /* editable = */ false);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertSelectionStartedEvent(selectionEvent);
 
         // Smart Selection, expand to "Wherefore art thou Romeo?".
-        logger.logSelectionModified("Wherefore art thou Romeo?", 16, null);
+        logger.onSelectionModified("Wherefore art thou Romeo?", 16, null);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertEvent(selectionEvent, SelectionEvent.EVENT_SELECTION_MODIFIED, /*expectedStart=*/-2,
                 /*expectedEnd=*/3);
 
         // COPY, PASTE, CUT, SHARE, SMART_SHARE are basically the same.
-        logger.logSelectionAction(
-                "Wherefore art thou Romeo?", 16, SelectionEvent.ACTION_COPY, null);
+        logger.onSelectionAction("Wherefore art thou Romeo?", 16, SelectionEvent.ACTION_COPY, null);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertEvent(selectionEvent, SelectionEvent.ACTION_COPY, /*expectedStart=*/-2,
                 /*expectedEnd=*/3);
 
         // SELECT_ALL
-        logger.logSelectionStarted("thou", 30, /* editable = */ true);
+        logger.onSelectionStarted("thou", 30, /* editable = */ true);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertSelectionStartedEvent(selectionEvent);
 
-        logger.logSelectionAction(sText, 0, SelectionEvent.ACTION_SELECT_ALL, null);
+        logger.onSelectionAction(sText, 0, SelectionEvent.ACTION_SELECT_ALL, null);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertEvent(selectionEvent, SelectionEvent.ACTION_SELECT_ALL, /*expectedStart=*/-7,
@@ -387,39 +386,39 @@
     @Test
     @Feature({"TextInput", "SmartSelection"})
     public void testMultipleDrag() {
-        SmartSelectionMetricsLogger logger = SmartSelectionMetricsLogger.create(mWebContents);
+        SmartSelectionEventProcessor logger = SmartSelectionEventProcessor.create(mWebContents);
         ArgumentCaptor<SelectionEvent> captor = ArgumentCaptor.forClass(SelectionEvent.class);
         InOrder inOrder = inOrder(mTextClassifier);
 
         // Start new selection. First "Deny" in row#2.
-        logger.logSelectionStarted("Deny", 42, /* editable = */ false);
+        logger.onSelectionStarted("Deny", 42, /* editable = */ false);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         SelectionEvent selectionEvent = captor.getValue();
         assertSelectionStartedEvent(selectionEvent);
 
         // Drag right handle to "father".
-        logger.logSelectionModified("Deny thy father", 42, null);
+        logger.onSelectionModified("Deny thy father", 42, null);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertEvent(selectionEvent, SelectionEvent.EVENT_SELECTION_MODIFIED, /*expectedStart=*/0,
                 /*expectedEnd=*/3);
 
         // Drag left handle to " and refuse"
-        logger.logSelectionModified(" and refuse", 57, null);
+        logger.onSelectionModified(" and refuse", 57, null);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertEvent(selectionEvent, SelectionEvent.EVENT_SELECTION_MODIFIED, /*expectedStart=*/3,
                 /*expectedEnd=*/5);
 
         // Drag right handle to " Romeo?\nDeny thy father".
-        logger.logSelectionModified(" Romeo?\nDeny thy father", 34, null);
+        logger.onSelectionModified(" Romeo?\nDeny thy father", 34, null);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertEvent(selectionEvent, SelectionEvent.EVENT_SELECTION_MODIFIED, /*expectedStart=*/-2,
                 /*expectedEnd=*/3);
 
         // Dismiss the selection.
-        logger.logSelectionAction(
+        logger.onSelectionAction(
                 " Romeo?\nDeny thy father", 34, SelectionEvent.ACTION_ABANDON, null);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
@@ -427,7 +426,7 @@
                 /*expectedEnd=*/3);
 
         // Start a new selection.
-        logger.logSelectionStarted("Deny", 42, /* editable = */ false);
+        logger.onSelectionStarted("Deny", 42, /* editable = */ false);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertSelectionStartedEvent(selectionEvent);
@@ -436,40 +435,40 @@
     @Test
     @Feature({"TextInput", "SmartSelection"})
     public void testTextShift() {
-        SmartSelectionMetricsLogger logger = SmartSelectionMetricsLogger.create(mWebContents);
+        SmartSelectionEventProcessor logger = SmartSelectionEventProcessor.create(mWebContents);
         ArgumentCaptor<SelectionEvent> captor = ArgumentCaptor.forClass(SelectionEvent.class);
         InOrder inOrder = inOrder(mTextClassifier);
 
         // Start to select, selected "thou" in row#1.
-        logger.logSelectionStarted("thou", 30, /* editable = */ false);
+        logger.onSelectionStarted("thou", 30, /* editable = */ false);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         SelectionEvent selectionEvent = captor.getValue();
         assertSelectionStartedEvent(selectionEvent);
 
         // Smart Selection, expand to "Wherefore art thou Romeo?".
-        logger.logSelectionModified("Wherefore art thou Romeo?", 30, null);
+        logger.onSelectionModified("Wherefore art thou Romeo?", 30, null);
         inOrder.verify(mTextClassifier, never())
                 .onSelectionEvent(Mockito.any(SelectionEvent.class));
 
         // Start to select, selected "thou" in row#1.
-        logger.logSelectionStarted("thou", 30, /* editable = */ false);
+        logger.onSelectionStarted("thou", 30, /* editable = */ false);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertSelectionStartedEvent(selectionEvent);
 
         // Drag. Non-intersect case.
-        logger.logSelectionModified("Wherefore art thou", 10, null);
+        logger.onSelectionModified("Wherefore art thou", 10, null);
         inOrder.verify(mTextClassifier, never())
                 .onSelectionEvent(Mockito.any(SelectionEvent.class));
 
         // Start to select, selected "thou" in row#1.
-        logger.logSelectionStarted("thou", 30, /* editable = */ false);
+        logger.onSelectionStarted("thou", 30, /* editable = */ false);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertSelectionStartedEvent(selectionEvent);
 
         // Drag. Adjacent case, form "Wherefore art thouthou". Wrong case.
-        logger.logSelectionModified("Wherefore art thou", 12, null);
+        logger.onSelectionModified("Wherefore art thou", 12, null);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertEvent(selectionEvent, SelectionEvent.EVENT_SELECTION_MODIFIED, /*expectedStart=*/-3,
@@ -479,42 +478,42 @@
     @Test
     @Feature({"TextInput", "SmartSelection"})
     public void testSelectionChanged() {
-        SmartSelectionMetricsLogger logger = SmartSelectionMetricsLogger.create(mWebContents);
+        SmartSelectionEventProcessor logger = SmartSelectionEventProcessor.create(mWebContents);
         ArgumentCaptor<SelectionEvent> captor = ArgumentCaptor.forClass(SelectionEvent.class);
         InOrder inOrder = inOrder(mTextClassifier);
 
         // Start to select, selected "thou" in row#1.
-        logger.logSelectionStarted("thou", 30, /* editable = */ false);
+        logger.onSelectionStarted("thou", 30, /* editable = */ false);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         SelectionEvent selectionEvent = captor.getValue();
         assertSelectionStartedEvent(selectionEvent);
 
         // Change "thou" to "math".
-        logger.logSelectionModified("Wherefore art math", 16, null);
+        logger.onSelectionModified("Wherefore art math", 16, null);
         inOrder.verify(mTextClassifier, never())
                 .onSelectionEvent(Mockito.any(SelectionEvent.class));
 
         // Start to select, selected "thou" in row#1.
-        logger.logSelectionStarted("thou", 30, /* editable = */ false);
+        logger.onSelectionStarted("thou", 30, /* editable = */ false);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertSelectionStartedEvent(selectionEvent);
 
         // Drag while deleting "art ". Wrong case.
-        logger.logSelectionModified("Wherefore thou", 16, null);
+        logger.onSelectionModified("Wherefore thou", 16, null);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertEvent(selectionEvent, SelectionEvent.EVENT_SELECTION_MODIFIED, /*expectedStart=*/-2,
                 /*expectedEnd=*/0);
 
         // Start to select, selected "thou" in row#1.
-        logger.logSelectionStarted("thou", 30, /* editable = */ false);
+        logger.onSelectionStarted("thou", 30, /* editable = */ false);
         inOrder.verify(mTextClassifier).onSelectionEvent(captor.capture());
         selectionEvent = captor.getValue();
         assertSelectionStartedEvent(selectionEvent);
 
         // Drag while deleting "Wherefore art ".
-        logger.logSelectionModified("thou", 16, null);
+        logger.onSelectionModified("thou", 16, null);
         inOrder.verify(mTextClassifier, never())
                 .onSelectionEvent(Mockito.any(SelectionEvent.class));
     }
diff --git a/content/test/data/accessibility/aria/aria-generic-expected-blink.txt b/content/test/data/accessibility/aria/aria-generic-expected-blink.txt
index 4df640c..0efcf42 100644
--- a/content/test/data/accessibility/aria/aria-generic-expected-blink.txt
+++ b/content/test/data/accessibility/aria/aria-generic-expected-blink.txt
@@ -1,6 +1,6 @@
 rootWebArea
 ++genericContainer ignored
 ++++genericContainer ignored
-++++++genericContainer
+++++++genericContainer hasAriaAttribute=true
 ++++++++staticText name='content'
 ++++++++++inlineTextBox name='content'
diff --git a/content/test/data/accessibility/aria/aria-generic.html b/content/test/data/accessibility/aria/aria-generic.html
index 99c0a67..4281fa5 100644
--- a/content/test/data/accessibility/aria/aria-generic.html
+++ b/content/test/data/accessibility/aria/aria-generic.html
@@ -1,3 +1,6 @@
+<!--
+@BLINK-ALLOW:hasAriaAttribute=true
+-->
 <!DOCTYPE html>
 <html>
 <body>
diff --git a/content/test/data/accessibility/aria/aria-global-expected-blink.txt b/content/test/data/accessibility/aria/aria-global-expected-blink.txt
new file mode 100644
index 0000000..072c7184
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-global-expected-blink.txt
@@ -0,0 +1,38 @@
+rootWebArea
+++genericContainer ignored
+++++genericContainer ignored
+++++++group hasAriaAttribute=true
+++++++group hasAriaAttribute=true
+++++++group hasAriaAttribute=true
+++++++group hasAriaAttribute=true
+++++++group hasAriaAttribute=true
+++++++group hasAriaAttribute=true
+++++++group hasAriaAttribute=true
+++++++group hasAriaAttribute=true
+++++++group hasAriaAttribute=true
+++++++group hasAriaAttribute=true
+++++++group hasAriaAttribute=true
+++++++group ignored invisible
+++++++group hasAriaAttribute=true
+++++++group hasAriaAttribute=true
+++++++group hasAriaAttribute=true
+++++++group hasAriaAttribute=true
+++++++group hasAriaAttribute=true
+++++++splitter horizontal
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer ignored invisible
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer hasAriaAttribute=true
+++++++genericContainer hasAriaAttribute=true
diff --git a/content/test/data/accessibility/aria/aria-global.html b/content/test/data/accessibility/aria/aria-global.html
new file mode 100644
index 0000000..e80c477
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-global.html
@@ -0,0 +1,41 @@
+<!--
+@BLINK-DENY:*=*
+@BLINK-ALLOW:hasAriaAttribute=true
+-->
+<!-- Global properties force role="presentation"/"none" to be exposed with its native role -->
+<fieldset role="presentation" aria-atomic="X"></fieldset>
+<fieldset role="presentation" aria-busy="X"></fieldset>
+<fieldset role="presentation" aria-controls="X"></fieldset>
+<fieldset role="presentation" aria-current="X"></fieldset>
+<fieldset role="presentation" aria-describedby="X"></fieldset>
+<fieldset role="presentation" aria-description="X"></fieldset>
+<fieldset role="presentation" aria-details="X"></fieldset>
+<fieldset role="presentation" aria-dropeffect="X"></fieldset>
+<fieldset role="presentation" aria-flowto="X"></fieldset>
+<fieldset role="presentation" aria-grabbed="X"></fieldset>
+<fieldset role="presentation" aria-hidden="false"></fieldset>  <!-- Include -->
+<fieldset role="presentation" aria-hidden="true"></fieldset>  <!-- Don't include -->
+<fieldset role="presentation" aria-keyshortcuts="X"></fieldset>
+<fieldset role="presentation" aria-live="X"></fieldset>
+<fieldset role="presentation" aria-owns="X"></fieldset>
+<fieldset role="presentation" aria-relevant="X"></fieldset>
+<fieldset role="presentation" aria-roledescription="X"></fieldset>
+<hr>
+<!-- Global properties force role="presentation" to be exposed where they otherwise wouldn't have been -->
+<div role="presentation" aria-atomic="X"></div>
+<div role="presentation" aria-busy="X"></div>
+<div role="presentation" aria-controls="X"></div>
+<div role="presentation" aria-current="X"></div>
+<div role="presentation" aria-describedby="X"></div>
+<div role="presentation" aria-description="X"></div>
+<div role="presentation" aria-details="X"></div>
+<div role="presentation" aria-dropeffect="X"></div>
+<div role="presentation" aria-flowto="X"></div>
+<div role="presentation" aria-grabbed="X"></div>
+<div role="presentation" aria-hidden="false"></div>  <!-- Include -->
+<div role="presentation" aria-hidden="true"></div>  <!-- Don't include -->
+<div role="presentation" aria-keyshortcuts="X"></div>
+<div role="presentation" aria-live="X"></div>
+<div role="presentation" aria-owns="X"></div>
+<div role="presentation" aria-relevant="X"></div>
+<div role="presentation" aria-roledescription="X"></div>
diff --git a/content/test/gpu/gpu_tests/gpu_helper.py b/content/test/gpu/gpu_tests/gpu_helper.py
index 06b10eb..dd8a62b 100644
--- a/content/test/gpu/gpu_tests/gpu_helper.py
+++ b/content/test/gpu/gpu_tests/gpu_helper.py
@@ -168,7 +168,7 @@
     return None
 
 
-# TODO(sgilhuly): Use GPU feature status for Dawn instead of command line.
+# TODO(rivr): Use GPU feature status for Dawn instead of command line.
 def HasDawnSkiaRenderer(extra_browser_args):
   if extra_browser_args:
     for arg in extra_browser_args:
diff --git a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
index e134b66..dd814680 100644
--- a/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
+++ b/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
@@ -14,7 +14,6 @@
 import org.chromium.base.annotations.JNIAdditionalImport;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
-import org.chromium.base.metrics.RecordHistogram;
 
 import java.util.HashMap;
 
@@ -132,22 +131,12 @@
                 @Override
                 public void run() {
                     if (newState == android.bluetooth.BluetoothProfile.STATE_CONNECTED) {
-                        RecordHistogram.recordSparseHistogram(
-                                "Bluetooth.Web.Android.onConnectionStateChange.Status.Connected",
-                                status);
                         mBluetoothGatt.discoverServices();
                     } else if (newState == android.bluetooth.BluetoothProfile.STATE_DISCONNECTED) {
-                        RecordHistogram.recordSparseHistogram(
-                                "Bluetooth.Web.Android.onConnectionStateChange.Status.Disconnected",
-                                status);
                         if (mBluetoothGatt != null) {
                             mBluetoothGatt.close();
                             mBluetoothGatt = null;
                         }
-                    } else {
-                        RecordHistogram.recordSparseHistogram(
-                                "Bluetooth.Web.Android.onConnectionStateChange.Status.InvalidState",
-                                status);
                     }
                     if (mNativeBluetoothDeviceAndroid != 0) {
                         ChromeBluetoothDeviceJni.get().onConnectionStateChange(
@@ -169,15 +158,8 @@
                         // When the device disconnects it deletes
                         // mBluetoothGatt, so we need to check it's not null.
                         if (mBluetoothGatt == null) {
-                            RecordHistogram.recordSparseHistogram(
-                                    "Bluetooth.Web.Android.onServicesDiscovered.Status."
-                                            + "Disconnected",
-                                    status);
                             return;
                         }
-                        RecordHistogram.recordSparseHistogram(
-                                "Bluetooth.Web.Android.onServicesDiscovered.Status.Connected",
-                                status);
 
                         // TODO(crbug.com/576906): Update or replace existing GATT objects if they
                         //                         change after initial discovery.
@@ -235,8 +217,6 @@
                         // when the event races object destruction.
                         Log.v(TAG, "onCharacteristicRead when chromeCharacteristic == null.");
                     } else {
-                        RecordHistogram.recordSparseHistogram(
-                                "Bluetooth.Web.Android.onCharacteristicRead.Status", status);
                         chromeCharacteristic.onCharacteristicRead(status);
                     }
                 }
@@ -257,8 +237,6 @@
                         // when the event races object destruction.
                         Log.v(TAG, "onCharacteristicWrite when chromeCharacteristic == null.");
                     } else {
-                        RecordHistogram.recordSparseHistogram(
-                                "Bluetooth.Web.Android.onCharacteristicWrite.Status", status);
                         chromeCharacteristic.onCharacteristicWrite(status);
                     }
                 }
@@ -278,8 +256,6 @@
                         // when the event races object destruction.
                         Log.v(TAG, "onDescriptorRead when chromeDescriptor == null.");
                     } else {
-                        RecordHistogram.recordSparseHistogram(
-                                "Bluetooth.Web.Android.onDescriptorRead.Status", status);
                         chromeDescriptor.onDescriptorRead(status);
                     }
                 }
@@ -299,8 +275,6 @@
                         // when the event races object destruction.
                         Log.v(TAG, "onDescriptorWrite when chromeDescriptor == null.");
                     } else {
-                        RecordHistogram.recordSparseHistogram(
-                                "Bluetooth.Web.Android.onDescriptorWrite.Status", status);
                         chromeDescriptor.onDescriptorWrite(status);
                     }
                 }
diff --git a/docs/clang_tidy.md b/docs/clang_tidy.md
index 2cf7aab..24e9ff28 100644
--- a/docs/clang_tidy.md
+++ b/docs/clang_tidy.md
@@ -197,6 +197,15 @@
 your own `clang-apply-replacements` binary if you want to use the `-fix` option
 noted below.
 
+**Note:** If you're on a system that offers a clang tools through its package
+manager (e.g., on Debian/Ubuntu, `sudo apt-get install clang-tidy clang-tools`),
+you might not need an LLVM checkout to make the required binaries and scripts
+(`clang-tidy`, `run-clang-tidy` and `clang-apply-replacements`) available in
+your `$PATH`. However, the system packaged binaries might be several versions
+behind Chromium's toolchain, so not all flags are guaranteed to work. If this is
+a problem, consider building clang-tidy from the same revision the current
+toolchain is using, rather than filing a bug against the toolchain component.
+
 Running clang-tidy is (hopefully) simple.
 1.  Build chrome normally.
 ```
diff --git a/docs/mac/triage.md b/docs/mac/triage.md
index b71a1b8e..e819865d 100644
--- a/docs/mac/triage.md
+++ b/docs/mac/triage.md
@@ -160,7 +160,7 @@
 * UI>Browser>WebUI
 
 [unconfirmed]: https://bugs.chromium.org/p/chromium/issues/list?q=OS%3DMac%20status%3AUnconfirmed%20-component%3ABlink%2CEnterprise%2CInternals%3ENetwork%2CPlatform%3EDevtools%2CServices%3ESyncs%2CUI%3EBrowser%3EPasswords%20-label%3AMac-TriageBypass&can=2
-[untriaged-m]: https://bugs.chromium.org/p/chromium/issues/list?q=has%3AMac%20status%3AUntriaged&can=2
+[untriaged-m]: https://bugs.chromium.org/p/chromium/issues/list?q=has%3AMac%20status%3AUntriaged%20-label%3AMac-TriageBypass&can=2
 [untriaged-c]: https://bugs.chromium.org/p/chromium/issues/list?q=OS%3DMac%20-OS%3DWindows%2CLinux%2CChrome%2CAndroid%2CiOS%20status%3AUntriaged%20-component%3AAdmin%2CBlink%2CInfra%2CInternals%3ECast%2CInternals%3EHeadless%2CInternals%3ENetwork%2CInternals%3EPlugins%3EPDF%2CInternals%3EPrinting%2CInternals%3ESkia%2CInternals%3EUpdater%2CInternals%3EViews%2CIO%3EBluetooth%2CIO%3EUSB%2CPlatform%2CServices%3EChromoting%2CTest%3ETelemetry%2CUI%3EBrowser%3EWebAppInstalls%2CPlatform%3EWebAppProvider%2CUI%3EBrowser%3EWebUI%20-label%3AMac-TriageBypass&can=2
 [available]: https://bugs.chromium.org/p/chromium/issues/list?q=has%3AMac%20status%3AAvailable&can=2
 [assigned]: https://bugs.chromium.org/p/chromium/issues/list?q=has%3AMac%20status%3AAssigned&can=2
diff --git a/fuchsia/cast_streaming/test/cast_streaming_test_sender.cc b/fuchsia/cast_streaming/test/cast_streaming_test_sender.cc
index e8b68b5..c1899e15 100644
--- a/fuchsia/cast_streaming/test/cast_streaming_test_sender.cc
+++ b/fuchsia/cast_streaming/test/cast_streaming_test_sender.cc
@@ -83,7 +83,8 @@
   sender_session_ = std::make_unique<openscreen::cast::SenderSession>(
       openscreen::cast::SenderSession::Configuration{
           openscreen::IPAddress::kV6LoopbackAddress(), this, &environment_,
-          message_port_.get(), kSenderId, kReceiverId, true});
+          message_port_.get(), kSenderId, kReceiverId,
+          true /* use_android_rtp_hack */});
 
   std::vector<openscreen::cast::AudioCaptureConfig> audio_configs;
   if (audio_config) {
diff --git a/ios/chrome/browser/ui/browser_view/BUILD.gn b/ios/chrome/browser/ui/browser_view/BUILD.gn
index 4f7963e..2451cc98 100644
--- a/ios/chrome/browser/ui/browser_view/BUILD.gn
+++ b/ios/chrome/browser/ui/browser_view/BUILD.gn
@@ -34,6 +34,7 @@
     "//components/signin/ios/browser:active_state_manager",
     "//components/strings",
     "//components/translate/core/browser",
+    "//components/ukm/ios:ukm_url_recorder",
     "//components/url_formatter",
     "//ios/chrome/app:tests_hook",
     "//ios/chrome/app/application_delegate:app_state_header",
@@ -198,6 +199,7 @@
     "//ios/web/public",
     "//ios/web/public/deprecated",
     "//ios/web/public/deprecated:deprecated_web_util",
+    "//services/metrics/public/cpp:ukm_builders",
     "//ui/base",
     "//ui/gfx",
     "//url",
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 7835383..5dddf66 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -29,6 +29,7 @@
 #import "components/signin/ios/browser/manage_accounts_delegate.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/translate/core/browser/translate_manager.h"
+#include "components/ukm/ios/ukm_url_recorder.h"
 #import "ios/chrome/app/application_delegate/app_state.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
@@ -195,6 +196,7 @@
 #import "ios/web/public/ui/crw_web_view_proxy.h"
 #import "ios/web/public/web_state_delegate_bridge.h"
 #import "ios/web/public/web_state_observer_bridge.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
 #include "ui/base/device_form_factor.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -2851,10 +2853,21 @@
 #pragma mark - Private Methods: Reading List
 
 - (void)addToReadingListURL:(const GURL&)URL title:(NSString*)title {
-  base::RecordAction(UserMetricsAction("MobileReadingListAdd"));
-
   ReadingListModel* readingModel =
       ReadingListModelFactory::GetForBrowserState(self.browserState);
+  if (self.currentWebState &&
+      self.currentWebState->GetVisibleURL().spec() == URL.spec()) {
+    // Log UKM if the current page is being added to Reading List.
+    ukm::SourceId sourceID =
+        ukm::GetSourceIdForWebStateDocument(self.currentWebState);
+    if (sourceID != ukm::kInvalidSourceId) {
+      ukm::builders::IOS_PageAddedToReadingList(sourceID)
+          .SetAddedFromMessages(false)
+          .Record(ukm::UkmRecorder::Get());
+    }
+  }
+  base::RecordAction(UserMetricsAction("MobileReadingListAdd"));
+
   readingModel->AddEntry(URL, base::SysNSStringToUTF8(title),
                          reading_list::ADDED_VIA_CURRENT_APP);
 
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
index 251f8422..2923f937 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
@@ -58,7 +58,7 @@
 
 // Height for the shrunk logo frame.
 // TODO(crbug.com/1170491): clean up post-launch.
-const CGFloat kGoogleSearchLogoShrunkHeight = 34;
+const CGFloat kGoogleSearchLogoShrunkHeight = 36;
 
 // Height for the doodle frame when Google is not the default search engine.
 const CGFloat kNonGoogleSearchDoodleHeight = 60;
@@ -99,7 +99,7 @@
       topInset +
       AlignValueToPixel(kDoodleScaledTopMarginOther *
                         ui_util::SystemSuggestedFontSizeMultiplier());
-  if (ShouldShrinkLogoForStartSurface()) {
+  if (ShouldShrinkLogoForStartSurface() && !IsCompactHeight(traitCollection)) {
     topMargin += kShrunkDoodleTopMarginOther;
   } else {
     topMargin += kDoodleTopMarginOther;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm
index 058c2726..815096f1 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm
@@ -190,7 +190,7 @@
       doodleTopMargin(YES, kTopInset, IPhoneLandscapeTraitCollection());
   EXPECT_EQ(68, heightLogoLandscape);
   EXPECT_EQ(60, heightNoLogoLandscape);
-  EXPECT_EQ(95, topMarginLandscape);
+  EXPECT_EQ(78, topMarginLandscape);
 
   // Portrait
   CGFloat heightLogoPortrait =
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm
index 40d18881..3fa5c6f12 100644
--- a/ios/chrome/browser/ui/main/scene_controller.mm
+++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -546,23 +546,25 @@
 // TODO(crbug.com/1173160): Split and move to the StartSurfaceSceneAgent after
 // refactoring the scene states.
 - (void)handleShowStartSurfaceIfNecessary {
+  if (!ShouldShowStartSurfaceForSceneState(self.sceneState)) {
+    return;
+  }
+
   // Do not show the Start Surface no matter whether it is enabled or not when
   // the Tab grid is active by design.
   if (self.mainCoordinator.isTabGridActive) {
     return;
   }
 
+  // If there is no active tab, a NTP will be added, and since there is no
+  // recent tab, there is not need to mark |modifytVisibleNTPForStartSurface|.
   // Keep showing the last active NTP tab no matter whether the Start Surface is
   // enabled or not by design.
   // Note that currentWebState could only be nullptr when the Tab grid is active
   // for now.
   web::WebState* currentWebState =
-      self.currentInterface.browser->GetWebStateList()->GetActiveWebState();
-  if (IsURLNtp(currentWebState->GetVisibleURL())) {
-    return;
-  }
-
-  if (!ShouldShowStartSurfaceForSceneState(self.sceneState)) {
+      self.mainInterface.browser->GetWebStateList()->GetActiveWebState();
+  if (!currentWebState || IsURLNtp(currentWebState->GetVisibleURL())) {
     return;
   }
 
@@ -880,6 +882,12 @@
     [self setCurrentInterfaceForMode:ApplicationMode::NORMAL];
   }
 
+  // Call this right after |setCurrentInterfaceForMode:| to ensure the
+  // currentInterface is set in case a new tab needs to be opened. Since this is
+  // synchronous with |setActivePage:| above, then the user should not see the
+  // last tab if the Start Surface is opened.
+  [self handleShowStartSurfaceIfNecessary];
+
   // Figure out what UI to show initially.
 
   if (self.mainCoordinator.isTabGridActive) {
diff --git a/ios/chrome/browser/ui/start_surface/BUILD.gn b/ios/chrome/browser/ui/start_surface/BUILD.gn
index 2103ac22..ec545b75 100644
--- a/ios/chrome/browser/ui/start_surface/BUILD.gn
+++ b/ios/chrome/browser/ui/start_surface/BUILD.gn
@@ -44,3 +44,24 @@
     "//ui/base",
   ]
 }
+
+source_set("eg2_tests") {
+  defines = [ "CHROME_EARL_GREY_2" ]
+  configs += [
+    "//build/config/compiler:enable_arc",
+    "//build/config/ios:xctest_config",
+  ]
+  testonly = true
+
+  sources = [ "start_surface_egtest.mm" ]
+
+  deps = [
+    ":feature_flags",
+    "//ios/chrome/test/earl_grey:eg_test_support+eg2",
+    "//ios/testing/earl_grey:eg_test_support+eg2",
+    "//ios/third_party/earl_grey2:test_lib",
+    "//net:test_support",
+  ]
+
+  frameworks = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_egtest.mm b/ios/chrome/browser/ui/start_surface/start_surface_egtest.mm
new file mode 100644
index 0000000..e1f1fe93
--- /dev/null
+++ b/ios/chrome/browser/ui/start_surface/start_surface_egtest.mm
@@ -0,0 +1,58 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <XCTest/XCTest.h>
+
+#import "ios/chrome/browser/ui/start_surface/start_surface_features.h"
+#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
+#import "ios/chrome/test/earl_grey/chrome_matchers.h"
+#import "ios/chrome/test/earl_grey/chrome_test_case.h"
+#import "ios/testing/earl_grey/app_launch_manager.h"
+#include "ios/testing/earl_grey/earl_grey_test.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// Integration tests for the Start Surface user flows.
+@interface StartSurfaceTestCase : ChromeTestCase
+@end
+
+@implementation StartSurfaceTestCase
+
+- (AppLaunchConfiguration)appConfigurationForTestCase {
+  AppLaunchConfiguration config;
+  config.additional_args.push_back(
+      std::string("--enable-features=StartSurface:"
+                  "ReturnToStartSurfaceInactiveDurationInSeconds/0"));
+  config.relaunch_policy = ForceRelaunchByCleanShutdown;
+  return config;
+}
+
+// Tests that navigating to a page and restarting upon cold start, an NTP page
+// is opened.
+- (void)testColdStartOpenStartSurface {
+  // TODO(crbug.com/1198227): Reenable this test when the session saving issue
+  // is resolved.
+  if ([ChromeEarlGrey isIPadIdiom]) {
+    EARL_GREY_TEST_SKIPPED(@"Skipped for iPad (Session saving issue)");
+  }
+
+  GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
+  const GURL destinationUrl = self.testServer->GetURL("/pony.html");
+  [ChromeEarlGrey loadURL:destinationUrl];
+
+  [[AppLaunchManager sharedManager]
+      ensureAppLaunchedWithConfiguration:self.appConfigurationForTestCase];
+
+  [ChromeTestCase removeAnyOpenMenusAndInfoBars];
+  // Assert NTP is visible by checking that the fake omnibox is here.
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::FakeOmnibox()]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  GREYAssertEqual([ChromeEarlGrey mainTabCount], 2,
+                  @"Two tabs were expected to be open");
+}
+
+@end
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_scene_agent.mm b/ios/chrome/browser/ui/start_surface/start_surface_scene_agent.mm
index cb611e03..c613cc24 100644
--- a/ios/chrome/browser/ui/start_surface/start_surface_scene_agent.mm
+++ b/ios/chrome/browser/ui/start_surface/start_surface_scene_agent.mm
@@ -19,6 +19,7 @@
     // TODO(crbug.com/1173160): Consider when to clear the session object since
     // Chrome may be closed without transiting to background, e.g. device power
     // off, then the previous session object is staled.
+    NSLog(@"%@", [NSThread callStackSymbols]);
     SetStartSurfaceSessionObjectForSceneState(sceneState);
   }
 }
diff --git a/ios/chrome/browser/url_loading/scene_url_loading_service.mm b/ios/chrome/browser/url_loading/scene_url_loading_service.mm
index 2dc0d06..9a20818 100644
--- a/ios/chrome/browser/url_loading/scene_url_loading_service.mm
+++ b/ios/chrome/browser/url_loading/scene_url_loading_service.mm
@@ -51,9 +51,9 @@
 
       PrefService* prefs = browser_state->GetPrefs();
       // Don't open the url in below situations:
-      // 1. When the url is suppused to be opened in an incognito tab, but the
+      // 1. When the url is supposed to be opened in an incognito tab, but the
       // incognito mode is disabled by policy.
-      // 2. When the url is suppused to be opened in a normal tab, but the
+      // 2. When the url is supposed to be opened in a normal tab, but the
       // normal mode is disabled by policy.
       if ((params.in_incognito && IsIncognitoModeDisabled(prefs)) ||
           (!params.in_incognito && IsIncognitoModeForced(prefs))) {
diff --git a/ios/chrome/test/earl_grey2/BUILD.gn b/ios/chrome/test/earl_grey2/BUILD.gn
index 91343c1..905ab4c 100644
--- a/ios/chrome/test/earl_grey2/BUILD.gn
+++ b/ios/chrome/test/earl_grey2/BUILD.gn
@@ -168,6 +168,7 @@
     "//ios/chrome/browser/ui/safe_mode:eg2_tests",
     "//ios/chrome/browser/ui/settings/sync/utils:eg2_tests",
     "//ios/chrome/browser/ui/side_swipe:eg2_tests",
+    "//ios/chrome/browser/ui/start_surface:eg2_tests",
     "//ios/chrome/browser/ui/tab_switcher/tab_grid:eg2_tests",
     "//ios/chrome/browser/ui/tabs:eg2_tests",
     "//ios/chrome/browser/ui/thumb_strip:eg2_tests",
diff --git a/ios/third_party/webkit/run-clusterfuzz.sh b/ios/third_party/webkit/run-clusterfuzz.sh
index e0fd5603..6d63b67f 100755
--- a/ios/third_party/webkit/run-clusterfuzz.sh
+++ b/ios/third_party/webkit/run-clusterfuzz.sh
@@ -5,5 +5,9 @@
 #
 # This script is used to launch WebKitTestRunner on ClusterFuzz bots.
 
+rm -rf "$HOME/Library/Application Support/DumpRenderTree"
+
 BASEDIR=$(dirname "$0")
 DYLD_FRAMEWORK_PATH=$BASEDIR DYLD_LIBRARY_PATH=$BASEDIR ./WebKitTestRunner $@
+
+rm -rf "$HOME/Library/Application Support/DumpRenderTree"
diff --git a/mojo/public/cpp/base/values_mojom_traits.h b/mojo/public/cpp/base/values_mojom_traits.h
index e7c6fa6..feb3780 100644
--- a/mojo/public/cpp/base/values_mojom_traits.h
+++ b/mojo/public/cpp/base/values_mojom_traits.h
@@ -86,13 +86,8 @@
         return mojo_base::mojom::ValueDataView::Tag::DICTIONARY_VALUE;
       case base::Value::Type::LIST:
         return mojo_base::mojom::ValueDataView::Tag::LIST_VALUE;
-      // TODO(crbug.com/859477): Remove after root cause is found.
-      case base::Value::Type::DEAD:
-        CHECK(false);
-        return mojo_base::mojom::ValueDataView::Tag::NULL_VALUE;
     }
-    // TODO(crbug.com/859477): Revert to NOTREACHED() after root cause is found.
-    CHECK(false);
+    NOTREACHED();
     return mojo_base::mojom::ValueDataView::Tag::NULL_VALUE;
   }
 
diff --git a/net/android/network_change_notifier_delegate_android.cc b/net/android/network_change_notifier_delegate_android.cc
index d5a6a83..4da7d80 100644
--- a/net/android/network_change_notifier_delegate_android.cc
+++ b/net/android/network_change_notifier_delegate_android.cc
@@ -94,7 +94,7 @@
 }
 
 NetworkChangeNotifierDelegateAndroid::~NetworkChangeNotifierDelegateAndroid() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   observers_->AssertEmpty();
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_NetworkChangeNotifier_removeNativeObserver(
@@ -109,7 +109,7 @@
 
 NetworkChangeNotifier::ConnectionSubtype
 NetworkChangeNotifierDelegateAndroid::GetCurrentConnectionSubtype() const {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   return ConvertConnectionSubtype(
       Java_NetworkChangeNotifier_getCurrentConnectionSubtype(
           base::android::AttachCurrentThread(), java_network_change_notifier_));
@@ -153,7 +153,7 @@
     const JavaParamRef<jobject>& obj,
     jint new_connection_type,
     jlong default_netid) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   const ConnectionType actual_connection_type = ConvertConnectionType(
       new_connection_type);
   SetCurrentConnectionType(actual_connection_type);
@@ -191,7 +191,7 @@
 
 jint NetworkChangeNotifierDelegateAndroid::GetConnectionType(JNIEnv*,
                                                              jobject) const {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   return GetCurrentConnectionType();
 }
 
@@ -199,7 +199,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     jint subtype) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   double new_max_bandwidth =
       NetworkChangeNotifierAndroid::GetMaxBandwidthMbpsForConnectionSubtype(
           ConvertConnectionSubtype(subtype));
@@ -213,7 +213,7 @@
     const JavaParamRef<jobject>& obj,
     jlong net_id,
     jint connection_type) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   NetworkHandle network = net_id;
   bool already_exists;
   {
@@ -236,7 +236,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     jlong net_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   NetworkHandle network = net_id;
   {
     base::AutoLock auto_lock(connection_lock_);
@@ -250,7 +250,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     jlong net_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   NetworkHandle network = net_id;
   {
     base::AutoLock auto_lock(connection_lock_);
@@ -266,7 +266,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     const JavaParamRef<jlongArray>& active_networks) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   NetworkList active_network_list;
   base::android::JavaLongArrayToInt64Vector(env, active_networks,
                                             &active_network_list);
diff --git a/net/android/network_change_notifier_delegate_android.h b/net/android/network_change_notifier_delegate_android.h
index c537f45..e4f98331 100644
--- a/net/android/network_change_notifier_delegate_android.h
+++ b/net/android/network_change_notifier_delegate_android.h
@@ -162,7 +162,7 @@
   void FakeDefaultNetwork(NetworkHandle network, ConnectionType type);
   void FakeConnectionSubtypeChanged(ConnectionSubtype subtype);
 
-  base::ThreadChecker thread_checker_;
+  THREAD_CHECKER(thread_checker_);
   scoped_refptr<base::ObserverListThreadSafe<Observer>> observers_;
   const base::android::ScopedJavaGlobalRef<jobject>
       java_network_change_notifier_;
diff --git a/pdf/ppapi_migration/value_conversions.cc b/pdf/ppapi_migration/value_conversions.cc
index c0b894ea..60bb8ba 100644
--- a/pdf/ppapi_migration/value_conversions.cc
+++ b/pdf/ppapi_migration/value_conversions.cc
@@ -50,10 +50,6 @@
       }
       return var_array;
     }
-    // TODO(crbug.com/859477): Remove after root cause is found.
-    case base::Value::Type::DEAD:
-      CHECK(false);
-      return pp::Var();
   }
 }
 
diff --git a/ppapi/shared_impl/private/ppb_x509_certificate_private_shared.cc b/ppapi/shared_impl/private/ppb_x509_certificate_private_shared.cc
index 984a29c..f76d9f5 100644
--- a/ppapi/shared_impl/private/ppb_x509_certificate_private_shared.cc
+++ b/ppapi/shared_impl/private/ppb_x509_certificate_private_shared.cc
@@ -73,8 +73,6 @@
     }
     case base::Value::Type::DICTIONARY:
     case base::Value::Type::LIST:
-    // TODO(crbug.com/859477): Remove after root cause is found.
-    case base::Value::Type::DEAD:
       // Not handled.
       break;
   }
diff --git a/printing/backend/cups_ipp_helper_unittest.cc b/printing/backend/cups_ipp_helper_unittest.cc
index 3a1fb8b..ba55bd27 100644
--- a/printing/backend/cups_ipp_helper_unittest.cc
+++ b/printing/backend/cups_ipp_helper_unittest.cc
@@ -21,7 +21,7 @@
 
 class MockCupsOptionProvider : public CupsOptionProvider {
  public:
-  ~MockCupsOptionProvider() override {}
+  ~MockCupsOptionProvider() override = default;
 
   ipp_attribute_t* GetSupportedOptionValues(
       const char* option_name) const override {
@@ -340,7 +340,7 @@
   PrinterSemanticCapsAndDefaults caps;
   CapsAndDefaultsFromPrinter(*printer_, &caps);
 
-  EXPECT_EQ(6u, caps.advanced_capabilities.size());
+  ASSERT_EQ(6u, caps.advanced_capabilities.size());
   EXPECT_EQ("confirmation-sheet-print", caps.advanced_capabilities[0].name);
   EXPECT_EQ(AdvancedCapability::Type::kBoolean,
             caps.advanced_capabilities[0].type);
@@ -354,8 +354,12 @@
   EXPECT_EQ(AdvancedCapability::Type::kString,
             caps.advanced_capabilities[3].type);
   EXPECT_EQ("output-bin", caps.advanced_capabilities[4].name);
+  EXPECT_EQ(AdvancedCapability::Type::kString,
+            caps.advanced_capabilities[4].type);
   EXPECT_EQ(2u, caps.advanced_capabilities[4].values.size());
   EXPECT_EQ("print-quality", caps.advanced_capabilities[5].name);
+  EXPECT_EQ(AdvancedCapability::Type::kString,
+            caps.advanced_capabilities[5].type);
   EXPECT_EQ(3u, caps.advanced_capabilities[5].values.size());
   histograms.ExpectUniqueSample("Printing.CUPS.IppAttributesCount", 5, 1);
 }
diff --git a/printing/backend/mojom/print_backend_mojom_traits_unittest.cc b/printing/backend/mojom/print_backend_mojom_traits_unittest.cc
index 1457d63..ceca119 100644
--- a/printing/backend/mojom/print_backend_mojom_traits_unittest.cc
+++ b/printing/backend/mojom/print_backend_mojom_traits_unittest.cc
@@ -17,80 +17,73 @@
 
 namespace {
 
-const printing::PrinterSemanticCapsAndDefaults::Paper kPaperA3{
+const PrinterSemanticCapsAndDefaults::Paper kPaperA3{
     /*display_name=*/"A3", /*vendor_id=*/"67",
     /*size_um=*/gfx::Size(7016, 9921)};
-const printing::PrinterSemanticCapsAndDefaults::Paper kPaperA4{
+const PrinterSemanticCapsAndDefaults::Paper kPaperA4{
     /*display_name=*/"A4", /*vendor_id=*/"12",
     /*size_um=*/gfx::Size(4961, 7016)};
-const printing::PrinterSemanticCapsAndDefaults::Paper kPaperLetter{
+const PrinterSemanticCapsAndDefaults::Paper kPaperLetter{
     /*display_name=*/"Letter", /*vendor_id=*/"45",
     /*size_um=*/gfx::Size(5100, 6600)};
-const printing::PrinterSemanticCapsAndDefaults::Paper kPaperLedger{
+const PrinterSemanticCapsAndDefaults::Paper kPaperLedger{
     /*display_name=*/"Ledger", /*vendor_id=*/"89",
     /*size_um=*/gfx::Size(6600, 10200)};
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-const printing::AdvancedCapability kAdvancedCapability1(
+const AdvancedCapability kAdvancedCapability1(
     /*name=*/"advanced_cap_bool",
     /*display_name=*/"Advanced Capability #1 (bool)",
-    /*type=*/printing::AdvancedCapability::Type::kBoolean,
+    /*type=*/AdvancedCapability::Type::kBoolean,
     /*default_value=*/"true",
-    /*values=*/std::vector<printing::AdvancedCapabilityValue>());
-const printing::AdvancedCapability kAdvancedCapability2(
+    /*values=*/{});
+const AdvancedCapability kAdvancedCapability2(
     /*name=*/"advanced_cap_double",
     /*display_name=*/"Advanced Capability #2 (double)",
-    /*type=*/printing::AdvancedCapability::Type::kFloat,
+    /*type=*/AdvancedCapability::Type::kFloat,
     /*default_value=*/"3.14159",
     /*values=*/
-    std::vector<printing::AdvancedCapabilityValue>{
-        printing::AdvancedCapabilityValue(
+    {
+        AdvancedCapabilityValue(
             /*name=*/"adv_cap_val_1",
             /*display_name=*/"Advanced Capability #1"),
-        printing::AdvancedCapabilityValue(
+        AdvancedCapabilityValue(
             /*name=*/"adv_cap_val_2",
             /*display_name=*/"Advanced Capability #2"),
-        printing::AdvancedCapabilityValue(
+        AdvancedCapabilityValue(
             /*name=*/"adv_cap_val_3",
             /*display_name=*/"Advanced Capability #3"),
     });
-const printing::AdvancedCapabilities kAdvancedCapabilities{
-    kAdvancedCapability1, kAdvancedCapability2};
+const AdvancedCapabilities kAdvancedCapabilities{kAdvancedCapability1,
+                                                 kAdvancedCapability2};
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-static constexpr bool kCollateCapable = true;
-static constexpr bool kCollateDefault = true;
-static constexpr int kCopiesMax = 123;
-const std::vector<printing::mojom::DuplexMode> kDuplexModes{
-    printing::mojom::DuplexMode::kSimplex,
-    printing::mojom::DuplexMode::kLongEdge,
-    printing::mojom::DuplexMode::kShortEdge};
-static constexpr printing::mojom::DuplexMode kDuplexDefault =
-    printing::mojom::DuplexMode::kSimplex;
-static constexpr bool kColorChangeable = true;
-static constexpr bool kColorDefault = true;
-static constexpr printing::mojom::ColorModel kColorModel =
-    printing::mojom::ColorModel::kRGB;
-static constexpr printing::mojom::ColorModel kBwModel =
-    printing::mojom::ColorModel::kGrayscale;
-const printing::PrinterSemanticCapsAndDefaults::Papers kPapers{kPaperA4,
-                                                               kPaperLetter};
-const printing::PrinterSemanticCapsAndDefaults::Papers kUserDefinedPapers{
-    kPaperA3, kPaperLedger};
-const printing::PrinterSemanticCapsAndDefaults::Paper kDefaultPaper =
-    kPaperLetter;
-static constexpr gfx::Size kDpi600(600, 600);
-static constexpr gfx::Size kDpi1200(1200, 1200);
-static constexpr gfx::Size kDpi1200x600(1200, 600);
+constexpr bool kCollateCapable = true;
+constexpr bool kCollateDefault = true;
+constexpr int kCopiesMax = 123;
+const std::vector<mojom::DuplexMode> kDuplexModes{
+    mojom::DuplexMode::kSimplex, mojom::DuplexMode::kLongEdge,
+    mojom::DuplexMode::kShortEdge};
+constexpr mojom::DuplexMode kDuplexDefault = mojom::DuplexMode::kSimplex;
+constexpr bool kColorChangeable = true;
+constexpr bool kColorDefault = true;
+constexpr mojom::ColorModel kColorModel = mojom::ColorModel::kRGB;
+constexpr mojom::ColorModel kBwModel = mojom::ColorModel::kGrayscale;
+const PrinterSemanticCapsAndDefaults::Papers kPapers{kPaperA4, kPaperLetter};
+const PrinterSemanticCapsAndDefaults::Papers kUserDefinedPapers{kPaperA3,
+                                                                kPaperLedger};
+const PrinterSemanticCapsAndDefaults::Paper kDefaultPaper = kPaperLetter;
+constexpr gfx::Size kDpi600(600, 600);
+constexpr gfx::Size kDpi1200(1200, 1200);
+constexpr gfx::Size kDpi1200x600(1200, 600);
 const std::vector<gfx::Size> kDpis{kDpi600, kDpi1200, kDpi1200x600};
-static constexpr gfx::Size kDefaultDpi = kDpi600;
+constexpr gfx::Size kDefaultDpi = kDpi600;
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-static constexpr bool kPinSupported = true;
+constexpr bool kPinSupported = true;
 #endif
 
-printing::PrinterSemanticCapsAndDefaults
-GenerateSamplePrinterSemanticCapsAndDefaults() {
-  printing::PrinterSemanticCapsAndDefaults caps;
+PrinterSemanticCapsAndDefaults GenerateSamplePrinterSemanticCapsAndDefaults() {
+  PrinterSemanticCapsAndDefaults caps;
 
   caps.collate_capable = kCollateCapable;
   caps.collate_default = kCollateDefault;
@@ -117,75 +110,72 @@
 }  // namespace
 
 TEST(PrintBackendMojomTraitsTest, TestSerializeAndDeserializePrinterBasicInfo) {
-  static const printing::PrinterBasicInfo kPrinterBasicInfo1(
+  static const PrinterBasicInfo kPrinterBasicInfo1(
       /*printer_name=*/"test printer name 1",
       /*display_name=*/"test display name 1",
       /*printer_description=*/"This is printer #1 for unit testing.",
       /*printer_status=*/0,
       /*is_default=*/true,
-      /*options=*/
-      std::map<std::string, std::string>{{"opt1", "123"}, {"opt2", "456"}});
-  static const printing::PrinterBasicInfo kPrinterBasicInfo2(
+      /*options=*/{{"opt1", "123"}, {"opt2", "456"}});
+  static const PrinterBasicInfo kPrinterBasicInfo2(
       /*printer_name=*/"test printer name 2",
       /*display_name=*/"test display name 2",
       /*printer_description=*/"This is printer #2 for unit testing.",
       /*printer_status=*/1,
       /*is_default=*/false,
-      /*options=*/std::map<std::string, std::string>{});
-  static const printing::PrinterBasicInfo kPrinterBasicInfo3(
+      /*options=*/{});
+  static const PrinterBasicInfo kPrinterBasicInfo3(
       /*printer_name=*/"test printer name 2",
       /*display_name=*/"test display name 2",
       /*printer_description=*/"",
       /*printer_status=*/9,
       /*is_default=*/false,
-      /*options=*/std::map<std::string, std::string>{});
+      /*options=*/{});
   static const PrinterList kPrinterList{kPrinterBasicInfo1, kPrinterBasicInfo2,
                                         kPrinterBasicInfo3};
 
-  for (auto info : kPrinterList) {
-    printing::PrinterBasicInfo input = info;
-    printing::PrinterBasicInfo output;
-    EXPECT_TRUE(
-        mojo::test::SerializeAndDeserialize<printing::mojom::PrinterBasicInfo>(
-            input, output));
+  for (const auto& info : kPrinterList) {
+    PrinterBasicInfo input = info;
+    PrinterBasicInfo output;
+    EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::PrinterBasicInfo>(
+        input, output));
     EXPECT_EQ(info, output);
   }
 }
 
 TEST(PrintBackendMojomTraitsTest,
      TestSerializeAndDeserializePrinterBasicInfoEmptyNames) {
-  static const printing::PrinterBasicInfo kPrinterBasicInfoEmptyPrinterName(
+  static const PrinterBasicInfo kPrinterBasicInfoEmptyPrinterName(
       /*printer_name=*/"",
       /*display_name=*/"test display name",
       /*printer_description=*/"",
       /*printer_status=*/0,
       /*is_default=*/true,
-      /*options=*/std::map<std::string, std::string>{});
-  static const printing::PrinterBasicInfo kPrinterBasicInfoEmptyDisplayName(
+      /*options=*/{});
+  static const PrinterBasicInfo kPrinterBasicInfoEmptyDisplayName(
       /*printer_name=*/"test printer name",
       /*display_name=*/"",
       /*printer_description=*/"",
       /*printer_status=*/0,
       /*is_default=*/true,
-      /*options=*/std::map<std::string, std::string>{});
+      /*options=*/{});
   static const PrinterList kPrinterList{kPrinterBasicInfoEmptyPrinterName,
                                         kPrinterBasicInfoEmptyDisplayName};
 
-  for (auto info : kPrinterList) {
-    printing::PrinterBasicInfo input = info;
-    printing::PrinterBasicInfo output;
-    EXPECT_FALSE(
-        mojo::test::SerializeAndDeserialize<printing::mojom::PrinterBasicInfo>(
-            input, output));
+  for (const auto& info : kPrinterList) {
+    PrinterBasicInfo input = info;
+    PrinterBasicInfo output;
+    EXPECT_FALSE(mojo::test::SerializeAndDeserialize<mojom::PrinterBasicInfo>(
+        input, output));
   }
 }
 
 TEST(PrintBackendMojomTraitsTest, TestSerializeAndDeserializePaper) {
   for (const auto& paper : kPapers) {
-    printing::PrinterSemanticCapsAndDefaults::Paper input = paper;
-    printing::PrinterSemanticCapsAndDefaults::Paper output;
-    EXPECT_TRUE(mojo::test::SerializeAndDeserialize<printing::mojom::Paper>(
-        input, output));
+    PrinterSemanticCapsAndDefaults::Paper input = paper;
+    PrinterSemanticCapsAndDefaults::Paper output;
+    EXPECT_TRUE(
+        mojo::test::SerializeAndDeserialize<mojom::Paper>(input, output));
     EXPECT_EQ(paper, output);
   }
 }
@@ -194,10 +184,10 @@
 TEST(PrintBackendMojomTraitsTest,
      TestSerializeAndDeserializeAdvancedCapability) {
   for (const auto& advanced_capability : kAdvancedCapabilities) {
-    printing::AdvancedCapability input = advanced_capability;
-    printing::AdvancedCapability output;
-    EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
-                printing::mojom::AdvancedCapability>(input, output));
+    AdvancedCapability input = advanced_capability;
+    AdvancedCapability output;
+    EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::AdvancedCapability>(
+        input, output));
     EXPECT_EQ(advanced_capability, output);
   }
 }
@@ -205,12 +195,12 @@
 
 TEST(PrintBackendMojomTraitsTest,
      TestSerializeAndDeserializePrinterSemanticCapsAndDefaults) {
-  printing::PrinterSemanticCapsAndDefaults input =
+  PrinterSemanticCapsAndDefaults input =
       GenerateSamplePrinterSemanticCapsAndDefaults();
-  printing::PrinterSemanticCapsAndDefaults output;
+  PrinterSemanticCapsAndDefaults output;
 
   EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
-              printing::mojom::PrinterSemanticCapsAndDefaults>(input, output));
+              mojom::PrinterSemanticCapsAndDefaults>(input, output));
 
   EXPECT_EQ(kCollateCapable, output.collate_capable);
   EXPECT_EQ(kCollateDefault, output.collate_default);
@@ -234,32 +224,31 @@
 
 TEST(PrintBackendMojomTraitsTest,
      TestSerializeAndDeserializePrinterSemanticCapsAndDefaultsCopiesMax) {
-  printing::PrinterSemanticCapsAndDefaults input =
+  PrinterSemanticCapsAndDefaults input =
       GenerateSamplePrinterSemanticCapsAndDefaults();
-  printing::PrinterSemanticCapsAndDefaults output;
+  PrinterSemanticCapsAndDefaults output;
 
   // Override sample with no copies.
   input.copies_max = 0;
 
   EXPECT_FALSE(mojo::test::SerializeAndDeserialize<
-               printing::mojom::PrinterSemanticCapsAndDefaults>(input, output));
+               mojom::PrinterSemanticCapsAndDefaults>(input, output));
 }
 
 TEST(
     PrintBackendMojomTraitsTest,
     TestSerializeAndDeserializePrinterSemanticCapsAndDefaultsAllowableEmptyArrays) {
-  printing::PrinterSemanticCapsAndDefaults input =
+  PrinterSemanticCapsAndDefaults input =
       GenerateSamplePrinterSemanticCapsAndDefaults();
-  printing::PrinterSemanticCapsAndDefaults output;
+  PrinterSemanticCapsAndDefaults output;
 
   // Override sample with arrays which are allowed to be empty:
   // `duplex_modes`, `user_defined_papers`, `dpis`, `advanced_capabilities`.
-  const std::vector<printing::mojom::DuplexMode> kEmptyDuplexModes{};
-  const printing::PrinterSemanticCapsAndDefaults::Papers
-      kEmptyUserDefinedPapers{};
-  const std::vector<gfx::Size> kEmptyDpis{};
+  const std::vector<mojom::DuplexMode> kEmptyDuplexModes;
+  const PrinterSemanticCapsAndDefaults::Papers kEmptyUserDefinedPapers;
+  const std::vector<gfx::Size> kEmptyDpis;
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  const printing::AdvancedCapabilities kEmptyAdvancedCapabilities{};
+  const AdvancedCapabilities kEmptyAdvancedCapabilities;
 #endif
 
   input.duplex_modes = kEmptyDuplexModes;
@@ -270,7 +259,7 @@
 #endif
 
   EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
-              printing::mojom::PrinterSemanticCapsAndDefaults>(input, output));
+              mojom::PrinterSemanticCapsAndDefaults>(input, output));
 
   EXPECT_EQ(kEmptyDuplexModes, output.duplex_modes);
   EXPECT_EQ(kEmptyUserDefinedPapers, output.user_defined_papers);
@@ -282,67 +271,64 @@
 
 TEST(PrintBackendMojomTraitsTest,
      TestSerializeAndDeserializePrinterSemanticCapsAndDefaultsEmptyPapers) {
-  printing::PrinterSemanticCapsAndDefaults input =
+  PrinterSemanticCapsAndDefaults input =
       GenerateSamplePrinterSemanticCapsAndDefaults();
-  printing::PrinterSemanticCapsAndDefaults output;
+  PrinterSemanticCapsAndDefaults output;
 
   // Override sample with empty `papers`, which is not allowed.
-  input.papers = printing::PrinterSemanticCapsAndDefaults::Papers{};
+  input.papers.clear();
 
   EXPECT_FALSE(mojo::test::SerializeAndDeserialize<
-               printing::mojom::PrinterSemanticCapsAndDefaults>(input, output));
+               mojom::PrinterSemanticCapsAndDefaults>(input, output));
 }
 
 TEST(
     PrintBackendMojomTraitsTest,
     TestSerializeAndDeserializePrinterSemanticCapsAndDefaultsNoDuplicatesInArrays) {
-  printing::PrinterSemanticCapsAndDefaults input =
+  PrinterSemanticCapsAndDefaults input =
       GenerateSamplePrinterSemanticCapsAndDefaults();
-  printing::PrinterSemanticCapsAndDefaults output;
+  PrinterSemanticCapsAndDefaults output;
 
   // Override sample with arrays containing duplicates, which is not allowed.
-  input.duplex_modes = std::vector<printing::mojom::DuplexMode>{
-      printing::mojom::DuplexMode::kLongEdge,
-      printing::mojom::DuplexMode::kSimplex,
-      printing::mojom::DuplexMode::kSimplex};
+  input.duplex_modes = {mojom::DuplexMode::kLongEdge,
+                        mojom::DuplexMode::kSimplex,
+                        mojom::DuplexMode::kSimplex};
 
   EXPECT_FALSE(mojo::test::SerializeAndDeserialize<
-               printing::mojom::PrinterSemanticCapsAndDefaults>(input, output));
+               mojom::PrinterSemanticCapsAndDefaults>(input, output));
 
   // Use a paper with same name but different size.
-  printing::PrinterSemanticCapsAndDefaults::Paper paperA4Prime = kPaperA4;
-  paperA4Prime.size_um = kPaperLetter.size_um;
+  PrinterSemanticCapsAndDefaults::Paper paper_a4_prime = kPaperA4;
+  paper_a4_prime.size_um = kPaperLetter.size_um;
   input = GenerateSamplePrinterSemanticCapsAndDefaults();
-  input.papers = printing::PrinterSemanticCapsAndDefaults::Papers{
-      kPaperA4, kPaperLetter, kPaperLedger, paperA4Prime};
+  input.papers = {kPaperA4, kPaperLetter, kPaperLedger, paper_a4_prime};
 
   EXPECT_FALSE(mojo::test::SerializeAndDeserialize<
-               printing::mojom::PrinterSemanticCapsAndDefaults>(input, output));
+               mojom::PrinterSemanticCapsAndDefaults>(input, output));
 
   input = GenerateSamplePrinterSemanticCapsAndDefaults();
-  input.user_defined_papers = printing::PrinterSemanticCapsAndDefaults::Papers{
-      kPaperLetter, kPaperLetter};
+  input.user_defined_papers = {kPaperLetter, kPaperLetter};
 
   EXPECT_FALSE(mojo::test::SerializeAndDeserialize<
-               printing::mojom::PrinterSemanticCapsAndDefaults>(input, output));
+               mojom::PrinterSemanticCapsAndDefaults>(input, output));
 
   input = GenerateSamplePrinterSemanticCapsAndDefaults();
-  input.dpis = std::vector<gfx::Size>{kDpi600, kDpi600, kDpi1200};
+  input.dpis = {kDpi600, kDpi600, kDpi1200};
 
   EXPECT_FALSE(mojo::test::SerializeAndDeserialize<
-               printing::mojom::PrinterSemanticCapsAndDefaults>(input, output));
+               mojom::PrinterSemanticCapsAndDefaults>(input, output));
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // Use an advanced capability with same name but different other fields.
-  printing::AdvancedCapability advancedCapability1Prime = kAdvancedCapability1;
-  advancedCapability1Prime.type = printing::AdvancedCapability::Type::kInteger;
-  advancedCapability1Prime.default_value = "42";
+  AdvancedCapability advanced_capability1_prime = kAdvancedCapability1;
+  advanced_capability1_prime.type = AdvancedCapability::Type::kInteger;
+  advanced_capability1_prime.default_value = "42";
   input = GenerateSamplePrinterSemanticCapsAndDefaults();
-  input.advanced_capabilities = printing::AdvancedCapabilities{
-      kAdvancedCapability1, advancedCapability1Prime};
+  input.advanced_capabilities = {kAdvancedCapability1,
+                                 advanced_capability1_prime};
 
   EXPECT_FALSE(mojo::test::SerializeAndDeserialize<
-               printing::mojom::PrinterSemanticCapsAndDefaults>(input, output));
+               mojom::PrinterSemanticCapsAndDefaults>(input, output));
 #endif
 }
 
diff --git a/services/device/power_monitor/power_monitor_message_broadcaster_unittest.cc b/services/device/power_monitor/power_monitor_message_broadcaster_unittest.cc
index 0f6d10f..7ef7bf9 100644
--- a/services/device/power_monitor/power_monitor_message_broadcaster_unittest.cc
+++ b/services/device/power_monitor/power_monitor_message_broadcaster_unittest.cc
@@ -51,24 +51,16 @@
 
   void SetUp() override {
     DeviceServiceTestBase::SetUp();
-
-    power_monitor_source_ = new base::PowerMonitorTestSource();
-    base::PowerMonitor::Initialize(
-        std::unique_ptr<base::PowerMonitorSource>(power_monitor_source_));
   }
 
   void TearDown() override {
-    // The DeviceService must be destroyed before shutting down the
-    // PowerMonitor, which the DeviceService is observing.
     DestroyDeviceService();
-    base::PowerMonitor::ShutdownForTesting();
   }
 
-  base::PowerMonitorTestSource* source() { return power_monitor_source_; }
+ protected:
+  base::test::ScopedPowerMonitorTestSource power_monitor_source_;
 
  private:
-  base::PowerMonitorTestSource* power_monitor_source_;
-
   DISALLOW_COPY_AND_ASSIGN(PowerMonitorMessageBroadcasterTest);
 };
 
@@ -96,39 +88,39 @@
   EXPECT_EQ(client->power_state_changes(), 1);
 
   // Sending resume when not suspended should have no effect.
-  source()->GenerateResumeEvent();
+  power_monitor_source_.GenerateResumeEvent();
   EXPECT_EQ(client->resumes(), 0);
 
   // Pretend we suspended.
-  source()->GenerateSuspendEvent();
+  power_monitor_source_.GenerateSuspendEvent();
   EXPECT_EQ(client->suspends(), 1);
 
   // Send a second suspend notification.  This should be suppressed.
-  source()->GenerateSuspendEvent();
+  power_monitor_source_.GenerateSuspendEvent();
   EXPECT_EQ(client->suspends(), 1);
 
   // Pretend we were awakened.
-  source()->GenerateResumeEvent();
+  power_monitor_source_.GenerateResumeEvent();
   EXPECT_EQ(client->resumes(), 1);
 
   // Send a duplicate resume notification.  This should be suppressed.
-  source()->GenerateResumeEvent();
+  power_monitor_source_.GenerateResumeEvent();
   EXPECT_EQ(client->resumes(), 1);
 
   // Pretend the device has gone on battery power
-  source()->GeneratePowerStateEvent(true);
+  power_monitor_source_.GeneratePowerStateEvent(true);
   EXPECT_EQ(client->power_state_changes(), 2);
 
   // Repeated indications the device is on battery power should be suppressed.
-  source()->GeneratePowerStateEvent(true);
+  power_monitor_source_.GeneratePowerStateEvent(true);
   EXPECT_EQ(client->power_state_changes(), 2);
 
   // Pretend the device has gone off battery power
-  source()->GeneratePowerStateEvent(false);
+  power_monitor_source_.GeneratePowerStateEvent(false);
   EXPECT_EQ(client->power_state_changes(), 3);
 
   // Repeated indications the device is off battery power should be suppressed.
-  source()->GeneratePowerStateEvent(false);
+  power_monitor_source_.GeneratePowerStateEvent(false);
   EXPECT_EQ(client->power_state_changes(), 3);
 
   broadcast_source.reset();
diff --git a/skia/features.gni b/skia/features.gni
index 894e8f6..5675938 100644
--- a/skia/features.gni
+++ b/skia/features.gni
@@ -8,7 +8,7 @@
   skia_use_gl = true
 
   # Enable gtests using SkiaRenderer Dawn.
-  # TODO(sgilhuly): Remove this and enable the tests by default once a software
+  # TODO(rivr): Remove this and enable the tests by default once a software
   # path for D3D12 is available.
   enable_skia_dawn_gtests = false
 }
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 242667e..022264b 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -4452,6 +4452,8 @@
     "gtest_tests": [
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
           "--avd-config=../../tools/android/avd/proto/generic_android29.textpb",
@@ -4516,6 +4518,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -4595,6 +4599,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -4674,6 +4680,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -4753,6 +4761,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -4832,6 +4842,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -4911,6 +4923,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -4994,6 +5008,8 @@
     "gtest_tests": [
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
           "--avd-config=../../tools/android/avd/proto/generic_android23.textpb",
@@ -5058,6 +5074,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -5137,6 +5155,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -5216,6 +5236,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -5295,6 +5317,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -5374,6 +5398,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -5453,6 +5479,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 0d44f93..bb6a33f 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -49000,6 +49000,8 @@
     "gtest_tests": [
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
           "--avd-config=../../tools/android/avd/proto/generic_android27.textpb"
@@ -49063,6 +49065,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -49142,6 +49146,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -49221,6 +49227,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -49300,6 +49308,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -49379,6 +49389,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -49458,6 +49470,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -49541,6 +49555,8 @@
     "gtest_tests": [
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
           "--avd-config=../../tools/android/avd/proto/generic_android28.textpb"
@@ -49604,6 +49620,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -49683,6 +49701,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -49762,6 +49782,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -49841,6 +49863,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -49920,6 +49944,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
@@ -49999,6 +50025,8 @@
       },
       {
         "args": [
+          "--timeout-scale",
+          "2.0",
           "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index bfe61ea9..a3ef6ed 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -1087,6 +1087,23 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
+        "test": "openscreen_unittests",
+        "test_id_prefix": "ninja://chrome/browser/media/router:openscreen_unittests/"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-16.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
         "test": "pdf_unittests",
         "test_id_prefix": "ninja://pdf:pdf_unittests/"
       },
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 5ffd813..6b86c48 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -6198,6 +6198,23 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
+        "test": "openscreen_unittests",
+        "test_id_prefix": "ninja://chrome/browser/media/router:openscreen_unittests/"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-16.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
         "test": "pdf_unittests",
         "test_id_prefix": "ninja://pdf:pdf_unittests/"
       },
diff --git a/testing/buildbot/filters/gpu.linux.skiarenderer_dawn_viz_unittests.filter b/testing/buildbot/filters/gpu.linux.skiarenderer_dawn_viz_unittests.filter
index 8a933506..1743a29 100644
--- a/testing/buildbot/filters/gpu.linux.skiarenderer_dawn_viz_unittests.filter
+++ b/testing/buildbot/filters/gpu.linux.skiarenderer_dawn_viz_unittests.filter
@@ -1 +1 @@
-# TODO(sgilhuly): Remove this file once SkiaRenderer Dawn is more stable.
+# TODO(rivr): Remove this file once SkiaRenderer Dawn is more stable.
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index d5c8361..e899561 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -2129,12 +2129,6 @@
       'ToTWinThinLTO64',
     ],
   },
-  'openscreen_unittests': {
-    'remove_from': [
-      'Linux CFI',  # crbug.com/1143983
-      'CFI Linux ToT',  # crbug.com/1143983
-    ],
-  },
   'ozone_unittests': {
     'modifications': {
       'chromeos-betty-pi-arc-chrome': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index fa8d84a..d5ed6cc8 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -6839,7 +6839,13 @@
     'android_weblayer_x86_marshmallow_10_gtests': {
       'weblayer_instrumentation_tests': {
         'variants': [
-          {'identifier': 'ToT_Tests'}
+          {
+            'identifier': 'ToT_Tests',
+            'args': [
+              '--timeout-scale',
+              '2.0',
+            ]
+          }
         ]
       },
       'weblayer_instrumentation_version_tests': {
@@ -6857,7 +6863,13 @@
     'android_weblayer_x86_pie_oreo_gtests': {
       'weblayer_instrumentation_tests': {
         'variants': [
-          {'identifier': 'ToT_Tests'}
+          {
+            'identifier': 'ToT_Tests',
+            'args': [
+              '--timeout-scale',
+              '2.0',
+            ]
+          }
         ]
       },
       'weblayer_instrumentation_version_tests': {
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index b832f112..c10f3c55 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -312,6 +312,8 @@
   },
   'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MILESTONE': {
     'args': [
+      '--timeout-scale',
+      '2.0',
       '--webview-apk-path=apks/AOSP_SystemWebView.apk',
       '--test-runner-outdir',
       '.',
@@ -336,6 +338,8 @@
   },
   'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
     'args': [
+      '--timeout-scale',
+      '2.0',
       '--webview-apk-path=apks/AOSP_SystemWebView.apk',
       '--test-runner-outdir',
       '.',
@@ -360,6 +364,8 @@
   },
   'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': {
     'args': [
+      '--timeout-scale',
+      '2.0',
       '--webview-apk-path=apks/AOSP_SystemWebView.apk',
       '--test-runner-outdir',
       '.',
@@ -384,6 +390,8 @@
   },
   'WEBLAYER_IMPL_SKEW_TESTS_NTH_MILESTONE': {
     'args': [
+      '--timeout-scale',
+      '2.0',
       '--webview-apk-path=apks/SystemWebView.apk',
       '--test-runner-outdir',
       '.',
@@ -408,6 +416,8 @@
   },
   'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
     'args': [
+      '--timeout-scale',
+      '2.0',
       '--webview-apk-path=apks/SystemWebView.apk',
       '--test-runner-outdir',
       '.',
@@ -432,6 +442,8 @@
   },
   'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': {
     'args': [
+      '--timeout-scale',
+      '2.0',
       '--webview-apk-path=apks/SystemWebView.apk',
       '--test-runner-outdir',
       '.',
@@ -456,6 +468,8 @@
   },
   'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MILESTONE': {
     'args': [
+      '--timeout-scale',
+      '2.0',
       '--webview-apk-path=apks/SystemWebView.apk',
       '--test-runner-outdir',
       '.',
@@ -480,6 +494,8 @@
   },
   'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
     'args': [
+      '--timeout-scale',
+      '2.0',
       '--webview-apk-path=apks/SystemWebView.apk',
       '--test-runner-outdir',
       '.',
@@ -504,6 +520,8 @@
   },
   'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': {
     'args': [
+      '--timeout-scale',
+      '2.0',
       '--webview-apk-path=apks/SystemWebView.apk',
       '--test-runner-outdir',
       '.',
@@ -575,4 +593,4 @@
     },
     'identifier': 'SNAPPY_TOT',
   },
-}
\ No newline at end of file
+}
diff --git a/testing/libfuzzer/libprotobuf-mutator.md b/testing/libfuzzer/libprotobuf-mutator.md
index 7837d70..94d7d28 100644
--- a/testing/libfuzzer/libprotobuf-mutator.md
+++ b/testing/libfuzzer/libprotobuf-mutator.md
@@ -46,9 +46,9 @@
 ## Write a fuzz target for code that accepts protobufs
 
 This is almost as easy as writing a standard libFuzzer-based fuzzer. You can
-look at [lpm_test_fuzzer] for an example of a working example of this (don't
-copy the line adding "//testing/libfuzzer:no_clusterfuzz" to
-additional_configs). Or you can follow this walkthrough:
+look at [override_lite_runtime_plugin_test_fuzzer] for an example of a working
+example of this (don't copy the line adding "//testing/libfuzzer:no_clusterfuzz"
+to additional_configs). Or you can follow this walkthrough:
 
 Start by creating a fuzz target. This is what the .cc file will look like:
 
@@ -365,5 +365,5 @@
 [this]: https://github.com/google/libprotobuf-mutator/tree/master/examples/libfuzzer/libfuzzer_example.cc
 [existing proto fuzzers]: https://cs.chromium.org/search/?q=DEFINE_(BINARY_%7CTEXT_)?PROTO_FUZZER+-file:src/third_party/libprotobuf-mutator/src/src/libfuzzer/libfuzzer_macro.h+lang:cpp&sq=package:chromium&type=cs
 [here]: https://github.com/google/libprotobuf-mutator/blob/master/README.md#utf-8-strings
-[lpm_test_fuzzer]: https://cs.chromium.org/#search&q=lpm_test_fuzzer+file:%5Esrc/third_party/libprotobuf-mutator/BUILD.gn
+[override_lite_runtime_plugin_test_fuzzer]: https://cs.chromium.org/#search&q=override_lite_runtime_plugin_test_fuzzer+file:%5Esrc/third_party/libprotobuf-mutator/BUILD.gn
 [mojo_parse_messages_proto_fuzzer]: https://cs.chromium.org/chromium/src/mojo/public/tools/fuzzers/mojo_parse_message_proto_fuzzer.cc?l=25
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index 9a495a60..0d4303d 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -1986,8 +1986,10 @@
       optional Node templateContent
       # Pseudo elements associated with this node.
       optional array of Node pseudoElements
-      # Import document for the HTMLImport links.
-      optional Node importedDocument
+      # Deprecated, as the HTML Imports API has been removed (crbug.com/937746).
+      # This property used to return the imported document for the HTMLImport links.
+      # The property is always undefined now.
+      deprecated optional Node importedDocument
       # Distributed nodes for given insertion point.
       optional array of BackendNode distributedNodes
       # Whether the node is SVG.
diff --git a/third_party/blink/renderer/core/animation/animation.h b/third_party/blink/renderer/core/animation/animation.h
index 4f267d1..c8484cd 100644
--- a/third_party/blink/renderer/core/animation/animation.h
+++ b/third_party/blink/renderer/core/animation/animation.h
@@ -531,7 +531,6 @@
   // stage with the CompositeBGColorAnimation feature.
   base::Optional<CompositorAnimations::FailureReasons>
       supplemental_failure_reasons_;
-  bool can_composite_bgcolor_anim_ = false;
 
   // Animations with an owning element stop ticking if there is an active
   // display lock on an ancestor element.  Cache the status to minimize the
diff --git a/third_party/blink/renderer/core/dom/node.h b/third_party/blink/renderer/core/dom/node.h
index d6b4cd5..4b508896 100644
--- a/third_party/blink/renderer/core/dom/node.h
+++ b/third_party/blink/renderer/core/dom/node.h
@@ -944,13 +944,6 @@
   void ClearNeedsInheritDirectionalityFromParent() {
     ClearFlag(kNeedsInheritDirectionalityFromParent);
   }
-
-  // TODO(masonf): This is needed to avoid devtools-frontend missing
-  // the |importedDocument| property, which apparently came from the now-
-  // removed LinkImport object. ImportedDocument used to point to the
-  // document imported by an HTML Imports <link rel=import>.
-  Document* ImportedDocument() const { return nullptr; }
-
   void Trace(Visitor*) const override;
 
  private:
diff --git a/third_party/blink/renderer/core/events/overscroll_event.idl b/third_party/blink/renderer/core/events/overscroll_event.idl
index f3e8c8c..944278f 100644
--- a/third_party/blink/renderer/core/events/overscroll_event.idl
+++ b/third_party/blink/renderer/core/events/overscroll_event.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(sahel): Add link to w3c. https://crbugs.com/907601
+// TODO(crbug.com/907601): Add link to w3c.
 
 [
     Exposed=Window,
diff --git a/third_party/blink/renderer/core/events/overscroll_event_init.idl b/third_party/blink/renderer/core/events/overscroll_event_init.idl
index 6d9e286b..44f4b6c7 100644
--- a/third_party/blink/renderer/core/events/overscroll_event_init.idl
+++ b/third_party/blink/renderer/core/events/overscroll_event_init.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(sahel): Add link to w3c. https://crbugs.com/907601
+// TODO(crbug.com/907601): Add link to w3c.
 
 dictionary OverscrollEventInit : EventInit {
   double deltaX = 0.0;
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 0dabfb2b..d2ae2e7 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -7464,8 +7464,8 @@
   NOT_DESTROYED();
   if (ShouldBeConsideredAsReplaced() || HasUnsplittableScrollingOverflow() ||
       (Parent() && IsWritingModeRoot()) ||
-      (IsOutOfFlowPositioned() &&
-       StyleRef().GetPosition() == EPosition::kFixed) ||
+      (IsFixedPositioned() && GetDocument().Printing() &&
+       IsA<LayoutView>(Container())) ||
       ShouldApplySizeContainment() || IsFrameSet())
     return kForbidBreaks;
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
index 0504f54..061f358 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
@@ -124,6 +124,7 @@
                          bool is_start_dominant,
                          bool is_block_direction,
                          bool is_table,
+                         bool is_shrink_to_fit,
                          base::Optional<LayoutUnit> size,
                          LayoutUnit* size_out,
                          LayoutUnit* inset_start_out,
@@ -278,7 +279,7 @@
   } else if (!size) {
     LayoutUnit computed_available_size =
         available_size - *inset_start - *inset_end;
-    if (is_table) {
+    if (is_shrink_to_fit) {
       size = ComputeShrinkToFitSize(is_table, min_max_sizes, available_size,
                                     computed_available_size, *margin_start,
                                     *margin_end);
@@ -299,8 +300,9 @@
         available_size, margin_start_length, margin_end_length,
         inset_start_length, inset_end_length, min_size, max_size,
         static_position_offset, static_position_edge, is_start_dominant,
-        is_block_direction, is_table, constrained_size, size_out,
-        inset_start_out, inset_end_out, margin_start_out, margin_end_out);
+        is_block_direction, is_table, is_shrink_to_fit, constrained_size,
+        size_out, inset_start_out, inset_end_out, margin_start_out,
+        margin_end_out);
     return;
   }
 
@@ -380,6 +382,9 @@
   DCHECK(dimensions);
 
   const auto& style = node.Style();
+  const bool is_table = node.IsTable();
+  const bool is_shrink_to_fit = is_table || node.ShouldBeConsideredAsReplaced();
+
   Length min_inline_length = style.LogicalMinWidth();
   base::Optional<MinMaxSizes> min_size_minmax = minmax_content_sizes;
   // We don't need to check for IsInlineSizeComputableFromBlockSize; this is
@@ -405,7 +410,6 @@
   }
 
   // Tables are never allowed to go below their min-content size.
-  const bool is_table = node.IsTable();
   if (is_table)
     min_inline_size = std::max(min_inline_size, minmax_content_sizes->min_size);
 
@@ -438,7 +442,7 @@
       style.LogicalInlineStart(), style.LogicalInlineEnd(), min_inline_size,
       max_inline_size, static_position.offset.inline_offset,
       GetStaticPositionEdge(static_position.inline_edge), is_start_dominant,
-      false /* is_block_direction */, is_table, inline_size,
+      false /* is_block_direction */, is_table, is_shrink_to_fit, inline_size,
       &dimensions->size.inline_size, &dimensions->inset.inline_start,
       &dimensions->inset.inline_end, &dimensions->margins.inline_start,
       &dimensions->margins.inline_end);
@@ -453,7 +457,13 @@
     const base::Optional<LogicalSize>& replaced_size,
     const WritingDirectionMode container_writing_direction,
     NGLogicalOutOfFlowDimensions* dimensions) {
+  DCHECK(dimensions);
+
+  // NOTE: |is_shrink_to_fit| isn't symmetrical with the inline calculations.
   const auto& style = node.Style();
+  const bool is_table = node.IsTable();
+  const bool is_shrink_to_fit = is_table;
+
   // After partial size has been computed, child block size is either unknown,
   // or fully computed, there is no minmax. To express this, a 'fixed' minmax
   // is created where min and max are the same.
@@ -470,7 +480,6 @@
       space, style, border_padding, style.LogicalMaxHeight());
 
   // Tables are never allowed to go below their "auto" block-size.
-  const bool is_table = node.IsTable();
   if (is_table)
     min_block_size = std::max(min_block_size, min_max_sizes->min_size);
 
@@ -500,7 +509,7 @@
       style.MarginAfter(), style.LogicalTop(), style.LogicalBottom(),
       min_block_size, max_block_size, static_position.offset.block_offset,
       GetStaticPositionEdge(static_position.block_edge), is_start_dominant,
-      true /* is_block_direction */, is_table, block_size,
+      true /* is_block_direction */, is_table, is_shrink_to_fit, block_size,
       &dimensions->size.block_size, &dimensions->inset.block_start,
       &dimensions->inset.block_end, &dimensions->margins.block_start,
       &dimensions->margins.block_end);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
index 5f91bef..e78c8fc0 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -579,6 +579,47 @@
   math_data_->italic_correction_ = italic_correction;
 }
 
+void NGBoxFragmentBuilder::AdjustOffsetsForFragmentainerDescendant(
+    NGLogicalOutOfFlowPositionedNode& descendant,
+    bool only_fixedpos_containing_block) {
+  if (!PreviousBreakToken())
+    return;
+  LayoutUnit previous_consumed_block_size =
+      PreviousBreakToken()->ConsumedBlockSize();
+
+  // If the containing block is fragmented, adjust the offset to be from the
+  // first containing block fragment to the fragmentation context root. Also,
+  // adjust the static position to be relative to the adjusted containing block
+  // offset.
+  if (!only_fixedpos_containing_block &&
+      !descendant.containing_block.fragment) {
+    descendant.containing_block.offset.block_offset -=
+        previous_consumed_block_size;
+    descendant.static_position.offset.block_offset +=
+        previous_consumed_block_size;
+  }
+
+  // If the fixedpos containing block is fragmented, adjust the offset to be
+  // from the first containing block fragment to the fragmentation context root.
+  if (!descendant.fixedpos_containing_block.fragment &&
+      node_.IsFixedContainer()) {
+    descendant.fixedpos_containing_block.offset.block_offset -=
+        previous_consumed_block_size;
+  }
+}
+
+void NGBoxFragmentBuilder::
+    AdjustFixedposContainingBlockForFragmentainerDescendants() {
+  if (!HasOutOfFlowFragmentainerDescendants() || !PreviousBreakToken() ||
+      !node_.IsFixedContainer())
+    return;
+
+  for (auto& descendant : oof_positioned_fragmentainer_descendants_) {
+    AdjustOffsetsForFragmentainerDescendant(
+        descendant, /* only_fixedpos_containing_block */ true);
+  }
+}
+
 #if DCHECK_IS_ON()
 
 void NGBoxFragmentBuilder::CheckNoBlockFragmentation() const {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index fb8e4ac..143c250 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -569,6 +569,11 @@
 
   void SetMathItalicCorrection(LayoutUnit italic_correction);
 
+  void AdjustOffsetsForFragmentainerDescendant(
+      NGLogicalOutOfFlowPositionedNode& descendant,
+      bool only_fixedpos_containing_block = false);
+  void AdjustFixedposContainingBlockForFragmentainerDescendants();
+
  private:
   // Update whether we have fragmented in this flow.
   void PropagateBreak(const NGLayoutResult&);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
index 1b0e0c2..00b5767e 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -171,8 +171,9 @@
   oof_positioned_candidates_.emplace_back(
       child, NGLogicalStaticPosition{child_offset, inline_edge, block_edge},
       /* inline_container */ nullptr, needs_block_offset_adjustment,
-      /* containing_block_offset */ LogicalOffset(),
-      /* containing_block_fragment */ nullptr, containing_block_rect);
+      /* containing_block */ NGLogicalContainingBlock(),
+      /* fixedpos_containing_block */ NGLogicalContainingBlock(),
+      containing_block_rect);
 }
 
 void NGContainerFragmentBuilder::AddOutOfFlowInlineChildCandidate(
@@ -278,10 +279,9 @@
     const NGPhysicalContainerFragment& fragment,
     LogicalOffset offset,
     LayoutUnit fragmentainer_consumed_block_size,
-    const LayoutInline* inline_container) {
-  // TODO(almaher): Determine if this needs updating once nested fixedpos
-  // elements are properly handled in a multicol.
-
+    const LayoutInline* inline_container,
+    const NGLogicalContainingBlock* fixedpos_containing_block,
+    LogicalOffset additional_fixedpos_offset) {
   // Collect the child's out of flow descendants.
   const WritingModeConverter converter(GetWritingDirection(), fragment.Size());
   for (const auto& descendant : fragment.OutOfFlowPositionedDescendants()) {
@@ -294,6 +294,24 @@
         IsInlineContainerForNode(descendant.node, inline_container))
       new_inline_container = inline_container;
 
+    // If an OOF element is inside a fragmentation context, it will be laid out
+    // once it reaches the fragmentation context root. However, if such OOF
+    // elements have fixedpos descendants, those descendants will not find their
+    // containing block if the containing block lives inside the fragmentation
+    // context root. In this case, the containing block will be passed in via
+    // |fixedpos_containing_block|. If one exists, add the fixedpos as a
+    // fragmentainer descendant with the correct containing block and static
+    // position.
+    if (fixedpos_containing_block && fixedpos_containing_block->fragment &&
+        descendant.node.Style().GetPosition() == EPosition::kFixed) {
+      static_position.offset += additional_fixedpos_offset;
+      AddOutOfFlowFragmentainerDescendant(
+          {descendant.node, static_position, new_inline_container,
+           /* needs_block_offset_adjustment */ false,
+           *fixedpos_containing_block, *fixedpos_containing_block});
+      continue;
+    }
+
     // |oof_positioned_candidates_| should not have duplicated entries.
     DCHECK(std::none_of(
         oof_positioned_candidates_.begin(), oof_positioned_candidates_.end(),
@@ -330,18 +348,43 @@
       box_fragment->OutOfFlowPositionedFragmentainerDescendants();
   for (const auto& descendant : out_of_flow_fragmentainer_descendants) {
     const NGPhysicalContainerFragment* containing_block_fragment =
-        descendant.containing_block_fragment;
+        descendant.containing_block.fragment;
     if (!containing_block_fragment)
       containing_block_fragment = box_fragment;
 
     LogicalOffset containing_block_offset = converter.ToLogical(
-        descendant.containing_block_offset, containing_block_fragment->Size());
-    if (!fragment.IsFragmentainerBox())
+        descendant.containing_block.offset, containing_block_fragment->Size());
+    if (!box_fragment->IsFragmentainerBox())
       containing_block_offset.block_offset += offset.block_offset;
     if (IsBlockFragmentationContextRoot()) {
       containing_block_offset.block_offset += fragmentainer_consumed_block_size;
     }
 
+    const NGPhysicalContainerFragment* fixedpos_containing_block_fragment =
+        descendant.fixedpos_containing_block.fragment;
+    if (!fixedpos_containing_block_fragment &&
+        box_fragment->GetLayoutObject() &&
+        box_fragment->GetLayoutObject()->CanContainFixedPositionObjects())
+      fixedpos_containing_block_fragment = box_fragment;
+
+    LogicalOffset fixedpos_containing_block_offset;
+    if (fixedpos_containing_block_fragment) {
+      fixedpos_containing_block_offset =
+          converter.ToLogical(descendant.fixedpos_containing_block.offset,
+                              fixedpos_containing_block_fragment->Size());
+      if (!box_fragment->IsFragmentainerBox())
+        fixedpos_containing_block_offset.block_offset += offset.block_offset;
+      if (IsBlockFragmentationContextRoot()) {
+        fixedpos_containing_block_offset.block_offset +=
+            fragmentainer_consumed_block_size;
+      }
+    }
+
+    if (!fixedpos_containing_block_fragment && fixedpos_containing_block) {
+      fixedpos_containing_block_fragment = fixedpos_containing_block->fragment;
+      fixedpos_containing_block_offset = fixedpos_containing_block->offset;
+    }
+
     // The static position should remain relative to its containing block
     // fragment.
     const WritingModeConverter containing_block_converter(
@@ -350,8 +393,11 @@
         descendant.static_position.ConvertToLogical(containing_block_converter);
     AddOutOfFlowFragmentainerDescendant(
         {descendant.node, static_position, descendant.inline_container,
-         /* needs_block_offset_adjustment */ false, containing_block_offset,
-         containing_block_fragment});
+         /* needs_block_offset_adjustment */ false,
+         NGLogicalContainingBlock(containing_block_offset,
+                                  containing_block_fragment),
+         NGLogicalContainingBlock(fixedpos_containing_block_offset,
+                                  fixedpos_containing_block_fragment)});
   }
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
index 75e3625..434d3ca 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
@@ -182,7 +182,9 @@
       const NGPhysicalContainerFragment& fragment,
       LogicalOffset offset,
       LayoutUnit fragmentainer_consumed_block_size,
-      const LayoutInline* inline_container = nullptr);
+      const LayoutInline* inline_container = nullptr,
+      const NGLogicalContainingBlock* fixedpos_containing_block = nullptr,
+      LogicalOffset additional_fixedpos_offset = LogicalOffset());
 
   void SetIsSelfCollapsing() { is_self_collapsing_ = true; }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
index 82e1ea0..185a4d75 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
@@ -773,13 +773,12 @@
 }  // namespace
 
 // Computes size for a replaced element.
-void ComputeReplacedSize(const NGBlockNode& node,
-                         const NGConstraintSpace& space,
-                         const base::Optional<MinMaxSizes>& child_min_max_sizes,
-                         base::Optional<LogicalSize>* out_replaced_size,
-                         base::Optional<LogicalSize>* out_aspect_ratio) {
+base::Optional<LogicalSize> ComputeReplacedSize(
+    const NGBlockNode& node,
+    const NGConstraintSpace& space,
+    const base::Optional<MinMaxSizes>& child_min_max_sizes,
+    base::Optional<LogicalSize>* out_aspect_ratio) {
   DCHECK(node.IsReplaced());
-  DCHECK(!out_replaced_size->has_value());
   DCHECK(!out_aspect_ratio->has_value());
 
   const ComputedStyle& style = node.Style();
@@ -843,22 +842,21 @@
         inline_min_max_sizes.ClampSizeToMinAndMax(*replaced_inline);
   }
 
-  if (replaced_inline && replaced_block) {
-    out_replaced_size->emplace(*replaced_inline, *replaced_block);
-    return;
-  }
+  if (replaced_inline && replaced_block)
+    return LogicalSize(*replaced_inline, *replaced_block);
 
   const LogicalSize aspect_ratio = node.GetAspectRatio();
   const base::Optional<LogicalSize> natural_size =
       ComputeNormalizedNaturalSize(node, border_padding, aspect_ratio);
 
+  // No sizes available, return only the aspect ratio.
   if (!natural_size && !replaced_inline && !replaced_block) {
-    // No sizes available, return only the aspect ratio.
     *out_aspect_ratio = aspect_ratio;
-    return;
+    return base::nullopt;
   }
 
-  // If we only know one length, the other length gets computed wrt one we know.
+  // We only know one size, the other gets computed via the aspect-ratio (if
+  // present), or by the natural-size.
   auto ComputeBlockFromInline = [&replaced_inline, &aspect_ratio,
                                  &border_padding](LayoutUnit default_block) {
     if (aspect_ratio.IsEmpty()) {
@@ -868,7 +866,6 @@
     return BlockSizeFromAspectRatio(border_padding, aspect_ratio,
                                     EBoxSizing::kContentBox, *replaced_inline);
   };
-
   auto ComputeInlineFromBlock = [&replaced_block, &aspect_ratio,
                                  &border_padding](LayoutUnit default_inline) {
     if (aspect_ratio.IsEmpty()) {
@@ -878,6 +875,7 @@
     return InlineSizeFromAspectRatio(border_padding, aspect_ratio,
                                      EBoxSizing::kContentBox, *replaced_block);
   };
+
   if (replaced_inline) {
     DCHECK(!replaced_block);
     DCHECK(natural_size || !aspect_ratio.IsEmpty());
@@ -885,7 +883,10 @@
         natural_size.value_or(LogicalSize(kIndefiniteSize, kIndefiniteSize))
             .block_size);
     replaced_block = block_min_max_sizes.ClampSizeToMinAndMax(*replaced_block);
-  } else if (replaced_block) {
+    return LogicalSize(*replaced_inline, *replaced_block);
+  }
+
+  if (replaced_block) {
     DCHECK(!replaced_inline);
     DCHECK(natural_size || !aspect_ratio.IsEmpty());
     replaced_inline = ComputeInlineFromBlock(
@@ -893,68 +894,71 @@
             .inline_size);
     replaced_inline =
         inline_min_max_sizes.ClampSizeToMinAndMax(*replaced_inline);
-  } else {
-    // If both lengths are unknown, they get defined by intrinsic values.
-    DCHECK(!replaced_inline);
-    DCHECK(!replaced_block);
-    replaced_inline = natural_size->inline_size;
-    replaced_block = natural_size->block_size;
-    // If lengths are constrained, keep aspect ratio.
-    // The side that shrank the most defines the other side.
-    LayoutUnit constrained_inline =
-        inline_min_max_sizes.ClampSizeToMinAndMax(*replaced_inline);
-    LayoutUnit constrained_block =
-        block_min_max_sizes.ClampSizeToMinAndMax(*replaced_block);
-    if (constrained_inline != replaced_inline ||
-        constrained_block != replaced_block) {
-      LayoutUnit inline_ratio =
-          (*replaced_inline - border_padding.InlineSum()) == LayoutUnit()
-              ? LayoutUnit::Max()
-              : (constrained_inline - border_padding.InlineSum()) /
-                    (*replaced_inline - border_padding.InlineSum());
-      LayoutUnit block_ratio =
-          (*replaced_block - border_padding.BlockSum()) == LayoutUnit()
-              ? LayoutUnit::Max()
-              : (constrained_block - border_padding.BlockSum()) /
-                    (*replaced_block - border_padding.BlockSum());
+    return LogicalSize(*replaced_inline, *replaced_block);
+  }
 
-      // The following implements spec table from section 10.4 at
-      // https://www.w3.org/TR/CSS22/visudet.html#min-max-widths
-      // Translating specs to code:
-      // inline_ratio < 1 => w > max_width
-      // inline_ratio > 1 => w < min_width
-      // block_ratio < 1 => h > max_height
-      // block_ratio > 1 => h < min_height
-      LayoutUnit one_unit(1);
-      if (inline_ratio != one_unit || block_ratio != one_unit) {
-        if ((inline_ratio < one_unit && block_ratio > one_unit) ||
-            (inline_ratio > one_unit && block_ratio < one_unit)) {
-          // Constraints caused us to grow in one dimension and shrink in the
-          // other. Use both constrained sizes.
-          replaced_inline = constrained_inline;
-          replaced_block = constrained_block;
-        } else if (block_ratio == one_unit ||
-                   (inline_ratio < one_unit && inline_ratio <= block_ratio) ||
-                   (inline_ratio > one_unit && inline_ratio >= block_ratio)) {
-          // The inline size got constrained more extremely than the block size.
-          // Use constrained inline size, re-calculate block size from aspect
-          // ratio.
-          replaced_inline = constrained_inline;
-          replaced_block = ComputeBlockFromInline(constrained_block);
-        } else {
-          // The block size got constrained more extremely than the inline size.
-          // Use constrained block size, re-calculate inline size from aspect
-          // ratio.
-          replaced_block = constrained_block;
-          replaced_inline = ComputeInlineFromBlock(constrained_inline);
-        }
-      }
+  // Both lengths are unknown, start with the natural-size.
+  DCHECK(!replaced_inline);
+  DCHECK(!replaced_block);
+  replaced_inline = natural_size->inline_size;
+  replaced_block = natural_size->block_size;
+
+  // Apply the min/max sizes to the natural-size.
+  const LayoutUnit constrained_inline =
+      inline_min_max_sizes.ClampSizeToMinAndMax(*replaced_inline);
+  const LayoutUnit constrained_block =
+      block_min_max_sizes.ClampSizeToMinAndMax(*replaced_block);
+
+  // If the min/max sizes had no effect, just return the natural-size.
+  if (constrained_inline == replaced_inline &&
+      constrained_block == replaced_block)
+    return LogicalSize(*replaced_inline, *replaced_block);
+
+  // If the min/max sizes have applied try and respect the aspect-ratio (if
+  // present). The side which shrinks the most defines the other side.
+  const LayoutUnit inline_ratio =
+      (*replaced_inline - border_padding.InlineSum()) == LayoutUnit()
+          ? LayoutUnit::Max()
+          : (constrained_inline - border_padding.InlineSum()) /
+                (*replaced_inline - border_padding.InlineSum());
+  const LayoutUnit block_ratio =
+      (*replaced_block - border_padding.BlockSum()) == LayoutUnit()
+          ? LayoutUnit::Max()
+          : (constrained_block - border_padding.BlockSum()) /
+                (*replaced_block - border_padding.BlockSum());
+
+  // The following implements the table from section 10.4 at:
+  // https://www.w3.org/TR/CSS22/visudet.html#min-max-widths
+  //   inline_ratio < 1 => w > max_width
+  //   inline_ratio > 1 => w < min_width
+  //   block_ratio < 1 => h > max_height
+  //   block_ratio > 1 => h < min_height
+  const LayoutUnit one_unit(1);
+  if (inline_ratio != one_unit || block_ratio != one_unit) {
+    if ((inline_ratio < one_unit && block_ratio > one_unit) ||
+        (inline_ratio > one_unit && block_ratio < one_unit)) {
+      // Constraints caused us to grow in one dimension and shrink in the
+      // other. Use both constrained sizes.
+      replaced_inline = constrained_inline;
+      replaced_block = constrained_block;
+    } else if (block_ratio == one_unit ||
+               (inline_ratio < one_unit && inline_ratio <= block_ratio) ||
+               (inline_ratio > one_unit && inline_ratio >= block_ratio)) {
+      // The inline-size got constrained more extremely than the block-size.
+      // Use constrained inline-size, recalculate block-size from aspect-ratio.
+      replaced_inline = constrained_inline;
+      replaced_block = block_min_max_sizes.ClampSizeToMinAndMax(
+          ComputeBlockFromInline(constrained_block));
+    } else {
+      // The block-size got constrained more extremely than the inline-size.
+      // Use constrained block-size, recalculate inline-size from aspect-ratio.
+      replaced_block = constrained_block;
+      replaced_inline = inline_min_max_sizes.ClampSizeToMinAndMax(
+          ComputeInlineFromBlock(constrained_inline));
     }
   }
 
-  replaced_inline = inline_min_max_sizes.ClampSizeToMinAndMax(*replaced_inline);
-  replaced_block = block_min_max_sizes.ClampSizeToMinAndMax(*replaced_block);
-  out_replaced_size->emplace(*replaced_inline, *replaced_block);
+  return LogicalSize(*replaced_inline, *replaced_block);
 }
 
 int ResolveUsedColumnCount(int computed_count,
@@ -1334,10 +1338,9 @@
         node.ComputeMinMaxSizes(constraint_space.GetWritingMode(),
                                 MinMaxSizesType::kIntrinsic, constraint_space)
             .sizes;
-    base::Optional<LogicalSize> replaced_size;
     base::Optional<LogicalSize> aspect_ratio;
-    ComputeReplacedSize(node, constraint_space, intrinsic_min_max_sizes,
-                        &replaced_size, &aspect_ratio);
+    base::Optional<LogicalSize> replaced_size = ComputeReplacedSize(
+        node, constraint_space, intrinsic_min_max_sizes, &aspect_ratio);
     bool has_aspect_ratio_without_intrinsic_size =
         !replaced_size && aspect_ratio && !aspect_ratio->IsEmpty();
     if (has_aspect_ratio_without_intrinsic_size) {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.h b/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
index 377a9a9..09c6af6 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
@@ -443,11 +443,10 @@
 // This routine will return precisely one of |out_replaced_size| and
 // |out_aspect_ratio|. If |out_aspect_ratio| is filled in, both inline and block
 // componenents will be non-zero.
-CORE_EXPORT void ComputeReplacedSize(
+CORE_EXPORT base::Optional<LogicalSize> ComputeReplacedSize(
     const NGBlockNode&,
     const NGConstraintSpace&,
     const base::Optional<MinMaxSizes>&,
-    base::Optional<LogicalSize>* out_replaced_size,
     base::Optional<LogicalSize>* out_aspect_ratio);
 
 // Based on available inline size, CSS computed column-width, CSS computed
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index b38aff62..0a1d4ab 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -142,8 +142,11 @@
 
   const LayoutObject* current_container = container_builder_->GetLayoutObject();
   if (!container_builder_->HasOutOfFlowPositionedCandidates() &&
-      !To<LayoutBlock>(current_container)->HasPositionedObjects())
+      !To<LayoutBlock>(current_container)->HasPositionedObjects()) {
+    container_builder_
+        ->AdjustFixedposContainingBlockForFragmentainerDescendants();
     return;
+  }
 
   // If the container is display-locked, then we skip the layout of descendants,
   // so we can early out immediately.
@@ -330,7 +333,7 @@
     LogicalSize content_size = ShrinkLogicalSize(size, border);
     LogicalOffset container_offset =
         LogicalOffset(border.inline_start, border.block_start);
-    container_offset += candidate.containing_block_offset;
+    container_offset += candidate.containing_block.offset;
 
     ContainingBlockInfo containing_block_info{
         writing_direction, LogicalRect(container_offset, content_size)};
@@ -501,19 +504,8 @@
       if (IsContainingBlockForCandidate(candidate) &&
           (!only_layout || layout_box == only_layout)) {
         if (has_block_fragmentation_) {
-          // If the containing block is fragmented, adjust the offset to be from
-          // the first containing block fragment to the fragmentation context
-          // root. Also, adjust the static position to be relative to the
-          // adjusted containing block offset.
-          if (const auto* previous_break_token =
-                  container_builder_->PreviousBreakToken()) {
-            LayoutUnit previous_consumed_block_size =
-                previous_break_token->ConsumedBlockSize();
-            candidate.containing_block_offset.block_offset -=
-                previous_consumed_block_size;
-            candidate.static_position.offset.block_offset +=
-                previous_consumed_block_size;
-          }
+          container_builder_->AdjustOffsetsForFragmentainerDescendant(
+              candidate);
           container_builder_->AddOutOfFlowFragmentainerDescendant(candidate);
           continue;
         }
@@ -644,11 +636,20 @@
     for (const auto& descendant :
          multicol_box_fragment->OutOfFlowPositionedFragmentainerDescendants()) {
       const NGPhysicalContainerFragment* containing_block_fragment =
-          descendant.containing_block_fragment;
+          descendant.containing_block.fragment;
       LogicalOffset containing_block_offset =
-          converter.ToLogical(descendant.containing_block_offset,
+          converter.ToLogical(descendant.containing_block.offset,
                               containing_block_fragment->Size());
 
+      const NGPhysicalContainerFragment* fixedpos_containing_block_fragment =
+          descendant.fixedpos_containing_block.fragment;
+      LogicalOffset fixedpos_containing_block_offset;
+      if (fixedpos_containing_block_fragment) {
+        fixedpos_containing_block_offset =
+            converter.ToLogical(descendant.fixedpos_containing_block.offset,
+                                fixedpos_containing_block_fragment->Size());
+      }
+
       // The containing block offset should be the offset from the top of the
       // inner multicol to the start of the containing block (as if all of the
       // columns are placed one on top of the other). When propagating OOFs
@@ -658,6 +659,10 @@
       if (previous_column_break_token) {
         containing_block_offset.block_offset +=
             previous_column_break_token->ConsumedBlockSize();
+        if (fixedpos_containing_block_fragment) {
+          fixedpos_containing_block_offset.block_offset +=
+              previous_column_break_token->ConsumedBlockSize();
+        }
       }
 
       // The static position should remain relative to its containing block
@@ -673,8 +678,10 @@
           static_position,
           descendant.inline_container,
           /* needs_block_offset_adjustment */ false,
-          containing_block_offset,
-          containing_block_fragment};
+          NGLogicalContainingBlock(containing_block_offset,
+                                   containing_block_fragment),
+          NGLogicalContainingBlock(fixedpos_containing_block_offset,
+                                   fixedpos_containing_block_fragment)};
       oof_nodes_to_layout.push_back(node);
     }
     previous_column_break_token = current_column_break_token;
@@ -712,6 +719,14 @@
       NodeToLayout node_to_layout = {
           node_info, CalculateOffset(node_info, /* only_layout */ nullptr)};
 
+      // Determine the additional offset to add to the static position of any
+      // fixedpos descendants.
+      if (descendant.fixedpos_containing_block.fragment) {
+        node_to_layout.additional_fixedpos_offset =
+            node_to_layout.offset_info.offset -
+            descendant.fixedpos_containing_block.offset;
+      }
+
       // Determine in which fragmentainer this OOF element will start its layout
       // and adjust the offset to be relative to that fragmentainer.
       wtf_size_t start_index = 0;
@@ -776,26 +791,19 @@
     const NGLogicalOutOfFlowPositionedNode& oof_node) {
   NGBlockNode node = oof_node.node;
   const NGPhysicalContainerFragment* containing_block_fragment =
-      oof_node.containing_block_fragment;
+      oof_node.containing_block.fragment;
 
 #if DCHECK_IS_ON()
-  // We wait to layout OOF positioned nodes that are inside a fragmentation
-  // context once we reach the associated fragmentation context root. In this
-  // case, the containing block for the node will be found in
-  // |containing_block_fragment|. Otherwise, the containing block for the OOF
-  // positioned node should be found in the current |container_builder_|.
-  if (containing_block_fragment) {
-    DCHECK_EQ(containing_block_fragment->GetLayoutObject(),
-              node.GetLayoutBox()->ContainingBlock());
-  } else {
-    // "NGOutOfFlowLayoutPart container is ContainingBlock" invariant cannot
-    // be enforced for tables. Tables are special, in that the ContainingBlock
-    // is TABLE, but constraint space is generated by TBODY/TR/. This happens
-    // because TBODY/TR are not LayoutBlocks, but LayoutBoxModelObjects.
-    DCHECK((container_builder_->GetLayoutObject() ==
-            node.GetLayoutBox()->ContainingBlock()) ||
-           node.GetLayoutBox()->ContainingBlock()->IsTable());
-  }
+  const LayoutObject* container =
+      containing_block_fragment ? containing_block_fragment->GetLayoutObject()
+                                : container_builder_->GetLayoutObject();
+
+  // "NGOutOfFlowLayoutPart container is ContainingBlock" invariant cannot
+  // be enforced for tables. Tables are special, in that the ContainingBlock
+  // is TABLE, but constraint space is generated by TBODY/TR/. This happens
+  // because TBODY/TR are not LayoutBlocks, but LayoutBoxModelObjects.
+  DCHECK((container == node.GetLayoutBox()->ContainingBlock()) ||
+         node.GetLayoutBox()->ContainingBlock()->IsTable());
 #endif
 
   const ContainingBlockInfo container_info =
@@ -816,11 +824,11 @@
   // be relative to the container's padding-box. Since
   // |container_info.rect.offset| is relative to its fragmentainer in this
   // case, we also need to adjust the offset to account for this.
-  DCHECK(oof_node.containing_block_offset == LogicalOffset() ||
+  DCHECK(oof_node.containing_block.offset == LogicalOffset() ||
          containing_block_fragment);
   NGLogicalStaticPosition static_position = oof_node.static_position;
   static_position.offset -=
-      container_info.rect.offset - oof_node.containing_block_offset;
+      container_info.rect.offset - oof_node.containing_block.offset;
 
   NGLogicalStaticPosition oof_static_position =
       static_position
@@ -836,10 +844,16 @@
   builder.SetAvailableSize(container_content_size);
   builder.SetPercentageResolutionSize(container_content_size);
 
+  DCHECK(!oof_node.fixedpos_containing_block.fragment ||
+         containing_block_fragment);
+  DCHECK(oof_node.fixedpos_containing_block.offset == LogicalOffset() ||
+         oof_node.fixedpos_containing_block.fragment);
+
   return NodeInfo(node, builder.ToConstraintSpace(), oof_static_position,
                   container_physical_content_size, container_info,
                   default_writing_direction,
                   /* is_fragmentainer_descendant */ containing_block_fragment,
+                  oof_node.fixedpos_containing_block,
                   oof_node.inline_container);
 }
 
@@ -997,8 +1011,9 @@
   base::Optional<LogicalSize> aspect_ratio;
   bool has_aspect_ratio_without_intrinsic_size = false;
   if (is_replaced) {
-    ComputeReplacedSize(node_info.node, node_info.constraint_space,
-                        min_max_sizes, &replaced_size, &aspect_ratio);
+    replaced_size =
+        ComputeReplacedSize(node_info.node, node_info.constraint_space,
+                            min_max_sizes, &aspect_ratio);
     DCHECK(replaced_size.has_value() != aspect_ratio.has_value());
     has_aspect_ratio_without_intrinsic_size = aspect_ratio.has_value();
     // If we only have aspect ratio, and no replaced size, intrinsic size
@@ -1013,11 +1028,6 @@
   } else if (!candidate_style.AspectRatio().IsAuto()) {
     has_aspect_ratio_without_intrinsic_size = true;
     aspect_ratio = node_info.node.GetAspectRatio();
-  } else if (should_be_considered_as_replaced) {
-    replaced_size =
-        LogicalSize{min_max_sizes->ShrinkToFit(
-                        node_info.constraint_space.AvailableSize().inline_size),
-                    kIndefiniteSize};
   }
 
   ComputeOutOfFlowInlineDimensions(
@@ -1025,11 +1035,6 @@
       node_info.static_position, min_max_sizes, minmax_intrinsic_sizes_for_ar,
       replaced_size, container_writing_direction, &offset_info.node_dimensions);
 
-  // |should_be_considered_as_replaced| sets the inline-size.
-  // It does not set the block-size. This is a compatibility quirk.
-  if (!is_replaced && should_be_considered_as_replaced)
-    replaced_size.reset();
-
   // Elements with only aspect ratio compute their block size from
   // inline size and aspect ratio.
   // https://www.w3.org/TR/css-sizing-3/#intrinsic-sizes
@@ -1323,9 +1328,23 @@
     result->GetMutableForOutOfFlow().SetOutOfFlowPositionedOffset(
         oof_offset, allow_first_tier_oof_cache_);
   }
+  LogicalOffset additional_fixedpos_offset =
+      descendant.additional_fixedpos_offset;
+  if (descendant.break_token &&
+      descendant.node_info.fixedpos_containing_block.fragment) {
+    // Currently, |additional_fixedpos_offset| is the offset from the top of
+    // |descendant| to the fixedpos containing block. Adjust this so that it
+    // includes the block contribution of |descendant| from previous
+    // fragmentainers. This ensures that any fixedpos descendants in the current
+    // fragmentainer have the correct static position.
+    additional_fixedpos_offset.block_offset +=
+        descendant.break_token->ConsumedBlockSize();
+  }
   container_builder_->PropagateOOFPositionedInfo(
       result->PhysicalFragment(), result->OutOfFlowPositionedOffset(),
-      fragmentainer_consumed_block_size_);
+      fragmentainer_consumed_block_size_, /* inline_container */ nullptr,
+      &descendant.node_info.fixedpos_containing_block,
+      additional_fixedpos_offset);
   algorithm->AppendOutOfFlowResult(result);
 
   const auto& physical_fragment =
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
index db3d3f6..424324f 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
@@ -30,6 +30,7 @@
 class NGPhysicalContainerFragment;
 class NGSimplifiedOOFLayoutAlgorithm;
 struct NGLink;
+struct NGLogicalContainingBlock;
 struct NGLogicalOutOfFlowPositionedNode;
 
 // Helper class for positioning of out-of-flow blocks.
@@ -117,6 +118,7 @@
     PhysicalSize container_physical_content_size;
     const ContainingBlockInfo container_info;
     const WritingDirectionMode default_writing_direction;
+    const NGLogicalContainingBlock& fixedpos_containing_block;
     bool inline_container = false;
 
     NodeInfo(NGBlockNode node,
@@ -126,6 +128,7 @@
              const ContainingBlockInfo container_info,
              const WritingDirectionMode default_writing_direction,
              bool is_fragmentainer_descendant,
+             const NGLogicalContainingBlock& fixedpos_containing_block,
              bool inline_container)
         : node(node),
           constraint_space(constraint_space),
@@ -133,6 +136,7 @@
           container_physical_content_size(container_physical_content_size),
           container_info(container_info),
           default_writing_direction(default_writing_direction),
+          fixedpos_containing_block(fixedpos_containing_block),
           inline_container(inline_container) {}
 
     void Trace(Visitor* visitor) const;
@@ -172,6 +176,14 @@
     OffsetInfo offset_info;
     Member<const NGBlockBreakToken> break_token;
 
+    // If an OOF element is fragmented, it gets laid out once it reaches the
+    // fragmentation context root. If that element has any fixedpos descendants
+    // whose containing block lives inside the same fragmentation context root,
+    // we'll need to adjust its static position to be relative to that
+    // containing block. |additional_fixedpos_offset| is used to make this
+    // adjustment.
+    LogicalOffset additional_fixedpos_offset;
+
     void Trace(Visitor* visitor) const;
   };
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h
index 6f648b37..582b617e0 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h
@@ -13,6 +13,48 @@
 
 namespace blink {
 
+// If an out-of-flow positioned element is inside a fragmentation context, it
+// will be laid out once it reaches the fragmentation context root rather than
+// once it reaches its containing block. A physical containing block holds the
+// containing block information needed to place these OOF positioned nodes once
+// they reach the fragmentation context root. See
+// NGPhysicalOutOfFlowPositionedNode for more details.
+// TODO(almaher): Update NGPhysicalContainingBlock and NGLogicalContainingBlock
+// to a single templated class if no other member variables are added.
+struct NGPhysicalContainingBlock {
+  DISALLOW_NEW();
+
+ public:
+  PhysicalOffset offset;
+  Member<const NGPhysicalContainerFragment> fragment;
+
+  NGPhysicalContainingBlock() : fragment(nullptr) {}
+
+  NGPhysicalContainingBlock(PhysicalOffset offset,
+                            const NGPhysicalContainerFragment* fragment)
+      : offset(offset), fragment(std::move(fragment)) {}
+
+  void Trace(Visitor* visitor) const { visitor->Trace(fragment); }
+};
+
+// The logical version of above. See NGLogicalOutOfFlowPositionedNode for more
+// details.
+struct NGLogicalContainingBlock {
+  DISALLOW_NEW();
+
+ public:
+  LogicalOffset offset;
+  Member<const NGPhysicalContainerFragment> fragment;
+
+  NGLogicalContainingBlock() : fragment(nullptr) {}
+
+  NGLogicalContainingBlock(LogicalOffset offset,
+                           const NGPhysicalContainerFragment* fragment)
+      : offset(offset), fragment(std::move(fragment)) {}
+
+  void Trace(Visitor* visitor) const { visitor->Trace(fragment); }
+};
+
 // A physical out-of-flow positioned-node is an element with the style
 // "postion: absolute" or "position: fixed" which hasn't been bubbled up to its
 // containing block yet, (e.g. an element with "position: relative"). As soon
@@ -31,6 +73,12 @@
 // addition, the containing block offset is needed to compute the start offset
 // and the initial fragmentainer of an out-of-flow positioned-node.
 //
+// If an OOF node in a fragmentation context has fixedpos descendants, those
+// descendants will not find their containing block if the containing block
+// lives inside the fragmentation context root. Thus, we also need to store
+// information on the containing block for any fixedpos descendants, if one
+// exists.
+//
 // This is struct is allowed to be stored/persisted.
 //
 // [1] https://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-width
@@ -42,20 +90,21 @@
   NGPhysicalStaticPosition static_position;
   // Continuation root of the optional inline container.
   Member<const LayoutInline> inline_container;
-  PhysicalOffset containing_block_offset;
-  Member<const NGPhysicalContainerFragment> containing_block_fragment;
+  NGPhysicalContainingBlock containing_block;
+  NGPhysicalContainingBlock fixedpos_containing_block;
 
   NGPhysicalOutOfFlowPositionedNode(
       NGBlockNode node,
       NGPhysicalStaticPosition static_position,
       const LayoutInline* inline_container = nullptr,
-      PhysicalOffset containing_block_offset = PhysicalOffset(),
-      const NGPhysicalContainerFragment* containing_block_fragment = nullptr)
+      NGPhysicalContainingBlock containing_block = NGPhysicalContainingBlock(),
+      NGPhysicalContainingBlock fixedpos_containing_block =
+          NGPhysicalContainingBlock())
       : node(node),
         static_position(static_position),
         inline_container(inline_container),
-        containing_block_offset(containing_block_offset),
-        containing_block_fragment(std::move(containing_block_fragment)) {
+        containing_block(containing_block),
+        fixedpos_containing_block(fixedpos_containing_block) {
     DCHECK(!inline_container ||
            inline_container == inline_container->ContinuationRoot());
   }
@@ -63,7 +112,8 @@
   void Trace(Visitor* visitor) const {
     visitor->Trace(node);
     visitor->Trace(inline_container);
-    visitor->Trace(containing_block_fragment);
+    visitor->Trace(containing_block);
+    visitor->Trace(fixedpos_containing_block);
   }
 };
 
@@ -83,8 +133,8 @@
   Member<const LayoutInline> inline_container;
   bool needs_block_offset_adjustment;
   const LayoutUnit fragmentainer_consumed_block_size;
-  LogicalOffset containing_block_offset;
-  Member<const NGPhysicalContainerFragment> containing_block_fragment;
+  NGLogicalContainingBlock containing_block;
+  NGLogicalContainingBlock fixedpos_containing_block;
   base::Optional<LogicalRect> containing_block_rect;
 
   NGLogicalOutOfFlowPositionedNode(
@@ -92,15 +142,16 @@
       NGLogicalStaticPosition static_position,
       const LayoutInline* inline_container = nullptr,
       bool needs_block_offset_adjustment = false,
-      LogicalOffset containing_block_offset = LogicalOffset(),
-      const NGPhysicalContainerFragment* containing_block_fragment = nullptr,
+      NGLogicalContainingBlock containing_block = NGLogicalContainingBlock(),
+      NGLogicalContainingBlock fixedpos_containing_block =
+          NGLogicalContainingBlock(),
       const base::Optional<LogicalRect> containing_block_rect = base::nullopt)
       : node(node),
         static_position(static_position),
         inline_container(inline_container),
         needs_block_offset_adjustment(needs_block_offset_adjustment),
-        containing_block_offset(containing_block_offset),
-        containing_block_fragment(std::move(containing_block_fragment)),
+        containing_block(containing_block),
+        fixedpos_containing_block(fixedpos_containing_block),
         containing_block_rect(containing_block_rect) {
     DCHECK(!inline_container ||
            inline_container == inline_container->ContinuationRoot());
@@ -109,7 +160,8 @@
   void Trace(Visitor* visitor) const {
     visitor->Trace(node);
     visitor->Trace(inline_container);
-    visitor->Trace(containing_block_fragment);
+    visitor->Trace(containing_block);
+    visitor->Trace(fixedpos_containing_block);
   }
 };
 
@@ -119,5 +171,8 @@
     blink::NGPhysicalOutOfFlowPositionedNode)
 WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(
     blink::NGLogicalOutOfFlowPositionedNode)
+WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(
+    blink::NGPhysicalContainingBlock)
+WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(blink::NGLogicalContainingBlock)
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_OUT_OF_FLOW_POSITIONED_NODE_H_
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
index 3e51da1..e9d3b1ada 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -380,12 +380,20 @@
         descendant.node,
         descendant.static_position.ConvertToPhysical(converter),
         descendant.inline_container,
-        descendant.containing_block_offset.ConvertToPhysical(
-            builder->Style().GetWritingDirection(), size,
-            descendant.containing_block_fragment
-                ? descendant.containing_block_fragment->Size()
-                : PhysicalSize()),
-        descendant.containing_block_fragment);
+        NGPhysicalContainingBlock(
+            descendant.containing_block.offset.ConvertToPhysical(
+                builder->Style().GetWritingDirection(), size,
+                descendant.containing_block.fragment
+                    ? descendant.containing_block.fragment->Size()
+                    : PhysicalSize()),
+            descendant.containing_block.fragment),
+        NGPhysicalContainingBlock(
+            descendant.fixedpos_containing_block.offset.ConvertToPhysical(
+                builder->Style().GetWritingDirection(), size,
+                descendant.fixedpos_containing_block.fragment
+                    ? descendant.fixedpos_containing_block.fragment->Size()
+                    : PhysicalSize()),
+            descendant.fixedpos_containing_block.fragment));
   }
   if (builder->HasMulticolsWithPendingOOFs()) {
     multicols_with_pending_oofs =
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index 2c3ae44..6aa5b80 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -465,18 +465,6 @@
     return kIgnoreObject;
   }
 
-  // If this element has aria attributes on it, it should not be ignored.
-  if (HasGlobalARIAAttribute())
-    return kIncludeObject;
-
-  bool has_non_empty_alt_attribute = !GetAttribute(kAltAttr).IsEmpty();
-  if (IsImage()) {
-    if (has_non_empty_alt_attribute || GetAttribute(kAltAttr).IsNull())
-      return kIncludeObject;
-    else if (ignored_reasons)
-      ignored_reasons->push_back(IgnoredReason(kAXEmptyAlt));
-    return kIgnoreObject;
-  }
   // Using the title or accessibility description (so we
   // check if there's some kind of accessible name for the element)
   // to decide an element's visibility is not as definitive as
@@ -486,8 +474,20 @@
   // for example, any element having an alt attribute will make it
   // not ignored, rather than just images.
   if (HasAriaAttribute() || !GetAttribute(kTitleAttr).IsEmpty() ||
-      has_non_empty_alt_attribute)
+      !GetAttribute(kAltAttr).IsEmpty()) {
     return kIncludeObject;
+  }
+
+  if (IsImage()) {
+    // A null alt attribute means the attribute is not present. We assume this
+    // is a mistake, and expose the image so that it can be repaired.
+    // In contrast, alt="" is treated as intentional markup to ignore the image.
+    if (GetAttribute(kAltAttr).IsNull())
+      return kIncludeObject;
+    else if (ignored_reasons)
+      ignored_reasons->push_back(IgnoredReason(kAXEmptyAlt));
+    return kIgnoreObject;
+  }
 
   // <span> tags are inline tags and not meant to convey information if they
   // have no other ARIA information on them. If we don't ignore them, they may
@@ -2680,25 +2680,6 @@
   return aria_role_;
 }
 
-bool AXNodeObject::HasAriaAttribute() const {
-  Element* element = GetElement();
-  if (!element)
-    return false;
-
-  // Explicit ARIA role should be considered an aria attribute.
-  if (AriaRoleAttribute() != ax::mojom::blink::Role::kUnknown)
-    return true;
-
-  AttributeCollection attributes = element->AttributesWithoutUpdate();
-  for (const Attribute& attr : attributes) {
-    // Attributes cache their uppercase names.
-    if (attr.GetName().LocalNameUpper().StartsWith("ARIA-"))
-      return true;
-  }
-
-  return false;
-}
-
 void AXNodeObject::AriaDescribedbyElements(AXObjectVector& describedby) const {
   AccessibilityChildrenFromAOMProperty(AOMRelationListProperty::kDescribedBy,
                                        describedby);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.h b/third_party/blink/renderer/modules/accessibility/ax_node_object.h
index 7240291..bda96ed4f 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.h
@@ -181,7 +181,6 @@
 
   // ARIA attributes.
   ax::mojom::blink::Role AriaRoleAttribute() const final;
-  bool HasAriaAttribute() const override;
   void AriaDescribedbyElements(AXObjectVector&) const override;
   void AriaOwnsElements(AXObjectVector&) const override;
   bool SupportsARIADragging() const override;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc
index 3bbdf0e..70a434f 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -3451,76 +3451,69 @@
   }
 }
 
-bool IsGlobalARIAAttribute(const AtomicString& name) {
-  if (!name.StartsWith("ARIA"))
-    return false;
-  if (name.StartsWith("ARIA-ATOMIC"))
-    return true;
-  if (name.StartsWith("ARIA-BUSY"))
-    return true;
-  if (name.StartsWith("ARIA-CONTROLS"))
-    return true;
-  if (name.StartsWith("ARIA-CURRENT"))
-    return true;
-  if (name.StartsWith("ARIA-DESCRIBEDBY"))
-    return true;
-  if (name.StartsWith("ARIA-DETAILS"))
-    return true;
-  if (name.StartsWith("ARIA-DISABLED"))
-    return true;
-  if (name.StartsWith("ARIA-DROPEFFECT"))
-    return true;
-  if (name.StartsWith("ARIA-ERRORMESSAGE"))
-    return true;
-  if (name.StartsWith("ARIA-FLOWTO"))
-    return true;
-  if (name.StartsWith("ARIA-GRABBED"))
-    return true;
-  if (name.StartsWith("ARIA-HASPOPUP"))
-    return true;
-  if (name.StartsWith("ARIA-HIDDEN"))
-    return true;
-  if (name.StartsWith("ARIA-INVALID"))
-    return true;
-  if (name.StartsWith("ARIA-KEYSHORTCUTS"))
-    return true;
-  if (name.StartsWith("ARIA-LABEL"))
-    return true;
-  if (name.StartsWith("ARIA-LABELEDBY"))
-    return true;
-  if (name.StartsWith("ARIA-LABELLEDBY"))
-    return true;
-  if (name.StartsWith("ARIA-LIVE"))
-    return true;
-  if (name.StartsWith("ARIA-OWNS"))
-    return true;
-  if (name.StartsWith("ARIA-RELEVANT"))
-    return true;
-  if (name.StartsWith("ARIA-ROLEDESCRIPTION"))
-    return true;
-  return false;
+bool DoesUndoRolePresentation(const AtomicString& name) {
+  // This is the list of global ARIA properties that force
+  // role="presentation"/"none" to be exposed, and does not contain ARIA
+  // properties who's global status is being deprecated.
+  // TODO(accessibility) aria-label/labelledby is not allowed on
+  // role="none"/"presentation", therefore it should not be listed here.
+  // However, this breaks a few name tests that assume aria-label causes
+  // role="none"/"presentation" to be exposed, even though the property is
+  // prohibited there. See https://github.com/w3c/accname/issues/121.
+  // clang-format off
+  DEFINE_STATIC_LOCAL(
+      HashSet<AtomicString>, aria_global_properties,
+      ({
+        "ARIA-ATOMIC",
+        // TODO(accessibility/ARIA 1.3) Add these (and test in aria-global.html)
+        // "ARIA-BRAILLELABEL",
+        // "ARIA-BRAILLEROLEDESCRIPTION",
+        "ARIA-BUSY",
+        "ARIA-CONTROLS",
+        "ARIA-CURRENT",
+        "ARIA-DESCRIBEDBY",
+        "ARIA-DESCRIPTION",
+        "ARIA-DETAILS",
+        "ARIA-DROPEFFECT",
+        "ARIA-FLOWTO",
+        "ARIA-GRABBED",
+        "ARIA-HIDDEN",  // For aria-hidden=false.
+        "ARIA-KEYSHORTCUTS",
+        "ARIA-LABEL",
+        "ARIA-LABELEDBY",
+        "ARIA-LABELLEDBY",
+        "ARIA-LIVE",
+        "ARIA-OWNS",
+        "ARIA-RELEVANT",
+        "ARIA-ROLEDESCRIPTION"
+      }));
+  // clang-format on
+
+  return aria_global_properties.Contains(name);
 }
 
-bool AXObject::HasGlobalARIAAttribute() const {
+bool AXObject::HasAriaAttribute(bool does_undo_role_presentation) const {
   auto* element = GetElement();
   if (!element)
     return false;
 
+  // A role is considered an ARIA attribute.
+  if (!does_undo_role_presentation &&
+      AriaRoleAttribute() != ax::mojom::blink::Role::kUnknown) {
+    return true;
+  }
+
+  // Check for any attribute that begins with "aria-".
   AttributeCollection attributes = element->AttributesWithoutUpdate();
   for (const Attribute& attr : attributes) {
     // Attributes cache their uppercase names.
     auto name = attr.GetName().LocalNameUpper();
-    if (IsGlobalARIAAttribute(name))
-      return true;
+    if (name.StartsWith("ARIA-")) {
+      if (!does_undo_role_presentation || DoesUndoRolePresentation(name))
+        return true;
+    }
   }
-  if (!element->DidAttachInternals())
-    return false;
-  const auto& internals_attributes =
-      element->EnsureElementInternals().GetAttributes();
-  for (const QualifiedName& attr : internals_attributes.Keys()) {
-    if (IsGlobalARIAAttribute(attr.LocalNameUpper()))
-      return true;
-  }
+
   return false;
 }
 
@@ -3642,9 +3635,13 @@
     if (IsA<HTMLIFrameElement>(*GetNode()) || IsA<HTMLFrameElement>(*GetNode()))
       return ax::mojom::blink::Role::kIframePresentational;
     if ((GetElement() && GetElement()->SupportsFocus()) ||
-        HasGlobalARIAAttribute()) {
-      // If we return an unknown role, then the native HTML role would be used
-      // instead.
+        HasAriaAttribute(true /* does_undo_role_presentation */)) {
+      // Must be exposed with a role if focusable or has a global ARIA property
+      // that is allowed in this context. See
+      // https://w3c.github.io/aria/#presentation for more information about the
+      // conditions upon which elements with role="none"/"presentation" must be
+      // included in the tree. Return Role::kUnknown, so that the native HTML
+      // role is used instead.
       return ax::mojom::blink::Role::kUnknown;
     }
   }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.h b/third_party/blink/renderer/modules/accessibility/ax_object.h
index be6db222..cd9c7d3 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_object.h
@@ -821,7 +821,7 @@
   virtual ax::mojom::blink::Role DetermineAccessibilityRole();
   ax::mojom::blink::Role DetermineAriaRoleAttribute() const;
   virtual ax::mojom::blink::Role AriaRoleAttribute() const;
-  virtual bool HasAriaAttribute() const { return false; }
+  bool HasAriaAttribute(bool does_undo_role_presentation = false) const;
   virtual AXObject* ActiveDescendant() { return nullptr; }
   virtual String AutoComplete() const { return String(); }
   virtual void AriaOwnsElements(AXObjectVector& owns) const {}
@@ -838,7 +838,6 @@
   virtual bool IsRichlyEditable() const { return false; }
   bool AriaCheckedIsPresent() const;
   bool AriaPressedIsPresent() const;
-  bool HasGlobalARIAAttribute() const;
   bool SupportsARIAExpanded() const;
   virtual bool SupportsARIADragging() const { return false; }
   virtual void Dropeffects(
diff --git a/third_party/blink/renderer/modules/webcodecs/BUILD.gn b/third_party/blink/renderer/modules/webcodecs/BUILD.gn
index 0195014e..74120484 100644
--- a/third_party/blink/renderer/modules/webcodecs/BUILD.gn
+++ b/third_party/blink/renderer/modules/webcodecs/BUILD.gn
@@ -109,6 +109,7 @@
     "//testing/gtest",
     "//third_party/blink/public:test_headers",
     "//third_party/blink/renderer/controller:blink_bindings_test_sources",
+    "//third_party/blink/renderer/core:testing",
     "//third_party/blink/renderer/modules",
     "//third_party/blink/renderer/platform",
     "//third_party/blink/renderer/platform:test_support",
diff --git a/third_party/blink/renderer/modules/webcodecs/image_decoder_core.cc b/third_party/blink/renderer/modules/webcodecs/image_decoder_core.cc
index 412ed94e..17a9583 100644
--- a/third_party/blink/renderer/modules/webcodecs/image_decoder_core.cc
+++ b/third_party/blink/renderer/modules/webcodecs/image_decoder_core.cc
@@ -255,7 +255,10 @@
   } else {
     DCHECK_EQ(data_size, 0u);
   }
-  decoder_->SetData(stream_buffer_, data_complete_);
+
+  // We may not have a decoder if Clear() was called while data arrives.
+  if (decoder_)
+    decoder_->SetData(stream_buffer_, data_complete_);
 }
 
 void ImageDecoderCore::Clear() {
diff --git a/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc b/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc
index 5b68896..0fa5df9 100644
--- a/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc
+++ b/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc
@@ -342,8 +342,10 @@
     if (available > 0 || data_complete != internal_data_complete_) {
       decoder_->AsyncCall(&ImageDecoderCore::AppendData)
           .WithArgs(available, std::move(data), data_complete);
-      DecodeMetadata();
-      MaybeSatisfyPendingDecodes();
+      if (tracks_->IsEmpty() || tracks_->selectedTrack()) {
+        DecodeMetadata();
+        MaybeSatisfyPendingDecodes();
+      }
     }
     internal_data_complete_ = data_complete;
   }
@@ -372,6 +374,7 @@
 void ImageDecoderExternal::MaybeSatisfyPendingDecodes() {
   DCHECK(!closed_);
   DCHECK(decoder_);
+  DCHECK(tracks_->IsEmpty() || tracks_->selectedTrack());
 
   for (auto& request : pending_decodes_) {
     if (failed_) {
@@ -490,6 +493,8 @@
 
 void ImageDecoderExternal::DecodeMetadata() {
   DCHECK(decoder_);
+  DCHECK(tracks_->IsEmpty() || tracks_->selectedTrack());
+
   decoder_->AsyncCall(&ImageDecoderCore::DecodeMetadata)
       .Then(CrossThreadBindOnce(&ImageDecoderExternal::OnMetadata,
                                 weak_factory_.GetWeakPtr()));
diff --git a/third_party/blink/renderer/modules/webcodecs/image_decoder_external_test.cc b/third_party/blink/renderer/modules/webcodecs/image_decoder_external_test.cc
index 50710df..8aeb79d 100644
--- a/third_party/blink/renderer/modules/webcodecs/image_decoder_external_test.cc
+++ b/third_party/blink/renderer/modules/webcodecs/image_decoder_external_test.cc
@@ -14,8 +14,11 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_image_decoder_init.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_image_track.h"
 #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
+#include "third_party/blink/renderer/core/streams/readable_stream.h"
+#include "third_party/blink/renderer/core/streams/test_underlying_source.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
@@ -342,8 +345,95 @@
   }
 }
 
-// TODO(crbug.com/1073995): Add tests for each format, selectTrack(), partial
-// decoding, and ImageBitmapOptions.
+TEST_F(ImageDecoderTest, DecoderReadableStream) {
+  V8TestingScope v8_scope;
+  constexpr char kImageType[] = "image/gif";
+  EXPECT_TRUE(IsTypeSupported(&v8_scope, kImageType));
+
+  auto data = ReadFile("images/resources/animated.gif");
+
+  Persistent<TestUnderlyingSource> underlying_source =
+      MakeGarbageCollected<TestUnderlyingSource>(v8_scope.GetScriptState());
+  Persistent<ReadableStream> stream =
+      ReadableStream::CreateWithCountQueueingStrategy(v8_scope.GetScriptState(),
+                                                      underlying_source, 0);
+
+  auto* init = MakeGarbageCollected<ImageDecoderInit>();
+  init->setType(kImageType);
+  init->setData(
+      ArrayBufferOrArrayBufferViewOrReadableStream::FromReadableStream(stream));
+
+  Persistent<ImageDecoderExternal> decoder = ImageDecoderExternal::Create(
+      v8_scope.GetScriptState(), init, IGNORE_EXCEPTION_FOR_TESTING);
+  ASSERT_TRUE(decoder);
+  ASSERT_FALSE(v8_scope.GetExceptionState().HadException());
+  EXPECT_EQ(decoder->type(), "image/gif");
+
+  constexpr size_t kNumChunks = 2;
+  const size_t chunk_size = (data->size() + 1) / kNumChunks;
+
+  const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(data->Data());
+  underlying_source->Enqueue(ScriptValue(
+      v8_scope.GetIsolate(), ToV8(DOMUint8Array::Create(data_ptr, chunk_size),
+                                  v8_scope.GetScriptState())));
+
+  // Ensure we have metadata.
+  {
+    auto promise = decoder->decodeMetadata();
+    ScriptPromiseTester tester(v8_scope.GetScriptState(), promise);
+    tester.WaitUntilSettled();
+    ASSERT_TRUE(tester.IsFulfilled());
+  }
+
+  // Deselect the current track.
+  ASSERT_TRUE(decoder->tracks().selectedTrack());
+  decoder->tracks().selectedTrack().value()->setSelected(false);
+
+  // Enqueue remaining data.
+  underlying_source->Enqueue(
+      ScriptValue(v8_scope.GetIsolate(),
+                  ToV8(DOMUint8Array::Create(data_ptr + chunk_size,
+                                             data->size() - chunk_size),
+                       v8_scope.GetScriptState())));
+  underlying_source->Close();
+
+  // Metadata should resolve okay while no track is selected.
+  {
+    auto promise = decoder->decodeMetadata();
+    ScriptPromiseTester tester(v8_scope.GetScriptState(), promise);
+    tester.WaitUntilSettled();
+    ASSERT_TRUE(tester.IsFulfilled());
+  }
+
+  // Decodes should be rejected while no track is selected.
+  {
+    auto promise = decoder->decode();
+    ScriptPromiseTester tester(v8_scope.GetScriptState(), promise);
+    tester.WaitUntilSettled();
+    EXPECT_TRUE(tester.IsRejected());
+  }
+
+  // Select a track again.
+  decoder->tracks().AnonymousIndexedGetter(0)->setSelected(true);
+
+  // Verify a decode completes successfully.
+  {
+    auto promise = decoder->decode();
+    ScriptPromiseTester tester(v8_scope.GetScriptState(), promise);
+    tester.WaitUntilSettled();
+    ASSERT_TRUE(tester.IsFulfilled());
+    auto* result = ToImageDecodeResult(&v8_scope, tester.Value());
+    EXPECT_TRUE(result->complete());
+
+    auto* frame = result->image();
+    EXPECT_EQ(frame->duration(), 0u);
+    EXPECT_EQ(frame->displayWidth(), 16u);
+    EXPECT_EQ(frame->displayHeight(), 16u);
+  }
+}
+
+// TODO(crbug.com/1073995): Add tests for each format, partial decoding,
+// reduced resolution decoding, premultiply, and ignored color behavior.
 
 }  // namespace
 
diff --git a/third_party/blink/renderer/modules/webcodecs/image_decoder_fuzzer.cc b/third_party/blink/renderer/modules/webcodecs/image_decoder_fuzzer.cc
index 0eace21..08ec14f8 100644
--- a/third_party/blink/renderer/modules/webcodecs/image_decoder_fuzzer.cc
+++ b/third_party/blink/renderer/modules/webcodecs/image_decoder_fuzzer.cc
@@ -144,6 +144,11 @@
       // Promises will be fulfilled synchronously since we're using an array
       // buffer based source.
       RunFuzzingLoop(image_decoder, proto.invocations());
+
+      // Close out underlying decoder to simplify reproduction analysis.
+      image_decoder->close();
+      image_decoder = nullptr;
+      base::RunLoop().RunUntilIdle();
     }
 
     Persistent<TestUnderlyingSource> underlying_source =
@@ -157,6 +162,7 @@
             stream));
     image_decoder = ImageDecoderExternal::Create(
         script_state, image_decoder_init, IGNORE_EXCEPTION_FOR_TESTING);
+    image_decoder_init = nullptr;
 
     if (image_decoder) {
       // Split the image data into chunks.
@@ -176,6 +182,7 @@
       }
 
       underlying_source->Close();
+      data_copy = nullptr;
 
       // Run one additional loop after all data has been appended.
       RunFuzzingLoop(image_decoder, proto.invocations());
diff --git a/third_party/blink/renderer/platform/graphics/filters/filter.cc b/third_party/blink/renderer/platform/graphics/filters/filter.cc
index 809c889a..4aef7f8 100644
--- a/third_party/blink/renderer/platform/graphics/filters/filter.cc
+++ b/third_party/blink/renderer/platform/graphics/filters/filter.cc
@@ -78,13 +78,14 @@
   return scale_ * value;
 }
 
-FloatPoint3D Filter::Resolve3dPoint(const FloatPoint3D& point) const {
-  if (unit_scaling_ != kBoundingBox)
-    return point;
-  return FloatPoint3D(
-      point.X() * ReferenceBox().Width() + ReferenceBox().X(),
-      point.Y() * ReferenceBox().Height() + ReferenceBox().Y(),
-      point.Z() * sqrtf(ReferenceBox().Size().DiagonalLengthSquared() / 2));
+FloatPoint3D Filter::Resolve3dPoint(FloatPoint3D point) const {
+  if (unit_scaling_ == kBoundingBox) {
+    point = FloatPoint3D(
+        point.X() * ReferenceBox().Width() + ReferenceBox().X(),
+        point.Y() * ReferenceBox().Height() + ReferenceBox().Y(),
+        point.Z() * sqrtf(ReferenceBox().Size().DiagonalLengthSquared() / 2));
+  }
+  return scale_ * point;
 }
 
 void Filter::SetLastEffect(FilterEffect* effect) {
diff --git a/third_party/blink/renderer/platform/graphics/filters/filter.h b/third_party/blink/renderer/platform/graphics/filters/filter.h
index 96aabe06..0c87f02 100644
--- a/third_party/blink/renderer/platform/graphics/filters/filter.h
+++ b/third_party/blink/renderer/platform/graphics/filters/filter.h
@@ -53,7 +53,7 @@
   float ApplyHorizontalScale(float value) const;
   float ApplyVerticalScale(float value) const;
 
-  FloatPoint3D Resolve3dPoint(const FloatPoint3D&) const;
+  FloatPoint3D Resolve3dPoint(FloatPoint3D) const;
 
   const FloatRect& FilterRegion() const { return filter_region_; }
   const FloatRect& ReferenceBox() const { return reference_box_; }
diff --git a/third_party/blink/renderer/platform/text/text_break_iterator_icu.cc b/third_party/blink/renderer/platform/text/text_break_iterator_icu.cc
index 0e8c60a..4fc5bdd 100644
--- a/third_party/blink/renderer/platform/text/text_break_iterator_icu.cc
+++ b/third_party/blink/renderer/platform/text/text_break_iterator_icu.cc
@@ -120,11 +120,11 @@
 
 const int kTextBufferCapacity = 16;
 
-typedef struct {
+struct UTextWithBuffer {
   DISALLOW_NEW();
   UText text;
   UChar buffer[kTextBufferCapacity];
-} UTextWithBuffer;
+};
 
 static inline int64_t TextPinIndex(int64_t& index, int64_t limit) {
   if (index < 0)
diff --git a/third_party/blink/web_tests/FlagExpectations/composite-after-paint b/third_party/blink/web_tests/FlagExpectations/composite-after-paint
index 140db859..106b066 100644
--- a/third_party/blink/web_tests/FlagExpectations/composite-after-paint
+++ b/third_party/blink/web_tests/FlagExpectations/composite-after-paint
@@ -60,3 +60,11 @@
 crbug.com/1191032 http/tests/devtools/tracing/frame-model-instrumentation.js [ Failure ]
 crbug.com/1191032 http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js [ Timeout ]
 crbug.com/1191032 virtual/threaded/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js [ Timeout ]
+
+# Tests pass with LayoutNGBlockFragmentation enabled and fail without. Tests
+# crash with CompositeAfterPaint enabled and LayoutNGBlockFragmentation
+# disabled.
+virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-029.html [ Pass ]
+virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-036.html [ Pass ]
+crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-029.html [ Crash Failure ]
+crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-036.html [ Crash Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index f28c900..3794958 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -990,6 +990,11 @@
 virtual/layout_ng_block_frag/external/wpt/css/css-break/fieldset-004.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/forced-break-at-fragmentainer-start-000.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-012.html [ Pass ]
+virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-029.html [ Pass ]
+virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-030.html [ Pass ]
+virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-032.html [ Pass ]
+virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-034.html [ Pass ]
+virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-036.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/overflow-clip-000.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/overflow-clip-001.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/overflowed-block-with-no-room-after-000.html [ Pass ]
@@ -3290,6 +3295,11 @@
 crbug.com/829028 external/wpt/css/css-break/fieldset-004.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/forced-break-at-fragmentainer-start-000.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-012.html [ Failure ]
+crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-029.html [ Failure ]
+crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-030.html [ Failure ]
+crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-032.html [ Failure ]
+crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-034.html [ Failure ]
+crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-036.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/overflow-clip-000.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/overflow-clip-001.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/overflowed-block-with-no-room-after-001.html [ Failure ]
diff --git a/third_party/blink/web_tests/WPTOverrideExpectations b/third_party/blink/web_tests/WPTOverrideExpectations
index 73c1464..5e3bc60 100644
--- a/third_party/blink/web_tests/WPTOverrideExpectations
+++ b/third_party/blink/web_tests/WPTOverrideExpectations
@@ -57,18 +57,15 @@
 external/wpt/input-events/input-events-get-target-ranges.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/input-events/input-events-typing.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/input-events/select-event-drag-remove.html [ Pass ] # wpt_use_checked_in_metadata
-crbug.com/1192099 external/wpt/pointerevents/compat/pointerevent_touch-action_two-finger_interaction.html [ Failure ]
 external/wpt/pointerevents/idlharness.window.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/inheritance.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/mouse-pointer-boundary-events-for-shadowdom.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_attributes_hoverable_pointers.html [ Pass ] # wpt_use_checked_in_metadata
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_attributes_nohover_pointers.html [ Failure ]
 external/wpt/pointerevents/pointerevent_auxclick_is_a_pointerevent.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_boundary_events_in_capturing.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_capture_mouse.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_capture_suppressing_mouse.html [ Pass ] # wpt_use_checked_in_metadata
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_change-touch-action-onpointerdown_touch.html [ Failure ]
 external/wpt/pointerevents/pointerevent_click_during_capture.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_click_is_a_pointerevent.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_coalesced_events_attributes.html [ Pass ] # wpt_use_checked_in_metadata
@@ -77,7 +74,6 @@
 external/wpt/pointerevents/pointerevent_disabled_form_control.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_element_haspointercapture.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_element_haspointercapture_release_pending_capture.html [ Pass ] # wpt_use_checked_in_metadata
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_fractional_coordinates.html?touch [ Failure ]
 external/wpt/pointerevents/pointerevent_iframe-touch-action-none_touch.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_lostpointercapture_for_disconnected_node.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_lostpointercapture_for_disconnected_node_in_shadow_dom.html [ Pass ] # wpt_use_checked_in_metadata
@@ -86,26 +82,22 @@
 external/wpt/pointerevents/pointerevent_mouse_capture_change_hover.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_mouse_pointercapture_inactivate_pointer.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_on_event_handlers.html [ Pass ] # wpt_use_checked_in_metadata
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_pointercancel_touch.html [ Failure ]
 external/wpt/pointerevents/pointerevent_pointercapture-in-custom-element.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_pointercapture-in-shadow-dom.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_pointercapture-not-lost-in-chorded-buttons.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_pointercapture_in_frame.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_pointerenter_does_not_bubble.html [ Pass ] # wpt_use_checked_in_metadata
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_pointerleave_after_pointercancel_touch.html [ Failure ]
 external/wpt/pointerevents/pointerevent_pointerleave_descendant_over.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_pointerleave_descendants.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_pointerleave_does_not_bubble.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_pointermove.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_pointermove_isprimary_same_as_pointerdown.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_pointermove_on_chorded_mouse_button.html [ Pass ] # wpt_use_checked_in_metadata
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_pointerout_after_pointercancel_touch.html [ Failure ]
 external/wpt/pointerevents/pointerevent_pointerout_pen.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_pointerout_received_once.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_pointerrawupdate.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_releasepointercapture_events_to_original_target.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_releasepointercapture_invalid_pointerid.html [ Pass ] # wpt_use_checked_in_metadata
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch.html [ Failure ]
 external/wpt/pointerevents/pointerevent_releasepointercapture_onpointerup_mouse.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_releasepointercapture_pointerup_mouse.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_releasepointercapture_pointerup_touch.html [ Pass ] # wpt_use_checked_in_metadata
@@ -125,30 +117,17 @@
 external/wpt/pointerevents/pointerevent_suppress_compat_events_on_click.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_suppress_compat_events_on_drag_mouse.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_tiltX_tiltY_to_azimuth_altitude.html [ Pass ] # wpt_use_checked_in_metadata
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_touch-action-auto-css_touch.html [ Failure ]
 external/wpt/pointerevents/pointerevent_touch-action-button-none-test_touch.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_touch-action-illegal.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-none_touch.html [ Pass ] # wpt_use_checked_in_metadata
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch.html [ Failure ]
 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch.html [ Pass ] # wpt_use_checked_in_metadata
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch.html [ Failure ]
 external/wpt/pointerevents/pointerevent_touch-action-inherit_parent-none_touch.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_touch-action-keyboard.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_touch-action-mouse.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_touch-action-none-css_touch.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_touch-action-none-on-body-when-style-propagates-to-viewport_touch.html [ Pass ] # wpt_use_checked_in_metadata
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_touch-action-pan-down-css_touch.html [ Failure ]
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_touch-action-pan-left-css_touch.html [ Failure ]
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_touch-action-pan-right-css_touch.html [ Failure ]
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_touch-action-pan-up-css_touch.html [ Failure ]
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch.html [ Failure ]
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch.html [ Failure ]
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch.html [ Failure ]
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch.html [ Failure ]
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_touch-action-span-none-test_touch.html [ Failure ]
 external/wpt/pointerevents/pointerevent_touch-action-svg-none-test_touch.html [ Pass ] # wpt_use_checked_in_metadata
-crbug.com/1192099 external/wpt/pointerevents/pointerevent_touch-action-table-none-test_touch.html [ Failure ]
 external/wpt/pointerevents/pointerevent_touch-action-verification.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/pointerevent_touch-adjustment_click_target.html [ Pass ] # wpt_use_checked_in_metadata
 external/wpt/pointerevents/compat/pointerevent_compat-mouse-events-when-removing-nodes.html [ Pass ] # wpt_use_checked_in_metadata
diff --git a/third_party/blink/web_tests/android/ChromiumWPTExpectations b/third_party/blink/web_tests/android/ChromiumWPTExpectations
index 3fba36ae..2c5a971 100644
--- a/third_party/blink/web_tests/android/ChromiumWPTExpectations
+++ b/third_party/blink/web_tests/android/ChromiumWPTExpectations
@@ -26,6 +26,161 @@
 crbug.com/1190392 external/wpt/trusted-types/WorkerGlobalScope-eval.html [ Failure ]
 crbug.com/1190392 external/wpt/trusted-types/WorkerGlobalScope-importScripts.html [ Failure ]
 crbug.com/1190392 external/wpt/trusted-types/worker-constructor.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/sandbox/shared-worker-sandbox.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/script-src-strict_dynamic_worker.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/worker-data-set-timeout.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/worker-importscripts.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/worker-set-timeout.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-child.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-fallback.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-list.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-none.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-self.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-worker-src-child-fallback-blocked.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-worker-src-child-fallback.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-worker-src-default-fallback.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-worker-src-script-fallback.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-worker-src-self-fallback.sub.html [ Failure ]
+
+# Failing CSP tests on Clank and WebLayer on Android
+crbug.com/1198079 external/wpt/content-security-policy/connect-src/shared-worker-connect-src-allowed.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/connect-src/shared-worker-connect-src-blocked.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/embedded-enforcement/subsumption_algorithm-source_list-wildcards.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-animation-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-animation.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-audio-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-audio.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-layout-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-layout.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-paint-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-paint.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/worklet-animation-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/worklet-audio-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/worklet-layout-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/worklet-paint-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/worker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/worker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-animation-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-animation.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-audio-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-audio.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-layout-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-layout.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-paint-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-paint.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/worklet-animation-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/worklet-audio-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/worklet-layout-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/worklet-paint-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/worker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/worker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/inside-worker/shared-inheritance.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/inside-worker/shared-script.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/inside-worker/shared-worker-report-only.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/navigate-to/spv-only-sent-to-initiator.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/object-src/object-src-url-allowed.html [ Crash Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/object-src/object-src-url-embed-allowed.html [ Crash Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/object-src/object-src-url-redirect-allowed.html [ Crash Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/object-src/object-src-url-redirect-blocked.sub.html [ Crash Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/sandbox/service-worker-sandbox.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/hash-always-converted-to-utf-8/iso-8859-1.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/hash-always-converted-to-utf-8/iso-8859-3.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/hash-always-converted-to-utf-8/iso-8859-7.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/hash-always-converted-to-utf-8/iso-8859-9.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/blockeduri-eval.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/blockeduri-inline.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/idlharness.window.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/inside-shared-worker.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/style-src/inline-style-allowed-while-cloning-objects.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/style-src/style-blocked.sub.html [ Failure ]
 
 # Reporting IDL failures on Android.
 crbug.com/1198081 external/wpt/reporting/idlharness.any.html [ Failure ]
@@ -80,6 +235,15 @@
 crbug.com/1198085 external/wpt/signed-exchange/sxg-utf8-inner-url.tentative.html [ Timeout ]
 crbug.com/1198085 external/wpt/signed-exchange/sxg-variants-match.tentative.html [ Failure ]
 
+# WebCodecs failures on Android.
+crbug.com/1198089 external/wpt/webcodecs/video-frame.any.html [ Failure ]
+crbug.com/1198089 external/wpt/webcodecs/video-frame.any.worker.html [ Failure ]
+crbug.com/1198089 external/wpt/webcodecs/videoFrame-canvasImageSource.html [ Failure ]
+crbug.com/1198089 external/wpt/webcodecs/videoFrame-createImageBitmap.any.html [ Failure ]
+crbug.com/1198089 external/wpt/webcodecs/videoFrame-createImageBitmap.any.worker.html [ Failure ]
+crbug.com/1198089 external/wpt/webcodecs/videoFrame-texImage.any.html [ Failure ]
+crbug.com/1198089 external/wpt/webcodecs/videoFrame-texImage.any.worker.html [ Failure ]
+
 # Add untriaged failures in this block
 crbug.com/1050754 external/wpt/FileAPI/file/File-constructor.html [ Failure Pass ]
 crbug.com/1050754 external/wpt/FileAPI/historical.https.html [ Failure Pass ]
@@ -486,87 +650,6 @@
 crbug.com/1050754 external/wpt/contacts/contacts-select.https.window.html [ Failure ]
 crbug.com/1050754 external/wpt/content-index/content-index.https.window.html [ Crash Failure ]
 crbug.com/1050754 external/wpt/content-index/idlharness.https.any.sharedworker.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/connect-src/connect-src-eventsource-blocked.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/connect-src/shared-worker-connect-src-allowed.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/connect-src/shared-worker-connect-src-blocked.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/connect-src/worker-connect-src-blocked.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/connect-src/worker-from-guid.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/form-action/form-action-src-redirect-blocked.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/frame-src/frame-src-same-document.sub.html [ Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/generic/no-default-src.sub.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/inside-worker/shared-inheritance.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/inside-worker/shared-script.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/media-src/media-src-7_1.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/media-src/media-src-redir-bug.sub.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/child-navigates-parent-blocked.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/form-blocked.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/form-cross-origin-blocked.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/form-redirected-blocked.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/href-location-blocked.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/href-location-cross-origin-blocked.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/href-location-redirected-blocked.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/link-click-blocked.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/link-click-cross-origin-blocked.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/link-click-redirected-blocked.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/meta-refresh-blocked.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/meta-refresh-cross-origin-blocked.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/meta-refresh-redirected-blocked.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/parent-navigates-child-blocked.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/spv-only-sent-to-initiator.sub.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/navigate-to/unsafe-allow-redirects/blocked-end-of-chain.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/navigation/javascript-url-navigation-inherits-csp.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/object-src/object-src-no-url-allowed.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/object-src/object-src-url-allowed.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/object-src/object-src-url-embed-allowed.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/object-src/object-src-url-redirect-allowed.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/plugin-types/plugintypes-mismatched-data.html [ Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/plugin-types/plugintypes-mismatched-url.html [ Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/plugin-types/plugintypes-nourl-allowed.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/prefetch-src/prefetch-blocked.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/prefetch-src/prefetch-header-blocked.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/reporting-api/reporting-api-doesnt-send-reports-without-violation.https.sub.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/reporting-api/reporting-api-report-only-sends-reports-on-violation.https.sub.html [ Failure Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/reporting-api/reporting-api-sends-reports-on-violation.https.sub.html [ Failure Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/reporting-api/reporting-api-works-on-frame-src.https.sub.html [ Failure Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/reporting/report-cross-origin-no-cookies.sub.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/reporting/report-only-in-meta.sub.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/hash-always-converted-to-utf-8/iso-8859-1.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/hash-always-converted-to-utf-8/iso-8859-3.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/hash-always-converted-to-utf-8/iso-8859-7.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/hash-always-converted-to-utf-8/iso-8859-9.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/script-src-1_10.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/script-src-strict_dynamic_double_policy_honor_source_expressions.html [ Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/script-src-strict_dynamic_hashes.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/script-src-strict_dynamic_in_img-src.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/script-src-strict_dynamic_worker.https.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/worker-importscripts-blocked.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/worker-set-timeout-blocked.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/blockeduri-eval.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/blockeduri-inline.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/idlharness.window.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html [ Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/inside-dedicated-worker.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/inside-service-worker.https.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/inside-shared-worker.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html [ Failure Pass ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/targeting.html [ Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/style-src/inline-style-allowed-while-cloning-objects.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/style-src/style-blocked.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/style-src/style-src-multiple-policies-multiple-hashing-algorithms.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/unsafe-eval/eval-blocked-in-about-blank-iframe.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-child.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-fallback.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-list.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-none.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-self.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-worker-src-child-fallback-blocked.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-worker-src-child-fallback.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-worker-src-default-fallback.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-worker-src-script-fallback.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-worker-src-self-fallback.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/cookie-store/change_eventhandler_for_document_cookie.tentative.https.window.html [ Failure Pass ]
 crbug.com/1050754 external/wpt/cookie-store/change_eventhandler_for_http_cookie_and_set_cookie_headers.tentative.https.window.html [ Failure Pass ]
 crbug.com/1050754 external/wpt/cookie-store/change_eventhandler_for_no_name_and_no_value.tentative.https.window.html [ Failure Pass ]
@@ -4486,8 +4569,6 @@
 crbug.com/1050754 external/wpt/webauthn/getcredential-rk-passing.https.html [ Crash Failure ]
 crbug.com/1050754 external/wpt/webauthn/getcredential-timeout.https.html [ Crash Failure ]
 crbug.com/1050754 external/wpt/webauthn/webauthn-testdriver-basic.https.html [ Crash Failure ]
-crbug.com/1050754 external/wpt/webcodecs/video-decoder.html [ Failure ]
-crbug.com/1050754 external/wpt/webcodecs/video-track-reader.html [ Failure ]
 crbug.com/1050754 external/wpt/webmessaging/broadcastchannel/basics.html [ Failure Pass ]
 crbug.com/1050754 external/wpt/webmessaging/broadcastchannel/sandbox.html [ Failure ]
 crbug.com/1050754 external/wpt/webmessaging/broadcastchannel/workers.html [ Failure Timeout ]
diff --git a/third_party/blink/web_tests/android/WeblayerWPTExpectations b/third_party/blink/web_tests/android/WeblayerWPTExpectations
index 5238978..00ba8cb2a 100644
--- a/third_party/blink/web_tests/android/WeblayerWPTExpectations
+++ b/third_party/blink/web_tests/android/WeblayerWPTExpectations
@@ -70,6 +70,161 @@
 crbug.com/1190392 external/wpt/trusted-types/WorkerGlobalScope-eval.html [ Failure ]
 crbug.com/1190392 external/wpt/trusted-types/WorkerGlobalScope-importScripts.html [ Failure ]
 crbug.com/1190392 external/wpt/trusted-types/worker-constructor.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-none/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-wildcard/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-none/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-classic.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-classic.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-import-data.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-module.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-wildcard/sharedworker-module.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/sandbox/shared-worker-sandbox.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/script-src-strict_dynamic_worker.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/worker-data-set-timeout.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/worker-importscripts.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/worker-set-timeout.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-child.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-fallback.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-list.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-none.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-self.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-worker-src-child-fallback-blocked.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-worker-src-child-fallback.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-worker-src-default-fallback.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-worker-src-script-fallback.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/worker-src/shared-worker-src-self-fallback.sub.html [ Failure ]
+
+# Failing CSP tests on Clank and WebLayer on Android
+crbug.com/1198079 external/wpt/content-security-policy/connect-src/shared-worker-connect-src-allowed.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/connect-src/shared-worker-connect-src-blocked.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/embedded-enforcement/subsumption_algorithm-source_list-wildcards.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-animation-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-animation.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-audio-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-audio.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-layout-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-layout.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-paint-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-self/worklet-paint.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/worklet-animation-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/worklet-audio-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/worklet-layout-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/script-src-wildcard/worklet-paint-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/worker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.http-rp/worker-src-self/worker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-animation-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-animation.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-audio-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-audio.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-layout-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-layout.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-paint-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-self/worklet-paint.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/worklet-animation-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/worklet-audio-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/worklet-layout-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/script-src-wildcard/worklet-paint-import-data.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/worker-import.http.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/gen/top.meta/worker-src-self/worker-import.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/inside-worker/shared-inheritance.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/inside-worker/shared-script.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/inside-worker/shared-worker-report-only.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/navigate-to/spv-only-sent-to-initiator.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/object-src/object-src-url-allowed.html [ Crash Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/object-src/object-src-url-embed-allowed.html [ Crash Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/object-src/object-src-url-redirect-allowed.html [ Crash Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/object-src/object-src-url-redirect-blocked.sub.html [ Crash Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/sandbox/service-worker-sandbox.https.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/hash-always-converted-to-utf-8/iso-8859-1.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/hash-always-converted-to-utf-8/iso-8859-3.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/hash-always-converted-to-utf-8/iso-8859-7.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/script-src/hash-always-converted-to-utf-8/iso-8859-9.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/blockeduri-eval.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/blockeduri-inline.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/idlharness.window.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/inside-shared-worker.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/style-src/inline-style-allowed-while-cloning-objects.sub.html [ Failure ]
+crbug.com/1198079 external/wpt/content-security-policy/style-src/style-blocked.sub.html [ Failure ]
 
 # Reporting IDL failures on Android.
 crbug.com/1198081 external/wpt/reporting/idlharness.any.html [ Failure ]
@@ -124,6 +279,15 @@
 crbug.com/1198085 external/wpt/signed-exchange/sxg-utf8-inner-url.tentative.html [ Timeout ]
 crbug.com/1198085 external/wpt/signed-exchange/sxg-variants-match.tentative.html [ Failure ]
 
+# WebCodecs failures on Android.
+crbug.com/1198089 external/wpt/webcodecs/video-frame.any.html [ Failure ]
+crbug.com/1198089 external/wpt/webcodecs/video-frame.any.worker.html [ Failure ]
+crbug.com/1198089 external/wpt/webcodecs/videoFrame-canvasImageSource.html [ Failure ]
+crbug.com/1198089 external/wpt/webcodecs/videoFrame-createImageBitmap.any.html [ Failure ]
+crbug.com/1198089 external/wpt/webcodecs/videoFrame-createImageBitmap.any.worker.html [ Failure ]
+crbug.com/1198089 external/wpt/webcodecs/videoFrame-texImage.any.html [ Failure ]
+crbug.com/1198089 external/wpt/webcodecs/videoFrame-texImage.any.worker.html [ Failure ]
+
 # Add untriaged failures in this block
 crbug.com/1050754 external/wpt/IndexedDB/file_support.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/IndexedDB/idbfactory_open10.htm [ Failure Pass ]
@@ -406,36 +570,6 @@
 crbug.com/1050754 external/wpt/contacts/contacts-select.https.window.html [ Failure ]
 crbug.com/1050754 external/wpt/content-index/content-index.https.window.html [ Crash Failure ]
 crbug.com/1050754 external/wpt/content-index/idlharness.https.any.sharedworker.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/connect-src/shared-worker-connect-src-allowed.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/connect-src/shared-worker-connect-src-blocked.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/connect-src/worker-connect-src-blocked.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/connect-src/worker-from-guid.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/form-action/form-action-src-redirect-blocked.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/inside-worker/shared-inheritance.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/inside-worker/shared-script.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/plugin-types/plugintypes-mismatched-data.html [ Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/plugin-types/plugintypes-mismatched-url.html [ Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/reporting-api/reporting-api-works-on-frame-src.https.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/script-src-strict_dynamic_hashes.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/script-src-strict_dynamic_worker.https.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/worker-data-set-timeout.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/worker-importscripts.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/script-src/worker-set-timeout.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html [ Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/inside-shared-worker.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/securitypolicyviolation/targeting.html [ Timeout ]
-crbug.com/1050754 external/wpt/content-security-policy/unsafe-eval/eval-blocked-in-about-blank-iframe.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-child.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-fallback.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-list.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-none.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-self.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-worker-src-child-fallback-blocked.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-worker-src-child-fallback.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-worker-src-default-fallback.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-worker-src-script-fallback.sub.html [ Failure ]
-crbug.com/1050754 external/wpt/content-security-policy/worker-src/shared-worker-src-self-fallback.sub.html [ Failure ]
 crbug.com/1050754 external/wpt/cookie-store/cookieStore_subscribe_arguments.tentative.https.any.html [ Failure Pass ]
 crbug.com/1050754 external/wpt/cookie-store/idlharness.tentative.https.any.sharedworker.html [ Failure ]
 crbug.com/1050754 external/wpt/cookie-store/serviceworker_cookieStore_cross_origin.tentative.https.sub.html [ Failure ]
@@ -2374,12 +2508,6 @@
 crbug.com/1050754 external/wpt/webauthn/getcredential-timeout.https.html [ Crash ]
 crbug.com/1050754 external/wpt/webauthn/idlharness.https.window.html [ Failure ]
 crbug.com/1050754 external/wpt/webauthn/webauthn-testdriver-basic.https.html [ Crash ]
-crbug.com/1050754 external/wpt/webcodecs/video-decoder.any.html [ Failure ]
-crbug.com/1050754 external/wpt/webcodecs/video-decoder.any.worker.html [ Failure ]
-crbug.com/1050754 external/wpt/webcodecs/video-encoder.any.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/webcodecs/video-encoder.any.worker.html [ Pass Timeout ]
-crbug.com/1050754 external/wpt/webcodecs/video-frame.any.html [ Failure ]
-crbug.com/1050754 external/wpt/webcodecs/video-frame.any.worker.html [ Failure ]
 crbug.com/1050754 external/wpt/webmessaging/broadcastchannel/sandbox.html [ Failure ]
 crbug.com/1050754 external/wpt/webmessaging/broadcastchannel/workers.html [ Failure ]
 crbug.com/1050754 external/wpt/webmessaging/with-options/broken-origin.html [ Failure ]
diff --git a/third_party/blink/web_tests/css3/filters/effect-reference-zoom-expected.png b/third_party/blink/web_tests/css3/filters/effect-reference-zoom-expected.png
index 7f5591d..5135c71e 100644
--- a/third_party/blink/web_tests/css3/filters/effect-reference-zoom-expected.png
+++ b/third_party/blink/web_tests/css3/filters/effect-reference-zoom-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-029.html b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-029.html
new file mode 100644
index 0000000..6de88c61
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-029.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<title>
+  Nested fixedpos in a multicol with transform container.
+</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#abspos-breaking">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<style>
+  .multicol {
+    column-count: 2;
+    column-fill: auto;
+    column-gap: 0px;
+    height: 100px;
+    width: 100px;
+    margin-left: -100px;
+  }
+  .rel {
+    position: relative;
+  }
+  .abs {
+    position: absolute;
+    width: 50px;
+    height: 200px;
+  }
+  .fixed {
+    position: fixed;
+    width: 50px;
+    height: 200px;
+    top: 0px;
+    background: green;
+  }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="multicol">
+  <div style="height: 200px;"></div>
+  <div style="transform: translateX(0); height: 200px; background: red;">
+    <div style="height: 200px;"></div>
+    <div class="rel">
+      <div style="height: 200px;"></div>
+      <div class="abs">
+        <div class="fixed"></div>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-030.html b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-030.html
new file mode 100644
index 0000000..7737e8e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-030.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<title>
+  Nested fixedpos static position in a multicol with transform container.
+</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#abspos-breaking">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<style>
+  .multicol {
+    column-count: 2;
+    column-fill: auto;
+    column-gap: 0px;
+    height: 100px;
+    width: 100px;
+    margin-left: -200px;
+  }
+  .rel {
+    position: relative;
+  }
+  .abs {
+    position: absolute;
+    width: 50px;
+    height: 200px;
+    background: red;
+  }
+  .fixed {
+    position: fixed;
+    width: 50px;
+    height: 200px;
+    background: green;
+  }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="multicol">
+  <div style="transform: translateX(0);">
+    <div style="height: 200px;"></div>
+    <div class="rel">
+      <div style="height: 200px;"></div>
+      <div class="abs">
+        <div class="fixed"></div>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-031.html b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-031.html
new file mode 100644
index 0000000..aaa581c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-031.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<title>
+  Nested fixedpos static position in a multicol with transform container.
+</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#abspos-breaking">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<style>
+  .multicol {
+    column-count: 2;
+    column-fill: auto;
+    column-gap: 0px;
+    height: 100px;
+    width: 100px;
+    margin-left: -100px;
+  }
+  .rel {
+    position: relative;
+  }
+  .abs {
+    position: absolute;
+    width: 50px;
+    height: 200px;
+    top: 0px;
+    background: red;
+  }
+  .fixed {
+    position: fixed;
+    width: 50px;
+    height: 200px;
+    background: green;
+  }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="multicol">
+  <div style="transform: translateX(0);">
+    <div style=" height: 200px;"></div>
+    <div class="rel">
+      <div style="height: 200px;"></div>
+      <div class="abs">
+        <div class="fixed"></div>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-032.html b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-032.html
new file mode 100644
index 0000000..b68f951
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-032.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<title>
+  Nested fixedpos static position in a multicol with transform container.
+</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#abspos-breaking">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<style>
+  .multicol {
+    column-count: 2;
+    column-fill: auto;
+    column-gap: 0px;
+    height: 100px;
+    width: 100px;
+    margin-left: -300px;
+  }
+  .rel {
+    position: relative;
+  }
+  .abs {
+    position: absolute;
+    width: 50px;
+    height: 200px;
+  }
+  .fixed {
+    position: fixed;
+    width: 50px;
+    height: 200px;
+    background: green;
+  }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="multicol">
+  <div style="transform: translateX(0);">
+    <div style="height: 200px;"></div>
+    <div class="rel">
+      <div style="height: 200px;"></div>
+      <div class="abs">
+        <div style="height: 200px;"></div>
+        <div class="abs" style="top: 200px; background: red;"></div>
+        <div class="fixed"></div>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-033.html b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-033.html
new file mode 100644
index 0000000..e1ecebe9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-033.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>
+  Nested fixedpos in a multicol with an abspos transform container.
+</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#abspos-breaking">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<style>
+  .multicol {
+    column-count: 2;
+    column-fill: auto;
+    column-gap: 0px;
+    height: 100px;
+    width: 100px;
+    margin-left: -100px;
+  }
+  .rel {
+    position: relative;
+  }
+  .abs {
+    position: absolute;
+    width: 50px;
+    height: 200px;
+    background: red;
+    transform: translateX(0);
+  }
+  .fixed {
+    position: fixed;
+    width: 50px;
+    height: 200px;
+    top: 0px;
+    background: green;
+  }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="multicol">
+  <div class="rel">
+    <div style="height: 200px;"></div>
+    <div class="abs">
+      <div class="fixed"></div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-034.html b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-034.html
new file mode 100644
index 0000000..286f6f43
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-034.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<title>
+  Nested fixedpos with fixedpos child in a multicol with transform container.
+</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#abspos-breaking">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<style>
+  .multicol {
+    column-count: 2;
+    column-fill: auto;
+    column-gap: 0px;
+    height: 100px;
+    width: 100px;
+  }
+  .rel {
+    position: relative;
+  }
+  .abs {
+    position: absolute;
+    width: 50px;
+    height: 200px;
+  }
+  .fixed {
+    position: fixed;
+    width: 50px;
+    height: 200px;
+    top: 0px;
+  }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="multicol">
+  <div style="transform: translateX(0);">
+    <div style="height: 200px;"></div>
+    <div class="rel">
+      <div style="height: 200px;"></div>
+      <div class="abs">
+        <div style="height: 200px;"></div>
+        <div class="fixed" style="background: red;">
+          <div class="fixed" style="background: green;"></div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-035.html b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-035.html
new file mode 100644
index 0000000..6a2d527
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-035.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<title>
+  Fixedpos in an abspos in a multicol with transform container.
+</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#abspos-breaking">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<style>
+  .multicol {
+    column-count: 2;
+    column-fill: auto;
+    column-gap: 0px;
+    height: 100px;
+    width: 100px;
+    margin-left: -200px;
+  }
+  .abs {
+    position: absolute;
+    width: 50px;
+    height: 200px;
+    top: 0px;
+    background: red;
+  }
+  .fixed {
+    position: fixed;
+    width: 50px;
+    height: 200px;
+    top: 0px;
+    background: green;
+  }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="multicol">
+  <div style="height: 400px;"></div>
+  <div style="transform: translateX(0);">
+    <div style="height: 200px;"></div>
+    <div class="abs">
+      <div class="fixed"></div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-036.html b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-036.html
new file mode 100644
index 0000000..d64f8b5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-036.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<title>
+  Fixedpos in a nested abspos in a multicol with transform container.
+</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#abspos-breaking">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<style>
+  .multicol {
+    column-count: 2;
+    column-fill: auto;
+    column-gap: 0px;
+    height: 100px;
+    width: 100px;
+    margin-left: -300px;
+  }
+  .abs {
+    position: absolute;
+    width: 50px;
+    height: 200px;
+  }
+  .fixed {
+    position: fixed;
+    width: 50px;
+    height: 200px;
+    background: green;
+  }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="multicol">
+  <div style="height: 400px;"></div>
+  <div style="transform: translateX(0);">
+    <div style="height: 200px;"></div>
+    <div class="abs">
+      <div style="height: 200px;"></div>
+      <div class="abs" style="top: 0px; background: red;">
+        <div class="fixed"></div>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/xmldecl/xmldecl-1.html b/third_party/blink/web_tests/external/wpt/html/syntax/xmldecl/xmldecl-1.html
index 87bf224..30a09184 100644
--- a/third_party/blink/web_tests/external/wpt/html/syntax/xmldecl/xmldecl-1.html
+++ b/third_party/blink/web_tests/external/wpt/html/syntax/xmldecl/xmldecl-1.html
@@ -21,7 +21,7 @@
                     let fc = doc.firstChild;
                     assert_equals(fc.nodeType, Node.COMMENT_NODE, 'Should have comment node');
                     assert_true(fc.nodeValue.startsWith("?xml"), 'Should start with ?xml');
-                } else if (expectation == "UTF-16BE" || expectation == "UTF-16BE") {
+                } else if (expectation == "UTF-16BE" || expectation == "UTF-16LE") {
                     let fc = doc.firstChild;
                     assert_equals(fc.nodeType, Node.COMMENT_NODE, 'Should have comment node');
                     assert_true(fc.nodeValue.startsWith("?x"), 'Should start with ?x');
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/xmldecl/xmldecl-2.html b/third_party/blink/web_tests/external/wpt/html/syntax/xmldecl/xmldecl-2.html
index e071001..bb28632 100644
--- a/third_party/blink/web_tests/external/wpt/html/syntax/xmldecl/xmldecl-2.html
+++ b/third_party/blink/web_tests/external/wpt/html/syntax/xmldecl/xmldecl-2.html
@@ -21,7 +21,7 @@
                     let fc = doc.firstChild;
                     assert_equals(fc.nodeType, Node.COMMENT_NODE, 'Should have comment node');
                     assert_true(fc.nodeValue.startsWith("?xml"), 'Should start with ?xml');
-                } else if (expectation == "UTF-16BE" || expectation == "UTF-16BE") {
+                } else if (expectation == "UTF-16BE" || expectation == "UTF-16LE") {
                     let fc = doc.firstChild;
                     assert_equals(fc.nodeType, Node.COMMENT_NODE, 'Should have comment node');
                     assert_true(fc.nodeValue.startsWith("?x"), 'Should start with ?x');
diff --git a/third_party/blink/web_tests/fast/multicol/fixedpos-in-transform-at-column-boundary-expected.txt b/third_party/blink/web_tests/fast/multicol/fixedpos-in-transform-at-column-boundary-expected.txt
deleted file mode 100644
index 9a73c31..0000000
--- a/third_party/blink/web_tests/fast/multicol/fixedpos-in-transform-at-column-boundary-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-Test that a fixed positioned object inside a transform inside a multicol isn't paginated.
-
-The word "YO" should be seen below, with large letter spacing.
-
-Y
-O
-PASS
diff --git a/third_party/blink/web_tests/fast/multicol/fixedpos-in-transform-at-column-boundary.html b/third_party/blink/web_tests/fast/multicol/fixedpos-in-transform-at-column-boundary.html
deleted file mode 100644
index 175ac371..0000000
--- a/third_party/blink/web_tests/fast/multicol/fixedpos-in-transform-at-column-boundary.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<style>
-    body { margin:0; }
-</style>
-<script src="../../resources/check-layout.js"></script>
-<!-- This test is a bit clunky, so that it actually would fail without the code changes that land
-     together with his test. There's a translation bug for fixed positioneds inside transforms in
-     the LayoutState class (there's even a FIXME). Prior to the code changes, it would accidentally
-     disable pagination inside fixed positioneds in many cases, so without some weirdness in the
-     test, it would also pass accidentally without the fix. -->
-<div style="position:absolute;">
-    <p>Test that a fixed positioned object inside a transform inside a multicol isn't paginated.</p>
-    <p>The word "YO" should be seen below, with large letter spacing.</p>
-</div>
-<div id="multicol" style="-webkit-columns:2; -webkit-column-gap:0; column-fill:auto; width:2em; height:200px; line-height:50px;">
-    <div style="position:relative; transform:translateX(0); height:350px;">
-        <div style="position:fixed;">
-            <div style="height:150px;"></div>
-            <div style="white-space:nowrap;" data-offset-y="150">
-                <span style="vertical-align:top;">Y</span>
-                <span style="line-height:80px;"> </span>
-            </div>
-        </div>
-    </div>
-    O
-</div>
-<script>
-    checkLayout("#multicol");
-</script>
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/css3/filters/effect-reference-zoom-hw-expected.png b/third_party/blink/web_tests/flag-specific/composite-after-paint/css3/filters/effect-reference-zoom-hw-expected.png
index 15bbc5f..844ee6fc 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/css3/filters/effect-reference-zoom-hw-expected.png
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/css3/filters/effect-reference-zoom-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png
index 2efc3e4..32ed34b 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
index 973632e6..c2c56ea6 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
index bb461ba..16ac3e8 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png
index 2efc3e4..32ed34b 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png
index eac4c6e..5c7d1f66 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-expected.png
index 973632e6..c2c56ea6 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
index feadd2995..d6e902b 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-subregion-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-subregion-expected.png
index bb461ba..16ac3e8 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-subregion-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-subregion-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
index c2ad698..ea075c8 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png
deleted file mode 100644
index 32ed34b..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/css3/filters/effect-reference-zoom-hw-expected.png b/third_party/blink/web_tests/platform/mac/css3/filters/effect-reference-zoom-hw-expected.png
index 819fe97..3265fac 100644
--- a/third_party/blink/web_tests/platform/mac/css3/filters/effect-reference-zoom-hw-expected.png
+++ b/third_party/blink/web_tests/platform/mac/css3/filters/effect-reference-zoom-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-expected.png b/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-expected.png
index f351aa5..10d03be 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-hw-expected.png b/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-hw-expected.png
index c2a9dcf..c3390033 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-hw-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/scalefactor200/css3/filters/effect-reference-zoom-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/css3/filters/effect-reference-zoom-hw-expected.png b/third_party/blink/web_tests/platform/win/css3/filters/effect-reference-zoom-hw-expected.png
index 078c2b9..ba67a1b 100644
--- a/third_party/blink/web_tests/platform/win/css3/filters/effect-reference-zoom-hw-expected.png
+++ b/third_party/blink/web_tests/platform/win/css3/filters/effect-reference-zoom-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png
index e5dd6bf..870e9a5 100644
--- a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png
index 919b978..78640da8 100644
--- a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-colorspace-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-expected.png b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-expected.png
index 90b3b70..b698f81 100644
--- a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
index c9fcbcf..cf88a90 100644
--- a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-subregion-expected.png b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-subregion-expected.png
index 19fcc22..392ff7f 100644
--- a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-subregion-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-subregion-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
index 42aef86..77e84a7 100644
--- a/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/scalefactor200/css3/filters/effect-reference-subregion-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png b/third_party/blink/web_tests/platform/win7/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png
deleted file mode 100644
index e5dd6bf..0000000
--- a/third_party/blink/web_tests/platform/win7/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png b/third_party/blink/web_tests/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png
deleted file mode 100644
index 2efc3e4..0000000
--- a/third_party/blink/web_tests/virtual/scalefactor200/css3/filters/effect-reference-colorspace-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/auto-scrollbars-001.html b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/auto-scrollbars-001.html
index 8882fb9..10890f9 100644
--- a/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/auto-scrollbars-001.html
+++ b/third_party/blink/web_tests/wpt_internal/css/css-conditional/container-queries/auto-scrollbars-001.html
@@ -13,7 +13,8 @@
     contain: inline-size layout;
   }
   #inner {
-    height: 101px;
+    height: 100px;
+    border-bottom: 1px solid red;
   }
   @container (max-width: 99px) {
     #inner {
@@ -40,7 +41,7 @@
   }, "Initial layout - expecting a scrollbar without overflowing content instead of overflowing content without a scrollbar");
 
   test(() => {
-    inner.style.height = "102px";
+    inner.style.borderBottomWidth = "2px";
     assert_less_than(scroller.clientWidth, 100, "Expects a vertical scrollbar");
     assert_equals(getComputedStyle(inner).height, "50px",
                   "Layout with a scrollbar means the container query applies");
diff --git a/third_party/highway/OWNERS b/third_party/highway/OWNERS
index 0d07657..3cf67d4 100644
--- a/third_party/highway/OWNERS
+++ b/third_party/highway/OWNERS
@@ -1,4 +1,8 @@
-file://media/OWNERS
-deymo@chromium.org
-firsching@google.com
-lode@google.com
+# Owners:
+noel@chromium.org
+scroggo@google.com
+
+# Reviewers:
+# deymo@chromium.org
+# firsching@google.com
+# lode@google.com
diff --git a/third_party/libjxl/OWNERS b/third_party/libjxl/OWNERS
index 0d07657..3cf67d4 100644
--- a/third_party/libjxl/OWNERS
+++ b/third_party/libjxl/OWNERS
@@ -1,4 +1,8 @@
-file://media/OWNERS
-deymo@chromium.org
-firsching@google.com
-lode@google.com
+# Owners:
+noel@chromium.org
+scroggo@google.com
+
+# Reviewers:
+# deymo@chromium.org
+# firsching@google.com
+# lode@google.com
diff --git a/third_party/libprotobuf-mutator/BUILD.gn b/third_party/libprotobuf-mutator/BUILD.gn
index 0a8da68d..25a7e9d 100644
--- a/third_party/libprotobuf-mutator/BUILD.gn
+++ b/third_party/libprotobuf-mutator/BUILD.gn
@@ -40,18 +40,39 @@
   }
 }
 
+# This protoc plugin, like the compiler, should only be built for the host
+# architecture.
+if (current_toolchain == host_toolchain) {
+  # This plugin will be needed to fuzz most protobuf code in Chromium. That's
+  # because production protobuf code must contain the line:
+  # "option optimize_for = LITE_RUNTIME", which instructs the proto compiler not
+  # to compile the proto using the full protobuf runtime. This allows Chromium
+  # not to depend on the full protobuf library, but prevents
+  # libprotobuf-mutator from fuzzing because the lite runtime lacks needed
+  # features (such as reflection).  The plugin simply compiles a proto library
+  # as normal but ensures that is compiled with the full protobuf runtime.
+  executable("override_lite_runtime_plugin") {
+    sources = [ "protoc_plugin/protoc_plugin.cc" ]
+    deps = [ "//third_party/protobuf:protoc_lib" ]
+    public_configs = [ "//third_party/protobuf:protobuf_config" ]
+  }
+  # To use the plugin in a proto_library you want to fuzz, change the build
+  # target to fuzzable_proto_library (defined in
+  # //third_party/libprotobuf-mutator/fuzzable_proto_library.gni)
+}
+
 # The CQ will try building this target without "use_libfuzzer" if it is defined.
 # That will cause the build to fail, so don't define it when "use_libfuzzer" is
 # is false.
 if (use_libfuzzer) {
-  # Test that fuzzable_proto_library works. This target contains files that are
-  # optimized for LITE_RUNTIME and which import other files that are also
-  # optimized for LITE_RUNTIME.
-  fuzzer_test("lpm_test_fuzzer") {
-    sources = [ "test_fuzzer/test_fuzzer.cc" ]
+  # Test that override_lite_runtime_plugin is working when built. This target
+  # contains files that are optimized for LITE_RUNTIME and which import other
+  # files that are also optimized for LITE_RUNTIME.
+  fuzzer_test("override_lite_runtime_plugin_test_fuzzer") {
+    sources = [ "protoc_plugin/test_fuzzer.cc" ]
     deps = [
       ":libprotobuf-mutator",
-      ":lpm_test_fuzzer_proto",
+      ":override_lite_runtime_plugin_test_fuzzer_proto",
     ]
 
     # Don't actually run this on CF. It's only a test to ensure builds work.
@@ -59,12 +80,12 @@
   }
 }
 
-# Proto library for lpm_test_fuzzer
-fuzzable_proto_library("lpm_test_fuzzer_proto") {
+# Proto library for override_lite_runtime_plugin_test_fuzzer
+fuzzable_proto_library("override_lite_runtime_plugin_test_fuzzer_proto") {
   sources = [
-    "test_fuzzer/imported.proto",
-    "test_fuzzer/imported_publicly.proto",
-    "test_fuzzer/test_fuzzer_input.proto",
+    "protoc_plugin/imported.proto",
+    "protoc_plugin/imported_publicly.proto",
+    "protoc_plugin/test_fuzzer_input.proto",
   ]
 }
 
diff --git a/third_party/libprotobuf-mutator/fuzzable_proto_library.gni b/third_party/libprotobuf-mutator/fuzzable_proto_library.gni
index b9c4453..c13d91b 100644
--- a/third_party/libprotobuf-mutator/fuzzable_proto_library.gni
+++ b/third_party/libprotobuf-mutator/fuzzable_proto_library.gni
@@ -6,7 +6,7 @@
 # non-fuzzer builds (ie: use_libfuzzer=false). However, in fuzzer builds, the
 # proto_library is built with the full protobuf runtime and any "optimize_for =
 # LITE_RUNTIME" options are ignored. This is done because libprotobuf-mutator
-# needs the full protobuf runtime, but proto_libraries shipped in Chrome must
+# needs the full protobuf runtime, but proto_libraries shipped in chrome must
 # use the optimize for LITE_RUNTIME option which is incompatible with the full
 # protobuf runtime. tl;dr: A fuzzable_proto_library is a proto_library that can
 # be fuzzed with libprotobuf-mutator and shipped in Chrome.
@@ -14,7 +14,6 @@
 import("//testing/libfuzzer/fuzzer_test.gni")
 import("//third_party/protobuf/proto_library.gni")
 
-# TODO(https://crbug.com/1197634): Fold this into proto_library.
 template("fuzzable_proto_library") {
   # Only make the proto library fuzzable if we are doing a build that we can
   # use LPM on (i.e. libFuzzer not on Chrome OS).
@@ -22,9 +21,20 @@
     proto_library("proto_library_" + target_name) {
       forward_variables_from(invoker, "*")
       assert(current_toolchain == host_toolchain)
+      if (!defined(proto_deps)) {
+        proto_deps = []
+      }
+      proto_deps +=
+          [ "//third_party/libprotobuf-mutator:override_lite_runtime_plugin" ]
+      generator_plugin_label =
+          "//third_party/libprotobuf-mutator:override_lite_runtime_plugin"
+      generator_plugin_suffix = ".pb"
 
-      # Override LITE_RUNTIME settings in the protobuf files.
-      cc_generator_options = "speed"
+      # The plugin will generate cc, so don't ask for it to be done by protoc.
+      generate_cc = false
+      if (!defined(invoker.generate_python)) {
+        generate_python = false
+      }
       extra_configs = [ "//third_party/protobuf:protobuf_config" ]
     }
 
diff --git a/third_party/libprotobuf-mutator/test_fuzzer/imported.proto b/third_party/libprotobuf-mutator/protoc_plugin/imported.proto
similarity index 92%
rename from third_party/libprotobuf-mutator/test_fuzzer/imported.proto
rename to third_party/libprotobuf-mutator/protoc_plugin/imported.proto
index f347c36..fd9c783 100644
--- a/third_party/libprotobuf-mutator/test_fuzzer/imported.proto
+++ b/third_party/libprotobuf-mutator/protoc_plugin/imported.proto
@@ -7,11 +7,11 @@
 
 syntax = "proto2";
 option optimize_for = LITE_RUNTIME;
-package lpm_test_fuzzer;
+package lpm_protoc_plugin_test_fuzzer;
 
 // Test public imported files are handled properly.
 import public "imported_publicly.proto";
 
 message Imported {
   required ImportedPublicly imported_publicly = 1;
-}
+}
\ No newline at end of file
diff --git a/third_party/libprotobuf-mutator/test_fuzzer/imported_publicly.proto b/third_party/libprotobuf-mutator/protoc_plugin/imported_publicly.proto
similarity index 90%
rename from third_party/libprotobuf-mutator/test_fuzzer/imported_publicly.proto
rename to third_party/libprotobuf-mutator/protoc_plugin/imported_publicly.proto
index 10768495..0af1a2d 100644
--- a/third_party/libprotobuf-mutator/test_fuzzer/imported_publicly.proto
+++ b/third_party/libprotobuf-mutator/protoc_plugin/imported_publicly.proto
@@ -7,7 +7,7 @@
 
 syntax = "proto2";
 option optimize_for = LITE_RUNTIME;
-package lpm_test_fuzzer;
+package lpm_protoc_plugin_test_fuzzer;
 
 message ImportedPublicly {
   required int32 input = 1;
diff --git a/third_party/libprotobuf-mutator/protoc_plugin/protoc_plugin.cc b/third_party/libprotobuf-mutator/protoc_plugin/protoc_plugin.cc
new file mode 100644
index 0000000..92f94f4
--- /dev/null
+++ b/third_party/libprotobuf-mutator/protoc_plugin/protoc_plugin.cc
@@ -0,0 +1,124 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Plugin for the protobuf compiler (protoc) that ensures proto definitions are
+// compiled in a way that they can be used with libprotobuf-mutator. Compiles
+// protobufs to C++ like the normal protoc (using the cpp plugin).
+
+#include <assert.h>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include "third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_generator.h"
+#include "third_party/protobuf/src/google/protobuf/compiler/plugin.h"
+#include "third_party/protobuf/src/google/protobuf/descriptor.h"
+#include "third_party/protobuf/src/google/protobuf/descriptor.pb.h"
+
+using google::protobuf::FileDescriptor;
+using google::protobuf::compiler::GeneratorContext;
+using google::protobuf::compiler::cpp::CppGenerator;
+
+// Class that generates C++ code that can be used by LPM from proto libraries.
+class LpmCppCodeGenerator : public CppGenerator {
+ public:
+  // Overrides the GenerateAll method on CppGenerator. This method essentially
+  // does the same thing except it ensures that files are not optimized for
+  // LITE_RUNTIME.
+  virtual bool GenerateAll(const std::vector<const FileDescriptor*>& files,
+                           const std::string& parameter,
+                           GeneratorContext* generator_context,
+                           std::string* error) const {
+    if (files.size() == 0)
+      return true;
+
+    // Created a DescriptorPool once here so that modified files will use the
+    // modified versions when importing.
+    google::protobuf::DescriptorPool descriptor_pool(files[0]->pool());
+
+    // Keep a list of files we have generated already, so that
+    // GenerateFileAndDependencies won't generate the same file twice.
+    std::unordered_set<const FileDescriptor*> prev_generated;
+
+    // Mostly copied from GenerateAll from
+    // //third_party/protobuf/src/google/protobuf/compiler/code_generator.cc
+    bool succeeded = true;
+    for (size_t idx = 0; idx < files.size(); idx++) {
+      const FileDescriptor* file = files[idx];
+      succeeded =
+          GenerateFileAndDependencies(file, parameter, generator_context, error,
+                                      &descriptor_pool, &prev_generated);
+
+      if (!succeeded && error && error->empty()) {
+        *error =
+            "Code generator returned false but provided no error "
+            "description.";
+      }
+      if (error && !error->empty()) {
+        *error = file->name() + ": " + *error;
+        break;
+      }
+      if (!succeeded)
+        break;
+    }
+    return succeeded;
+  }
+
+  // Ensures that file and its dependancies are optimized for LPM by making them
+  // optimized for speed (as opposed to LITE_RUNTIME which would make file
+  // usable for LPM) then returns the result of a call to Generate on the
+  // modified file and the other arguments to this method. Needs to modify
+  // dependencies before file because protobuf doesn't allow a file to import
+  // another if file is not optimized_for LITE_RUNTIME but the dependency is.
+  // Returns true if file is in prev_generated.
+  virtual bool GenerateFileAndDependencies(
+      const FileDescriptor* file,
+      const std::string& parameter,
+      GeneratorContext* generator_context,
+      std::string* error,
+      google::protobuf::DescriptorPool* descriptor_pool,
+      std::unordered_set<const FileDescriptor*>* prev_generated) const {
+    if (prev_generated->find(file) != prev_generated->end())
+      return true;
+
+    // Make a copy of the file that we can modify.
+    google::protobuf::FileDescriptorProto file_proto;
+    file->CopyTo(&file_proto);
+
+    // Fix all dependencies before fixing this file (A file must be optimized
+    // for the lite runtime if it imports files that are.
+    for (int idx = 0; idx < file->dependency_count(); idx++) {
+      const FileDescriptor* dependent_file = file->dependency(idx);
+      assert(dependent_file);
+      bool result = GenerateFileAndDependencies(
+          dependent_file, parameter, generator_context, error, descriptor_pool,
+          prev_generated);
+      assert(result);
+      if (!result)
+        return result;
+    }
+
+    // Base case:
+    // Now make sure we aren't using the LITE_RUNTIME.
+    file_proto.mutable_options()->set_optimize_for(
+        google::protobuf::FileOptions::SPEED);
+
+    // Convert it back to a FileDescriptor and pass it to the parent Generate
+    // method.
+    const FileDescriptor* modified_file =
+        descriptor_pool->BuildFile(file_proto);
+    assert(modified_file);
+
+    // Ensure we only generate code once for file.
+    prev_generated->insert(file);
+    return CppGenerator::Generate(modified_file, parameter, generator_context,
+                                  error);
+  }
+};
+
+int main(int argc, char** argv) {
+  // Invoke our lightly modified C++ code generator on the inputs.
+  LpmCppCodeGenerator generator;
+  return PluginMain(argc, argv, &generator);
+}
diff --git a/third_party/libprotobuf-mutator/protoc_plugin/test_fuzzer.cc b/third_party/libprotobuf-mutator/protoc_plugin/test_fuzzer.cc
new file mode 100644
index 0000000..43083982
--- /dev/null
+++ b/third_party/libprotobuf-mutator/protoc_plugin/test_fuzzer.cc
@@ -0,0 +1,18 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Test fuzzer that when built successfully proves that lpm_protoc_plugin is
+// working. Building this fuzzer without using lpm_protoc_plugin will fail
+// because of test_fuzzer_input.proto
+
+#include <iostream>
+
+#include "third_party/libprotobuf-mutator/src/src/libfuzzer/libfuzzer_macro.h"
+
+#include "third_party/libprotobuf-mutator/protoc_plugin/test_fuzzer_input.pb.h"
+
+DEFINE_PROTO_FUZZER(
+    const lpm_protoc_plugin_test_fuzzer::TestFuzzerInput& input) {
+  std::cout << input.imported().imported_publicly().input() << std::endl;
+}
diff --git a/third_party/libprotobuf-mutator/protoc_plugin/test_fuzzer_input.proto b/third_party/libprotobuf-mutator/protoc_plugin/test_fuzzer_input.proto
new file mode 100644
index 0000000..cdc965f
--- /dev/null
+++ b/third_party/libprotobuf-mutator/protoc_plugin/test_fuzzer_input.proto
@@ -0,0 +1,23 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Depended on by override_lite_runtime_plugin_test_fuzzer. Tests whether
+// override_lite_runtime_plugin is working since without it
+// builds will fail because of the optimize_for LITE_RUNTIME option this
+// file has set. Also imports a file that does the same thing which complicates
+// things for the plugin.
+
+syntax = "proto2";
+
+// This line is essentially the purpose of this test fuzzer. The plugin, if
+// working, ignores this line. If it is not working or isn't used, then this
+// build will fail.
+option optimize_for = LITE_RUNTIME;
+
+package lpm_protoc_plugin_test_fuzzer;
+import "imported.proto";
+
+message TestFuzzerInput {
+  required Imported imported = 1;
+}
diff --git a/third_party/libprotobuf-mutator/test_fuzzer/test_fuzzer.cc b/third_party/libprotobuf-mutator/test_fuzzer/test_fuzzer.cc
deleted file mode 100644
index a40167a..0000000
--- a/third_party/libprotobuf-mutator/test_fuzzer/test_fuzzer.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Test fuzzer that when built successfully proves that fuzzable_proto_library
-// is working. Building this fuzzer without using fuzzable_proto_library will
-// fail because of test_fuzzer_input.proto
-
-#include <iostream>
-
-#include "third_party/libprotobuf-mutator/src/src/libfuzzer/libfuzzer_macro.h"
-
-#include "third_party/libprotobuf-mutator/test_fuzzer/test_fuzzer_input.pb.h"
-
-DEFINE_PROTO_FUZZER(const lpm_test_fuzzer::TestFuzzerInput& input) {
-  std::cout << input.imported().imported_publicly().input() << std::endl;
-}
diff --git a/third_party/libprotobuf-mutator/test_fuzzer/test_fuzzer_input.proto b/third_party/libprotobuf-mutator/test_fuzzer/test_fuzzer_input.proto
deleted file mode 100644
index 7167340..0000000
--- a/third_party/libprotobuf-mutator/test_fuzzer/test_fuzzer_input.proto
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Depended on by lpm_test_fuzzer. Tests whether fuzzable_proto_library is
-// working since without it builds will fail because of the optimize_for
-// LITE_RUNTIME option this file has set. Also imports a file that does the same
-// thing.
-
-syntax = "proto2";
-
-// This line is essentially the purpose of this test fuzzer. The build rule, if
-// working, ignores this line. If it is not working or isn't used, then this
-// build will fail.
-option optimize_for = LITE_RUNTIME;
-
-package lpm_test_fuzzer;
-import "imported.proto";
-
-message TestFuzzerInput {
-  required Imported imported = 1;
-}
diff --git a/third_party/tint/LICENSE b/third_party/tint/LICENSE
deleted file mode 100644
index d645695..0000000
--- a/third_party/tint/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/third_party/tint/OWNERS b/third_party/tint/OWNERS
deleted file mode 100644
index 9e4daee..0000000
--- a/third_party/tint/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-cwallez@chromium.org
-dsinclair@chromium.org
-kainino@chromium.org
diff --git a/third_party/tint/README.chromium b/third_party/tint/README.chromium
deleted file mode 100644
index 9be773e..0000000
--- a/third_party/tint/README.chromium
+++ /dev/null
@@ -1,13 +0,0 @@
-Name: Tint
-Short Name: tint
-URL: https://dawn.googlesource.com/tint
-Version: 0
-Revision: 464928ed913b18f1af068780468de38b50986aac
-License: Apache 2.0
-License File: LICENSE
-Security Critical: yes
-
-Description:
-Tint is an implementation of WGSL, the WebGPU shading language. It is used by
-Dawn, an implementation for WebGPU, in Chromium. Specifically it provides
-facilities for conversion to/from WGSL from other shading languages like SPIR-V.
diff --git a/tools/fuchsia/local-sdk.py b/tools/fuchsia/local-sdk.py
index 3220b94..2162657 100755
--- a/tools/fuchsia/local-sdk.py
+++ b/tools/fuchsia/local-sdk.py
@@ -15,10 +15,9 @@
 import tarfile
 import tempfile
 
-
 SELF_FILE = os.path.normpath(os.path.abspath(__file__))
-REPOSITORY_ROOT = os.path.abspath(os.path.join(
-    os.path.dirname(__file__), '..', '..'))
+REPOSITORY_ROOT = os.path.abspath(
+    os.path.join(os.path.dirname(__file__), '..', '..'))
 
 
 def Run(*args):
@@ -35,19 +34,16 @@
 
 
 def BuildForArch(arch):
-  build_dir = 'out/release-' + arch
   Run(
       'scripts/fx',
       '--dir',
-      build_dir,
+      'out/release-{}'.format(arch),
       'set',
-      'terminal.qemu-' + arch,
-      '--args=cache_package_labels+=["//sdk/bundles:tools"]',
+      'terminal.qemu-{}'.format(arch),
       '--args=is_debug=false',
       '--args=build_sdk_archives=true',
       # Increase the size of the image to allow multiple test runs.
-      # 512 MiB (512 * 1024 * 1024).
-      '--args=fvm_image_size=536870912')
+      '--args=fvm_image_size={}'.format(512 * 1024 * 1024))
   Run('scripts/fx', 'build', 'sdk', 'build/images')
 
 
@@ -83,7 +79,7 @@
   # file. This means that on next gclient runhooks, we'll restore to the
   # real DEPS-determined SDK.
   sdk_output_dir = os.path.join(REPOSITORY_ROOT, 'third_party', 'fuchsia-sdk',
-                            'sdk')
+                                'sdk')
   images_output_dir = os.path.join(REPOSITORY_ROOT, 'third_party',
                                    'fuchsia-sdk', 'images')
   EnsureEmptyDir(sdk_output_dir)
@@ -144,9 +140,9 @@
       if not entry.get('archive'):
         continue
 
-      shutil.copyfile(os.path.join(arch_output_dir, entry['path']),
-                      os.path.join(arch_image_dir, entry['name']) + '.' +
-                          entry['type'])
+      shutil.copyfile(
+          os.path.join(arch_output_dir, entry['path']),
+          os.path.join(arch_image_dir, entry['name']) + '.' + entry['type'])
 
   # Write merged manifest file.
   with open(manifest_path, 'w') as manifest_file:
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 5390248..b7eeaa7 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -67994,6 +67994,7 @@
   <int value="6" label="Unauthorized"/>
   <int value="7" label="File encrypted"/>
   <int value="8" label="Unsupported file type"/>
+  <int value="9" label="Too many requests"/>
 </enum>
 
 <enum name="SafeBrowsingDelayedWarningEvent">
@@ -71025,6 +71026,40 @@
   <int value="7"/>
 </enum>
 
+<enum name="SharingLongScreenshotsBitmapGenerationStatus">
+<!--
+  SharingLongScreenshotsBitmapGenerationStatus must be kept in sync with BitmapGenerationStatus defined
+  in /chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMetrics.java
+-->
+
+  <int value="0" label="Unknown"/>
+  <int value="1" label="OK"/>
+  <int value="2" label="Directory Creation Failed"/>
+  <int value="3" label="Capture Failed"/>
+  <int value="4" label="Proto Serialization Failed"/>
+  <int value="5" label="Web Contents Gone"/>
+  <int value="6" label="Native Service Uninitialized"/>
+  <int value="7" label="Low Memory Detected"/>
+  <int value="8" label="Proto Deserialization Failed"/>
+  <int value="9" label="Native Not Initialized"/>
+</enum>
+
+<enum name="SharingLongScreenshotsEvent">
+<!--
+  SharingLongScreenshotsEvent must be kept in sync with SharingLongScreenshotsEvent defined
+  in /chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/LongScreenshotsMetrics.java
+-->
+
+  <int value="0" label="Dialog Open"/>
+  <int value="1" label="Dialog Cancel"/>
+  <int value="2" label="Dialog Confirm"/>
+  <int value="3" label="Capture: Generation Error"/>
+  <int value="4" label="Capture: Memory Pressure"/>
+  <int value="5" label="Compositor: Complete"/>
+  <int value="6" label="Compositor: Memory Pressure"/>
+  <int value="7" label="Compositor: Generation Error"/>
+</enum>
+
 <enum name="SharingMajorVersionComparison">
   <int value="0" label="Unknown"/>
   <int value="1" label="Sender version is lower"/>
@@ -71080,7 +71115,7 @@
 
 <enum name="SharingScreenshotFallbackAction">
 <!--
-  SharingScreenshotAction must be kept in sync with SharingScreenshotAction defined
+  SharingScreenshotFallbackAction must be kept in sync with SharingScreenshotAction defined
   in /chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMetrics.java
 -->
 
diff --git a/tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml b/tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml
index e051b2c..278c036 100644
--- a/tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml
@@ -263,6 +263,9 @@
 
 <histogram name="Bluetooth.Web.Android" enum="AndroidGATTStatusResult"
     expires_after="2021-01-31">
+  <obsolete>
+    Removed 2021/04/12. crbug.com/1052934
+  </obsolete>
 <!-- Name completed by histogram_suffixes name="AndroidGATTEvents" -->
 
   <owner>ortuno@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/download/histograms.xml b/tools/metrics/histograms/histograms_xml/download/histograms.xml
index e107323..d8a6ede 100644
--- a/tools/metrics/histograms/histograms_xml/download/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/download/histograms.xml
@@ -580,7 +580,8 @@
 </histogram>
 
 <histogram name="Download.ParallelDownloadRequestCount" units="requests"
-    expires_after="2020-10-18">
+    expires_after="2022-04-01">
+  <owner>qinmin@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
   <summary>
     The total number of requests sent for a parallel download, including the
@@ -867,7 +868,7 @@
 </histogram>
 
 <histogram name="Download.Service.OnUploadDataReceived.PauseReason"
-    enum="Download.Service.PauseReason" expires_after="2020-03-01">
+    enum="Download.Service.PauseReason" expires_after="never">
 <!-- expires-never: Used for detecting anomalies in background download service. -->
 
   <owner>shaktisahu@chromium.org</owner>
@@ -879,7 +880,7 @@
 </histogram>
 
 <histogram name="Download.Service.PauseReason"
-    enum="Download.Service.PauseReason" expires_after="M82">
+    enum="Download.Service.PauseReason" expires_after="never">
 <!-- expires-never: Used for detecting anomalies in background download service. -->
 
   <owner>shaktisahu@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
index a1e16c7..accbff2 100644
--- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -849,6 +849,9 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="AndroidGATTEvents" separator=".">
+  <obsolete>
+    Removed 2021/04/12. crbug.com/1052934
+  </obsolete>
   <suffix name="onCharacteristicRead.Status" label=""/>
   <suffix name="onCharacteristicWrite.Status" label=""/>
   <suffix name="onConnectionStateChange.Status.Connected"
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml
index 9df7a5c..2e2314f 100644
--- a/tools/metrics/histograms/histograms_xml/others/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -14897,7 +14897,7 @@
 </histogram>
 
 <histogram name="Skia.VulkanMemoryAllocator.PercentUsed" units="%"
-    expires_after="2021-04-29">
+    expires_after="2021-09-05">
   <owner>egdaniel@google.com</owner>
   <owner>bsalomon@google.com</owner>
   <summary>
@@ -18892,7 +18892,8 @@
 
 <histogram name="WheelScrolling.WasLatched" enum="BooleanLatched"
     expires_after="M77">
-  <owner>sahel@chromium.org</owner>
+  <owner>flackr@chromium.org</owner>
+  <owner>input-dev@chromium.org</owner>
   <summary>
     Records whether or not a GSU event with wheel source is latched to the
     current scrolling element. It is false for the first GSU event of every
diff --git a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
index f08c5f6..6041d2c 100644
--- a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
@@ -310,6 +310,17 @@
   </summary>
 </histogram>
 
+<histogram name="SafeBrowsing.DeepScan.Download.TooManyRequests.Duration"
+    units="ms" expires_after="2022-02-01">
+  <owner>domfc@chromium.org</owner>
+  <owner>webprotect-team@google.com</owner>
+  <summary>
+    This records the deep scanning duration of a user download request with a
+    TooManyRequests result. It is logged once for each binary upload with that
+    result.
+  </summary>
+</histogram>
+
 <histogram name="SafeBrowsing.DeepScan.Download.Unknown.Duration" units="ms"
     expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
@@ -431,6 +442,17 @@
   </summary>
 </histogram>
 
+<histogram name="SafeBrowsing.DeepScan.DragAndDrop.TooManyRequests.Duration"
+    units="ms" expires_after="2022-02-01">
+  <owner>domfc@chromium.org</owner>
+  <owner>webprotect-team@google.com</owner>
+  <summary>
+    This records the deep scanning duration of a user &quot;drag and drop&quot;
+    request with a TooManyRequests result. It is logged once for each binary
+    upload with that result.
+  </summary>
+</histogram>
+
 <histogram name="SafeBrowsing.DeepScan.DragAndDrop.Unknown.Duration" units="ms"
     expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
@@ -539,6 +561,17 @@
   </summary>
 </histogram>
 
+<histogram name="SafeBrowsing.DeepScan.Paste.TooManyRequests.Duration"
+    units="ms" expires_after="2022-02-01">
+  <owner>domfc@chromium.org</owner>
+  <owner>webprotect-team@google.com</owner>
+  <summary>
+    This records the deep scanning duration of a user paste request with a
+    TooManyRequests result. It is logged once for each binary upload with that
+    result.
+  </summary>
+</histogram>
+
 <histogram name="SafeBrowsing.DeepScan.Paste.Unknown.Duration" units="ms"
     expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
@@ -656,6 +689,17 @@
   </summary>
 </histogram>
 
+<histogram name="SafeBrowsing.DeepScan.Upload.TooManyRequests.Duration"
+    units="ms" expires_after="2022-02-01">
+  <owner>domfc@chromium.org</owner>
+  <owner>webprotect-team@google.com</owner>
+  <summary>
+    This records the deep scanning duration of a user upload request with a
+    TooManyRequests result. It is logged once for each binary upload with that
+    result.
+  </summary>
+</histogram>
+
 <histogram name="SafeBrowsing.DeepScan.Upload.Unknown.Duration" units="ms"
     expires_after="2022-02-01">
   <owner>domfc@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/search/histograms.xml b/tools/metrics/histograms/histograms_xml/search/histograms.xml
index 83a7695..b96ccafa 100644
--- a/tools/metrics/histograms/histograms_xml/search/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/search/histograms.xml
@@ -1313,7 +1313,7 @@
 </histogram>
 
 <histogram name="Search.QueryTiles.ImagePreloadingEvent"
-    enum="QueryTilesImageLoadingEvent" expires_after="M91">
+    enum="QueryTilesImageLoadingEvent" expires_after="2022-04-01">
   <owner>xingliu@chromium.org</owner>
   <owner>chrome-upboarding-eng@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/sharing/histograms.xml b/tools/metrics/histograms/histograms_xml/sharing/histograms.xml
index b32ec24..0491b0a 100644
--- a/tools/metrics/histograms/histograms_xml/sharing/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/sharing/histograms.xml
@@ -178,6 +178,30 @@
   </summary>
 </histogram>
 
+<histogram name="Sharing.LongScreenshots.BitmapGenerationStatus"
+    enum="SharingLongScreenshotsEvent" expires_after="M98">
+  <owner>ramyan@chromium.org</owner>
+  <owner>skare@chromium.org</owner>
+  <owner>src/components/send_tab_to_self/OWNERS</owner>
+  <summary>
+    Counts of Bitmap Generator statuses when capturing long screenshots.
+    Recorded when a new bitmap is requested from the paint_preview engine, for
+    example when scrolling down the page for the first time.
+  </summary>
+</histogram>
+
+<histogram name="Sharing.LongScreenshots.Event"
+    enum="SharingLongScreenshotsEvent" expires_after="M98">
+  <owner>ramyan@chromium.org</owner>
+  <owner>skare@chromium.org</owner>
+  <owner>src/components/send_tab_to_self/OWNERS</owner>
+  <summary>
+    Counts of events in the long screenshot capture process. Events are recorded
+    for events such as opening/confirming the dialog, or on corner cases such as
+    memory pressure while the dialog is open.
+  </summary>
+</histogram>
+
 <histogram name="Sharing.MajorVersionComparison"
     enum="SharingMajorVersionComparison" expires_after="M87">
   <obsolete>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 7418c5a..b38351b2 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -7402,6 +7402,19 @@
   </metric>
 </event>
 
+<event name="IOS.PageAddedToReadingList">
+  <owner>thegreenfrog@chromium.org</owner>
+  <summary>
+    Logged when the user adds a page to the Reading List.
+  </summary>
+  <metric name="AddedFromMessages" enum="Boolean">
+    <summary>
+      True if the page was added by the user tapping on the Messages prompt to
+      save to Reading List.
+    </summary>
+  </metric>
+</event>
+
 <event name="IOS.PageZoomChanged">
   <owner>rkgibson@google.com</owner>
   <summary>
@@ -12200,7 +12213,7 @@
 </event>
 
 <event name="PaymentApp.CheckoutEvents">
-  <owner>sahel@chromium.org</owner>
+  <owner>rouslan@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
     Records checkout events as well as completion status for the invoked payment
@@ -12233,7 +12246,7 @@
 </event>
 
 <event name="PaymentRequest.CheckoutEvents">
-  <owner>sahel@chromium.org</owner>
+  <owner>rouslan@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <metric name="CompletionStatus">
     <summary>
@@ -12258,7 +12271,7 @@
 </event>
 
 <event name="PaymentRequest.TransactionAmount">
-  <owner>sahel@chromium.org</owner>
+  <owner>rouslan@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <metric name="Category">
     <summary>
diff --git a/tools/perf/contrib/system_health_scroll_jank/system_health_scroll_jank.py b/tools/perf/contrib/system_health_scroll_jank/system_health_scroll_jank.py
index 5ebc2a07..c93309c4 100644
--- a/tools/perf/contrib/system_health_scroll_jank/system_health_scroll_jank.py
+++ b/tools/perf/contrib/system_health_scroll_jank/system_health_scroll_jank.py
@@ -18,6 +18,8 @@
     'Event.Latency.ScrollUpdate.Wheel.TimeToScrollUpdateSwapBegin4',
     'Graphics.Smoothness.Checkerboarding.TouchScroll',
     'Graphics.Smoothness.Checkerboarding.WheelScroll',
+    'Graphics.Smoothness.Jank.Compositor.TouchScroll',
+    'Graphics.Smoothness.Jank.Main.TouchScroll',
     'Graphics.Smoothness.PercentDroppedFrames.AllAnimations',
     'Graphics.Smoothness.PercentDroppedFrames.AllInteractions',
     'Graphics.Smoothness.PercentDroppedFrames.AllSequences',
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 257ba43..aa4c8363 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -2,15 +2,15 @@
     "trace_processor_shell": {
         "win": {
             "hash": "fe4d07829c74610e4ea8455a540d602ebdd8e2b1",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/9f85729fdbafefa1e1caec3775c648a5f6a25c7d/trace_processor_shell.exe"
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/e2af31e5ad285a2d89143f65cfc8f41a56dba5e0/trace_processor_shell.exe"
         },
         "mac": {
             "hash": "4969720d5c4c63ab4f99abd3da2e3d8a862f30d2",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/9f85729fdbafefa1e1caec3775c648a5f6a25c7d/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/507ccb8542d8915bcc88f0bec545ac9e8a464af6/trace_processor_shell"
         },
         "linux": {
-            "hash": "d004343850b8fc3f362faac432d395a05613b477",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/9f85729fdbafefa1e1caec3775c648a5f6a25c7d/trace_processor_shell"
+            "hash": "d4236cf2970714db8496eb09e5f0405ac34ca977",
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/7dceb880165b7ba5b85f3f8d095e5262407b5fad/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc
index 5b13480..e4061e54 100644
--- a/ui/accessibility/accessibility_features.cc
+++ b/ui/accessibility/accessibility_features.cc
@@ -94,13 +94,6 @@
 #endif  // defined(OS_WIN)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-const base::Feature kMagnifierNewFocusFollowing{
-    "MagnifierNewFocusFollowing", base::FEATURE_ENABLED_BY_DEFAULT};
-
-bool IsMagnifierNewFocusFollowingEnabled() {
-  return base::FeatureList::IsEnabled(::features::kMagnifierNewFocusFollowing);
-}
-
 const base::Feature kMagnifierPanningImprovements{
     "MagnifierPanningImprovements", base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/ui/accessibility/accessibility_features.h b/ui/accessibility/accessibility_features.h
index 848656cc..cbc368b6 100644
--- a/ui/accessibility/accessibility_features.h
+++ b/ui/accessibility/accessibility_features.h
@@ -78,13 +78,6 @@
 #endif  // defined(OS_WIN)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-// Enables new magnifier focus following feature, which provides a richer
-// focus following experience.
-AX_BASE_EXPORT extern const base::Feature kMagnifierNewFocusFollowing;
-
-// Returns true if the new magnifier focus following feature is enabled.
-AX_BASE_EXPORT bool IsMagnifierNewFocusFollowingEnabled();
-
 // Enables new magnifier panning improvements feature, which adds
 // additional keyboard and mouse panning functionality in Magnifier.
 AX_BASE_EXPORT extern const base::Feature kMagnifierPanningImprovements;
diff --git a/ui/android/java/src/org/chromium/ui/gfx/AdpfRenderingStageScheduler.java b/ui/android/java/src/org/chromium/ui/gfx/AdpfRenderingStageScheduler.java
index 592d891..d3e37b1 100644
--- a/ui/android/java/src/org/chromium/ui/gfx/AdpfRenderingStageScheduler.java
+++ b/ui/android/java/src/org/chromium/ui/gfx/AdpfRenderingStageScheduler.java
@@ -19,7 +19,7 @@
 @JNINamespace("gfx")
 class AdpfRenderingStageScheduler {
     private static final String TAG = "Adpf";
-    private static final String HINT_SERVICE = "hint";
+    private static final String HINT_SERVICE = "performance_hint";
 
     // TODO(crbug.com/1157620): Remove reflection once SDK is public.
     private static final boolean sEnabled;
@@ -32,10 +32,10 @@
         boolean enabled = false;
         if (BuildInfo.isAtLeastS()) {
             try {
-                Class hintManagerClazz = Class.forName("android.os.HintManager");
+                Class hintManagerClazz = Class.forName("android.os.PerformanceHintManager");
                 sHintManagerCreateHintSession =
-                        hintManagerClazz.getMethod("createHintSession", int[].class);
-                Class hintSessionClazz = Class.forName("android.os.HintManager$Session");
+                        hintManagerClazz.getMethod("createHintSession", int[].class, long.class);
+                Class hintSessionClazz = Class.forName("android.os.PerformanceHintManager$Session");
                 sHintSessionUpdateTargetWorkDuration =
                         hintSessionClazz.getMethod("updateTargetWorkDuration", long.class);
                 sHintSessionReportActualWorkDuration =
@@ -43,7 +43,7 @@
                 sHintSessionClose = hintSessionClazz.getMethod("close");
                 enabled = true;
             } catch (ReflectiveOperationException e) {
-                Log.d(TAG, "HintManager reflection exception", e);
+                Log.d(TAG, "PerformanceHintManager reflection exception", e);
             }
         }
         sEnabled = enabled;
@@ -62,18 +62,17 @@
             Log.d(TAG, "Null hint manager");
             return null;
         }
-        Object hintSession = sHintManagerCreateHintSession.invoke(hintManager, threadIds);
+        Object hintSession =
+                sHintManagerCreateHintSession.invoke(hintManager, threadIds, targetDurationNanos);
         if (hintSession == null) {
             Log.d(TAG, "Null hint session");
             return null;
         }
-        return new AdpfRenderingStageScheduler(hintSession, targetDurationNanos);
+        return new AdpfRenderingStageScheduler(hintSession);
     }
 
-    private AdpfRenderingStageScheduler(Object hintSession, long targetDurationNanos)
-            throws ReflectiveOperationException {
+    private AdpfRenderingStageScheduler(Object hintSession) throws ReflectiveOperationException {
         mHintSession = hintSession;
-        sHintSessionUpdateTargetWorkDuration.invoke(mHintSession, targetDurationNanos);
     }
 
     @CalledByNative
diff --git a/ui/compositor/test/in_process_context_factory.cc b/ui/compositor/test/in_process_context_factory.cc
index 4eceaee..d4e5b2a 100644
--- a/ui/compositor/test/in_process_context_factory.cc
+++ b/ui/compositor/test/in_process_context_factory.cc
@@ -145,7 +145,7 @@
 
 }  // namespace
 
-// TODO(sgilhuly): This class is managed heavily by InProcessTransportFactory.
+// TODO(rivr): This class is managed heavily by InProcessTransportFactory.
 // Move some of the logic in here and simplify the interface.
 class InProcessContextFactory::PerCompositorData
     : public viz::mojom::DisplayPrivate {
diff --git a/ui/gtk/gdk.sigs b/ui/gtk/gdk.sigs
index f2099c6..01b0b25 100644
--- a/ui/gtk/gdk.sigs
+++ b/ui/gtk/gdk.sigs
@@ -17,3 +17,4 @@
 int gdk_paintable_get_intrinsic_width(GdkPaintable* paintable);
 int gdk_paintable_get_intrinsic_height(GdkPaintable* paintable);
 GdkScreen* gdk_screen_get_default(void);
+void gdk_color_free(GdkColor* color);
diff --git a/ui/gtk/gtk.sigs b/ui/gtk/gtk.sigs
index 39dd8f1..d9b6bec9 100644
--- a/ui/gtk/gtk.sigs
+++ b/ui/gtk/gtk.sigs
@@ -52,3 +52,8 @@
 void gtk_style_context_add_provider_for_display(GdkDisplay* display, GtkStyleProvider* provider, guint priority);
 void gtk_style_context_remove_provider_for_screen(GdkScreen* screen, GtkStyleProvider* provider);
 void gtk_style_context_remove_provider_for_display(GdkDisplay* display, GtkStyleProvider* provider);
+void gtk_window_destroy(GtkWindow* window);
+GtkIconTheme* gtk_icon_theme_get_for_display(GdkDisplay* display);
+GtkIconTheme* gtk_icon_theme_get_default(void);
+gboolean gtk_widget_path_iter_has_class(const GtkWidgetPath* path, gint pos, const gchar* name);
+void gtk_style_context_get_background_color(GtkStyleContext* context, GtkStateFlags state, GdkRGBA* color);
diff --git a/ui/gtk/gtk_compat.cc b/ui/gtk/gtk_compat.cc
index 0610d8aa..7434830 100644
--- a/ui/gtk/gtk_compat.cc
+++ b/ui/gtk/gtk_compat.cc
@@ -172,6 +172,19 @@
 }
 
 DISABLE_CFI_ICALL
+GdkRGBA GtkStyleContextGetColor(GtkStyleContext* context) {
+  static void* get_color = DlSym(GetLibGtk(), "gtk_style_context_get_color");
+  GdkRGBA color;
+  if (GtkCheckVersion(4)) {
+    DlCast<void(GtkStyleContext*, GdkRGBA*)>(get_color)(context, &color);
+  } else {
+    DlCast<void(GtkStyleContext*, GtkStateFlags, GdkRGBA*)>(get_color)(
+        context, gtk_style_context_get_state(context), &color);
+  }
+  return color;
+}
+
+DISABLE_CFI_ICALL
 bool GtkImContextFilterKeypress(GtkIMContext* context, GdkEventKey* event) {
   static void* filter = DlSym(GetLibGtk(), "gtk_im_context_filter_keypress");
   if (GtkCheckVersion(4)) {
@@ -213,6 +226,28 @@
   }
 }
 
+DISABLE_CFI_ICALL
+GtkWidget* GtkToplevelWindowNew() {
+  static void* window_new = DlSym(GetLibGtk(), "gtk_window_new");
+  if (GtkCheckVersion(4))
+    return DlCast<GtkWidget*()>(window_new)();
+  return DlCast<GtkWidget*(GtkWindowType)>(window_new)(GTK_WINDOW_TOPLEVEL);
+}
+
+DISABLE_CFI_ICALL
+void GtkCssProviderLoadFromData(GtkCssProvider* css_provider,
+                                const char* data,
+                                gssize length) {
+  static void* load = DlSym(GetLibGtk(), "gtk_css_provider_load_from_data");
+  if (GtkCheckVersion(4)) {
+    DlCast<void(GtkCssProvider*, const char*, gssize)>(load)(css_provider, data,
+                                                             length);
+  } else {
+    DlCast<gboolean(GtkCssProvider*, const char*, gssize, GError**)>(load)(
+        css_provider, data, length, nullptr);
+  }
+}
+
 ScopedGObject<GListModel> Gtk4FileChooserGetFiles(GtkFileChooser* dialog) {
   DCHECK(GtkCheckVersion(4));
   static void* get = DlSym(GetLibGtk(), "gtk_file_chooser_get_files");
diff --git a/ui/gtk/gtk_compat.h b/ui/gtk/gtk_compat.h
index 5d87d1b..ed6fb86 100644
--- a/ui/gtk/gtk_compat.h
+++ b/ui/gtk/gtk_compat.h
@@ -51,6 +51,8 @@
 
 gfx::Insets GtkStyleContextGetMargin(GtkStyleContext* context);
 
+GdkRGBA GtkStyleContextGetColor(GtkStyleContext* context);
+
 bool GtkImContextFilterKeypress(GtkIMContext* context, GdkEventKey* event);
 
 bool GtkFileChooserSetCurrentFolder(GtkFileChooser* dialog,
@@ -63,6 +65,12 @@
                    double x,
                    double y);
 
+GtkWidget* GtkToplevelWindowNew();
+
+void GtkCssProviderLoadFromData(GtkCssProvider* css_provider,
+                                const char* data,
+                                gssize length);
+
 ScopedGObject<GListModel> Gtk4FileChooserGetFiles(GtkFileChooser* dialog);
 
 ScopedGObject<GtkIconInfo> Gtk3IconThemeLookupByGicon(GtkIconTheme* theme,
diff --git a/ui/gtk/gtk_types.h b/ui/gtk/gtk_types.h
index a891983..b26717f 100644
--- a/ui/gtk/gtk_types.h
+++ b/ui/gtk/gtk_types.h
@@ -56,6 +56,7 @@
 constexpr GdkMemoryFormat GDK_MEMORY_B8G8R8A8 = static_cast<GdkMemoryFormat>(3);
 #else
 enum GtkWidgetHelpType : int;
+enum GtkWindowType : int;
 
 using GtkWidgetPath = struct _GtkWidgetPath;
 using GtkContainer = struct _GtkContainer;
@@ -64,6 +65,7 @@
 using GdkKeymap = struct _GdkKeymap;
 using GtkIconInfo = struct _GtkIconInfo;
 using GdkScreen = struct _GdkScreen;
+using GdkColor = struct _GdkColor;
 
 struct _GdkEventKey {
   GdkEventType type;
@@ -79,11 +81,20 @@
   guint is_modifier : 1;
 };
 
+struct _GdkColor {
+  guint32 pixel;
+  guint16 red;
+  guint16 green;
+  guint16 blue;
+};
+
 constexpr int GTK_ICON_LOOKUP_USE_BUILTIN = 1 << 2;
 constexpr int GTK_ICON_LOOKUP_GENERIC_FALLBACK = 1 << 3;
 constexpr int GTK_ICON_LOOKUP_FORCE_SIZE = 1 << 4;
 
 constexpr const char GTK_STYLE_PROPERTY_BACKGROUND_IMAGE[] = "background-image";
+
+constexpr auto GTK_WINDOW_TOPLEVEL = static_cast<GtkWindowType>(0);
 #endif
 }
 
diff --git a/ui/gtk/gtk_util.cc b/ui/gtk/gtk_util.cc
index 4f72827..23c72ca 100644
--- a/ui/gtk/gtk_util.cc
+++ b/ui/gtk/gtk_util.cc
@@ -27,6 +27,7 @@
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/gtk/gtk_compat.h"
 #include "ui/gtk/gtk_ui.h"
 #include "ui/gtk/gtk_ui_delegate.h"
 #include "ui/native_theme/common_theme.h"
@@ -37,16 +38,6 @@
 
 namespace gtk {
 
-#if BUILDFLAG(GTK_VERSION) >= 4
-const char kGtkCSSMenu[] = "#popover.background.menu #contents";
-const char kGtkCSSMenuItem[] = "#modelbutton.flat";
-const char kGtkCSSMenuScrollbar[] = "#scrollbar #range";
-#else
-const char kGtkCSSMenu[] = "GtkMenu#menu";
-const char kGtkCSSMenuItem[] = "GtkMenuItem#menuitem";
-const char kGtkCSSMenuScrollbar[] = "GtkScrollbar#scrollbar #trough";
-#endif
-
 namespace {
 
 const char kAuraTransientParent[] = "aura-transient-parent";
@@ -161,17 +152,27 @@
 }
 
 GtkWidget* CreateDummyWindow() {
-#if BUILDFLAG(GTK_VERSION) >= 4
-  GtkWidget* window = gtk_window_new();
-#else
-  GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-#endif
+  GtkWidget* window = GtkToplevelWindowNew();
   gtk_widget_realize(window);
   return window;
 }
 
 }  // namespace
 
+const char* GtkCssMenu() {
+  return GtkCheckVersion(4) ? "#popover.background.menu #contents"
+                            : "GtkMenu#menu";
+}
+
+const char* GtkCssMenuItem() {
+  return GtkCheckVersion(4) ? "#modelbutton.flat" : "GtkMenuItem#menuitem";
+}
+
+const char* GtkCssMenuScrollbar() {
+  return GtkCheckVersion(4) ? "#scrollbar #range"
+                            : "GtkScrollbar#scrollbar #trough";
+}
+
 void GtkInitFromCommandLine(const base::CommandLine& command_line) {
   CommonInitFromCommandLine(command_line);
 }
@@ -408,10 +409,10 @@
           object_name = t.token();
           break;
         case CSS_TYPE: {
-#if BUILDFLAG(GTK_VERSION) < 4
-          gtype = g_type_from_name(t.token().c_str());
-          DCHECK(gtype);
-#endif
+          if (!GtkCheckVersion(4)) {
+            gtype = g_type_from_name(t.token().c_str());
+            DCHECK(gtype);
+          }
           break;
         }
         case CSS_CLASS:
@@ -458,14 +459,7 @@
 }
 
 SkColor GetFgColorFromStyleContext(GtkStyleContext* context) {
-  GdkRGBA color;
-#if BUILDFLAG(GTK_VERSION) >= 4
-  gtk_style_context_get_color(context, &color);
-#else
-  gtk_style_context_get_color(context, gtk_style_context_get_state(context),
-                              &color);
-#endif
-  return GdkRgbaToSkColor(color);
+  return GdkRgbaToSkColor(GtkStyleContextGetColor(context));
 }
 
 SkColor GetBgColorFromStyleContext(GtkCssContext context) {
@@ -493,13 +487,7 @@
 
 ScopedCssProvider GetCssProvider(const std::string& css) {
   auto provider = TakeGObject(gtk_css_provider_new());
-#if BUILDFLAG(GTK_VERSION) >= 4
-  gtk_css_provider_load_from_data(provider, css.c_str(), -1);
-#else
-  GError* error = nullptr;
-  gtk_css_provider_load_from_data(provider, css.c_str(), -1, &error);
-  DCHECK(!error);
-#endif
+  GtkCssProviderLoadFromData(provider, css.c_str(), -1);
   return provider;
 }
 
@@ -544,28 +532,24 @@
   auto context = GetStyleContextFromCss(css_selector);
   if (GtkCheckVersion(3, 20))
     return GetBgColorFromStyleContext(context);
-#if BUILDFLAG(GTK_VERSION) < 4
-  // This is verbatim how Gtk gets the selection color on versions before 3.20.
+  DCHECK(!GtkCheckVersion(4));
+  // This is verbatim how Gtk gets the selection color on versions
+  // before 3.20.
   GdkRGBA selection_color;
   G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
   gtk_style_context_get_background_color(
       context, gtk_style_context_get_state(context), &selection_color);
   G_GNUC_END_IGNORE_DEPRECATIONS;
   return GdkRgbaToSkColor(selection_color);
-#else
-  NOTREACHED();
-  return gfx::kPlaceholderColor;
-#endif
 }
 
 bool ContextHasClass(GtkCssContext context, const std::string& style_class) {
-#if BUILDFLAG(GTK_VERSION) >= 4
-  return gtk_style_context_has_class(context, style_class.c_str());
-#else
-  return gtk_style_context_has_class(context, style_class.c_str()) ||
-         gtk_widget_path_iter_has_class(gtk_style_context_get_path(context), -1,
-                                        style_class.c_str());
-#endif
+  bool has_class = gtk_style_context_has_class(context, style_class.c_str());
+  if (!GtkCheckVersion(4)) {
+    has_class |= gtk_widget_path_iter_has_class(
+        gtk_style_context_get_path(context), -1, style_class.c_str());
+  }
+  return has_class;
 }
 
 SkColor GetSeparatorColor(const std::string& css_selector) {
@@ -576,22 +560,17 @@
   bool horizontal = ContextHasClass(context, "horizontal");
 
   int w = 1, h = 1;
-  GtkBorder border, padding;
-#if BUILDFLAG(GTK_VERSION) >= 4
-  auto size = GetSeparatorSize(horizontal);
-  w = size.width();
-  h = size.height();
-  gtk_style_context_get_border(context, &border);
-  gtk_style_context_get_padding(context, &padding);
-#else
-  gtk_style_context_get(context, gtk_style_context_get_state(context),
-                        "min-width", &w, "min-height", &h, nullptr);
-  GtkStateFlags state = gtk_style_context_get_state(context);
-  gtk_style_context_get_border(context, state, &border);
-  gtk_style_context_get_padding(context, state, &padding);
-#endif
-  w += border.left + padding.left + padding.right + border.right;
-  h += border.top + padding.top + padding.bottom + border.bottom;
+  if (GtkCheckVersion(4)) {
+    auto size = GetSeparatorSize(horizontal);
+    w = size.width();
+    h = size.height();
+  } else {
+    GtkStyleContextGet(context, "min-width", &w, "min-height", &h, nullptr);
+  }
+  auto border = GtkStyleContextGetBorder(context);
+  auto padding = GtkStyleContextGetPadding(context);
+  w += border.left() + padding.left() + padding.right() + border.right();
+  h += border.top() + padding.top() + padding.bottom() + border.bottom();
 
   if (horizontal) {
     w = 24;
@@ -690,19 +669,16 @@
 }
 
 GtkIconTheme* GetDefaultIconTheme() {
-#if BUILDFLAG(GTK_VERSION) >= 4
-  return gtk_icon_theme_get_for_display(gdk_display_get_default());
-#else
-  return gtk_icon_theme_get_default();
-#endif
+  return GtkCheckVersion(4)
+             ? gtk_icon_theme_get_for_display(gdk_display_get_default())
+             : gtk_icon_theme_get_default();
 }
 
 void GtkWindowDestroy(GtkWidget* widget) {
-#if BUILDFLAG(GTK_VERSION) >= 4
-  gtk_window_destroy(GTK_WINDOW(widget));
-#else
-  gtk_widget_destroy(widget);
-#endif
+  if (GtkCheckVersion(4))
+    gtk_window_destroy(GTK_WINDOW(widget));
+  else
+    gtk_widget_destroy(widget);
 }
 
 GtkWidget* GetDummyWindow() {
@@ -810,60 +786,61 @@
     case ui::kColorMenuItemBackgroundAlertedInitial:
     case ui::kColorMenuItemBackgroundAlertedTarget:
     case ui::kColorSubtleEmphasisBackground:
-      return GetBgColor(kGtkCSSMenu);
+      return GetBgColor(GtkCssMenu());
     case ui::kColorMenuBorder:
-      return GetBorderColor(kGtkCSSMenu);
+      return GetBorderColor(GtkCssMenu());
     case ui::kColorMenuItemBackgroundSelected:
-      return GetBgColor(StrCat({kGtkCSSMenu, " ", kGtkCSSMenuItem, ":hover"}));
+      return GetBgColor(
+          StrCat({GtkCssMenu(), " ", GtkCssMenuItem(), ":hover"}));
     case ui::kColorMenuItemForeground:
     case ui::kColorMenuDropmarker:
     case ui::kColorMenuItemForegroundHighlighted:
       return GetFgColor(
-          StrCat({kGtkCSSMenu, " ", kGtkCSSMenuItem, " GtkLabel#label"}));
+          StrCat({GtkCssMenu(), " ", GtkCssMenuItem(), " GtkLabel#label"}));
     case ui::kColorMenuItemForegroundSelected:
-      return GetFgColor(
-          StrCat({kGtkCSSMenu, " ", kGtkCSSMenuItem, ":hover GtkLabel#label"}));
+      return GetFgColor(StrCat(
+          {GtkCssMenu(), " ", GtkCssMenuItem(), ":hover GtkLabel#label"}));
     case ui::kColorMenuItemForegroundDisabled:
       return GetFgColor(StrCat(
-          {kGtkCSSMenu, " ", kGtkCSSMenuItem, ":disabled GtkLabel#label"}));
+          {GtkCssMenu(), " ", GtkCssMenuItem(), ":disabled GtkLabel#label"}));
     case ui::kColorAvatarIconGuest:
     case ui::kColorMenuItemForegroundSecondary:
       if (GtkCheckVersion(3, 20)) {
         return GetFgColor(
-            StrCat({kGtkCSSMenu, " ", kGtkCSSMenuItem, " #accelerator"}));
+            StrCat({GtkCssMenu(), " ", GtkCssMenuItem(), " #accelerator"}));
       }
-      return GetFgColor(StrCat(
-          {kGtkCSSMenu, " ", kGtkCSSMenuItem, " GtkLabel#label.accelerator"}));
+      return GetFgColor(StrCat({GtkCssMenu(), " ", GtkCssMenuItem(),
+                                " GtkLabel#label.accelerator"}));
     case ui::kColorMenuSeparator:
     case ui::kColorAvatarHeaderArt:
       if (GtkCheckVersion(3, 20)) {
         return GetSeparatorColor(
-            StrCat({kGtkCSSMenu, " GtkSeparator#separator.horizontal"}));
+            StrCat({GtkCssMenu(), " GtkSeparator#separator.horizontal"}));
       }
       return GetFgColor(
-          StrCat({kGtkCSSMenu, " ", kGtkCSSMenuItem, ".separator"}));
+          StrCat({GtkCssMenu(), " ", GtkCssMenuItem(), ".separator"}));
 
     // Dropdown
     case ui::kColorDropdownBackground:
       return GetBgColor(
           StrCat({"GtkComboBoxText#combobox GtkWindow#window.background.popup ",
-                  "GtkTreeMenu#menu(gtk-combobox-popup-menu) ", kGtkCSSMenuItem,
-                  " ", "GtkCellView#cellview"}));
+                  "GtkTreeMenu#menu(gtk-combobox-popup-menu) ",
+                  GtkCssMenuItem(), " ", "GtkCellView#cellview"}));
     case ui::kColorDropdownForeground:
       return GetFgColor(
           StrCat({"GtkComboBoxText#combobox GtkWindow#window.background.popup ",
-                  "GtkTreeMenu#menu(gtk-combobox-popup-menu) ", kGtkCSSMenuItem,
-                  " ", "GtkCellView#cellview"}));
+                  "GtkTreeMenu#menu(gtk-combobox-popup-menu) ",
+                  GtkCssMenuItem(), " ", "GtkCellView#cellview"}));
     case ui::kColorDropdownBackgroundSelected:
       return GetBgColor(
           StrCat({"GtkComboBoxText#combobox GtkWindow#window.background.popup ",
-                  "GtkTreeMenu#menu(gtk-combobox-popup-menu) ", kGtkCSSMenuItem,
-                  ":hover GtkCellView#cellview"}));
+                  "GtkTreeMenu#menu(gtk-combobox-popup-menu) ",
+                  GtkCssMenuItem(), ":hover GtkCellView#cellview"}));
     case ui::kColorDropdownForegroundSelected:
       return GetFgColor(
           StrCat({"GtkComboBoxText#combobox GtkWindow#window.background.popup ",
-                  "GtkTreeMenu#menu(gtk-combobox-popup-menu) ", kGtkCSSMenuItem,
-                  ":hover GtkCellView#cellview"}));
+                  "GtkTreeMenu#menu(gtk-combobox-popup-menu) ",
+                  GtkCssMenuItem(), ":hover GtkCellView#cellview"}));
 
     // Label
     case ui::kColorLabelForeground:
@@ -894,22 +871,20 @@
     case ui::kColorLinkForeground: {
       if (GtkCheckVersion(3, 12))
         return GetFgColor("GtkLabel#label.link:link");
-#if BUILDFLAG(GTK_VERSION) < 4
       auto link_context = GetStyleContextFromCss("GtkLabel#label.view");
-      GdkColor* color;
-      gtk_style_context_get_style(link_context, "link-color", &color, nullptr);
+      GdkColor* color = nullptr;
+      GtkStyleContextGetStyle(link_context, "link-color", &color, nullptr);
       if (color) {
         SkColor ret_color =
             SkColorSetRGB(color->red >> 8, color->green >> 8, color->blue >> 8);
         // gdk_color_free() was deprecated in Gtk3.14.  This code path is only
-        // taken on versions earlier than Gtk3.12, but the compiler doesn't know
-        // that, so silence the deprecation warnings.
+        // taken on versions earlier than Gtk3.12, but the compiler doesn't
+        // know that, so silence the deprecation warnings.
         G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
         gdk_color_free(color);
         G_GNUC_END_IGNORE_DEPRECATIONS;
         return ret_color;
       }
-#endif
       // Default color comes from gtklinkbutton.c.
       return SkColorSetRGB(0x00, 0x00, 0xEE);
     }
@@ -1100,8 +1075,9 @@
     case ui::kColorMenuIcon:
       if (GtkCheckVersion(3, 20))
         return GetFgColor(
-            StrCat({kGtkCSSMenu, " ", kGtkCSSMenuItem, " #radio"}));
-      return GetFgColor(StrCat({kGtkCSSMenu, " ", kGtkCSSMenuItem, ".radio"}));
+            StrCat({GtkCssMenu(), " ", GtkCssMenuItem(), " #radio"}));
+      return GetFgColor(
+          StrCat({GtkCssMenu(), " ", GtkCssMenuItem(), ".radio"}));
 
     case ui::kColorIcon:
       return GetFgColor("GtkButton#button.flat.scale GtkImage#image");
diff --git a/ui/gtk/gtk_util.h b/ui/gtk/gtk_util.h
index 67550b1..36d8846b 100644
--- a/ui/gtk/gtk_util.h
+++ b/ui/gtk/gtk_util.h
@@ -33,9 +33,9 @@
 
 namespace gtk {
 
-extern const char kGtkCSSMenu[];
-extern const char kGtkCSSMenuItem[];
-extern const char kGtkCSSMenuScrollbar[];
+const char* GtkCssMenu();
+const char* GtkCssMenuItem();
+const char* GtkCssMenuScrollbar();
 
 COMPONENT_EXPORT(GTK)
 void GtkInitFromCommandLine(const base::CommandLine& command_line);
@@ -122,7 +122,6 @@
 
 using ScopedCssProvider = ScopedGObject<GtkCssProvider>;
 
-#if BUILDFLAG(GTK_VERSION) < 4
 }  // namespace gtk
 
 // Template override cannot be in the gtk namespace.
@@ -150,7 +149,6 @@
 }
 
 namespace gtk {
-#endif
 
 // Converts ui::NativeTheme::State to GtkStateFlags.
 GtkStateFlags StateToStateFlags(ui::NativeTheme::State state);
diff --git a/ui/gtk/native_theme_gtk.cc b/ui/gtk/native_theme_gtk.cc
index 7efdd8cf..171e3edb4 100644
--- a/ui/gtk/native_theme_gtk.cc
+++ b/ui/gtk/native_theme_gtk.cc
@@ -244,7 +244,7 @@
   // Add the "flat" styleclass to avoid drawing a border.
   auto context = GetStyleContextFromCss(
       GtkCheckVersion(3, 20)
-          ? StrCat({kGtkCSSMenuScrollbar, " #range GtkButton#button.flat"})
+          ? StrCat({GtkCssMenuScrollbar(), " #range GtkButton#button.flat"})
           : "GtkRange.scrollbar.button.flat");
   // Remove any rounded corners since arrow scrollbar buttons are tiny.
   ApplyCssToContext(context, "* { border-radius: 0px; }");
@@ -282,7 +282,7 @@
   PaintWidget(
       canvas, rect,
       GetStyleContextFromCss(GtkCheckVersion(3, 20)
-                                 ? StrCat({kGtkCSSMenuScrollbar, " #trough"})
+                                 ? StrCat({GtkCssMenuScrollbar(), " #trough"})
                                  : "GtkScrollbar.scrollbar.trough"),
       BG_RENDER_NORMAL, true);
 }
@@ -296,7 +296,7 @@
     ColorScheme color_scheme) const {
   auto context = GetStyleContextFromCss(
       GtkCheckVersion(3, 20)
-          ? StrCat({kGtkCSSMenuScrollbar, " #trough #slider"})
+          ? StrCat({GtkCssMenuScrollbar(), " #trough #slider"})
           : "GtkScrollbar.scrollbar.slider");
   gtk_style_context_set_state(context, StateToStateFlags(state));
   PaintWidget(canvas, rect, context, BG_RENDER_NORMAL, true);
@@ -318,7 +318,7 @@
     const gfx::Size& size,
     const MenuBackgroundExtraParams& menu_background,
     ColorScheme color_scheme) const {
-  auto context = GetStyleContextFromCss(kGtkCSSMenu);
+  auto context = GetStyleContextFromCss(GtkCssMenu());
   // Chrome menus aren't rendered with transparency, so avoid rounded corners.
   ApplyCssToContext(context, "* { border-radius: 0px; }");
   PaintWidget(canvas, gfx::Rect(size), context, BG_RENDER_RECURSIVE, false);
@@ -331,7 +331,7 @@
     const MenuItemExtraParams& menu_item,
     ColorScheme color_scheme) const {
   auto context =
-      GetStyleContextFromCss(StrCat({kGtkCSSMenu, " ", kGtkCSSMenuItem}));
+      GetStyleContextFromCss(StrCat({GtkCssMenu(), " ", GtkCssMenuItem()}));
   gtk_style_context_set_state(context, StateToStateFlags(state));
   PaintWidget(canvas, rect, context, BG_RENDER_NORMAL, true);
 }
@@ -365,7 +365,7 @@
   };
   if (GtkCheckVersion(3, 20)) {
     auto context = GetStyleContextFromCss(
-        StrCat({kGtkCSSMenu, " GtkSeparator#separator.horizontal"}));
+        StrCat({GtkCssMenu(), " GtkSeparator#separator.horizontal"}));
     int min_height = 1;
     auto margin = GtkStyleContextGetMargin(context);
     auto border = GtkStyleContextGetBorder(context);
@@ -383,7 +383,7 @@
     PaintWidget(canvas, gfx::Rect(x, y, w, h), context, BG_RENDER_NORMAL, true);
   } else {
     auto context = GetStyleContextFromCss(
-        StrCat({kGtkCSSMenu, " ", kGtkCSSMenuItem, ".separator.horizontal"}));
+        StrCat({GtkCssMenu(), " ", GtkCssMenuItem(), ".separator.horizontal"}));
     gboolean wide_separators = false;
     gint separator_height = 0;
     GtkStyleContextGetStyle(context, "wide-separators", &wide_separators,
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc
index 25e492a..a5c8794f 100644
--- a/ui/views/bubble/bubble_dialog_delegate_view.cc
+++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -365,7 +365,6 @@
   set_title_margins(provider->GetInsetsMetric(INSETS_DIALOG_TITLE));
   if (anchor_view)
     SetAnchorView(anchor_view);
-  UpdateColorsFromTheme();
   UMA_HISTOGRAM_BOOLEAN("Dialog.BubbleDialogDelegateView.Create", true);
 }
 
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc
index 95a4b1d..7c2934f 100644
--- a/ui/views/bubble/bubble_frame_view.cc
+++ b/ui/views/bubble/bubble_frame_view.cc
@@ -472,10 +472,8 @@
 
 void BubbleFrameView::ViewHierarchyChanged(
     const ViewHierarchyChangedDetails& details) {
-  if (details.is_add && details.child == this) {
-    OnThemeChanged();
+  if (details.is_add && details.child == this)
     UpdateClientLayerCornerRadius();
-  }
 
   // We need to update the client view's corner radius whenever the header or
   // footer are added/removed from the bubble frame so that the client view
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 6de2563..39d6db7 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -232,7 +232,6 @@
   set_drag_controller(this);
   auto cursor_view = std::make_unique<View>();
   cursor_view->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
-  cursor_view->layer()->SetColor(GetTextColor());
   cursor_view->GetViewAccessibility().OverrideIsIgnored(true);
   cursor_view_ = AddChildView(std::move(cursor_view));
   GetRenderText()->SetFontList(GetDefaultFontList());