Import cobalt 25.master.0.1034729
diff --git a/base/threading/OWNERS b/base/threading/OWNERS
new file mode 100644
index 0000000..9c20e00
--- /dev/null
+++ b/base/threading/OWNERS
@@ -0,0 +1,2 @@
+# For HangWatcher implementation and tests:
+per-file hang_watcher*=olivierli@chromium.org
diff --git a/base/threading/counter_perftest.cc b/base/threading/counter_perftest.cc
new file mode 100644
index 0000000..db3b99d
--- /dev/null
+++ b/base/threading/counter_perftest.cc
@@ -0,0 +1,180 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <atomic>
+#include <string>
+
+#include "base/barrier_closure.h"
+#include "base/functional/callback.h"
+#include "base/memory/raw_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_result_reporter.h"
+
+// This file contains tests to measure the cost of incrementing:
+// - A non-atomic variable, no lock.
+// - A non-atomic variable, with lock.
+// - An atomic variable, no memory barriers.
+// - An atomic variable, acquire-release barriers.
+// The goal is to provide data to guide counter implementation choices.
+
+namespace base {
+
+namespace {
+
+constexpr char kMetricPrefixCounter[] = "Counter.";
+constexpr char kMetricOperationThroughput[] = "operation_throughput";
+constexpr uint64_t kNumIterations = 100000000;
+
+perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
+  perf_test::PerfResultReporter reporter(kMetricPrefixCounter, story_name);
+  reporter.RegisterImportantMetric(kMetricOperationThroughput, "operations/ms");
+  return reporter;
+}
+
+class Uint64_NoLock {
+ public:
+  Uint64_NoLock() = default;
+  void Increment() { counter_ = counter_ + 1; }
+  uint64_t value() const { return counter_; }
+
+ private:
+  // Volatile to prevent the compiler from over-optimizing the increment.
+  volatile uint64_t counter_ = 0;
+};
+
+class Uint64_Lock {
+ public:
+  Uint64_Lock() = default;
+  void Increment() {
+    AutoLock auto_lock(lock_);
+    ++counter_;
+  }
+  uint64_t value() const {
+    AutoLock auto_lock(lock_);
+    return counter_;
+  }
+
+ private:
+  mutable Lock lock_;
+  uint64_t counter_ GUARDED_BY(lock_) = 0;
+};
+
+class AtomicUint64_NoBarrier {
+ public:
+  AtomicUint64_NoBarrier() = default;
+  void Increment() { counter_.fetch_add(1, std::memory_order_relaxed); }
+  uint64_t value() const { return counter_; }
+
+ private:
+  std::atomic<uint64_t> counter_{0};
+};
+
+class AtomicUint64_Barrier {
+ public:
+  AtomicUint64_Barrier() = default;
+  void Increment() { counter_.fetch_add(1, std::memory_order_acq_rel); }
+  uint64_t value() const { return counter_; }
+
+ private:
+  std::atomic<uint64_t> counter_{0};
+};
+
+template <typename CounterType>
+class IncrementThread : public SimpleThread {
+ public:
+  // Upon entering its main function, the thread waits for |start_event| to be
+  // signaled. Then, it increments |counter| |kNumIterations| times.
+  // Finally, it invokes |done_closure|.
+  explicit IncrementThread(WaitableEvent* start_event,
+                           CounterType* counter,
+                           OnceClosure done_closure)
+      : SimpleThread("IncrementThread"),
+        start_event_(start_event),
+        counter_(counter),
+        done_closure_(std::move(done_closure)) {}
+
+  // SimpleThread:
+  void Run() override {
+    start_event_->Wait();
+    for (uint64_t i = 0; i < kNumIterations; ++i)
+      counter_->Increment();
+    std::move(done_closure_).Run();
+  }
+
+ private:
+  const raw_ptr<WaitableEvent> start_event_;
+  const raw_ptr<CounterType> counter_;
+  OnceClosure done_closure_;
+};
+
+template <typename CounterType>
+void RunIncrementPerfTest(const std::string& story_name, int num_threads) {
+  WaitableEvent start_event;
+  WaitableEvent end_event;
+  CounterType counter;
+  RepeatingClosure done_closure = BarrierClosure(
+      num_threads, BindOnce(&WaitableEvent::Signal, Unretained(&end_event)));
+
+  std::vector<std::unique_ptr<IncrementThread<CounterType>>> threads;
+  for (int i = 0; i < num_threads; ++i) {
+    threads.push_back(std::make_unique<IncrementThread<CounterType>>(
+        &start_event, &counter, done_closure));
+    threads.back()->Start();
+  }
+
+  TimeTicks start_time = TimeTicks::Now();
+  start_event.Signal();
+  end_event.Wait();
+  TimeTicks end_time = TimeTicks::Now();
+
+  EXPECT_EQ(num_threads * kNumIterations, counter.value());
+
+  auto reporter = SetUpReporter(story_name);
+  reporter.AddResult(
+      kMetricOperationThroughput,
+      kNumIterations / (end_time - start_time).InMillisecondsF());
+
+  for (auto& thread : threads)
+    thread->Join();
+}
+
+}  // namespace
+
+TEST(CounterPerfTest, Uint64_NoLock_1Thread) {
+  RunIncrementPerfTest<Uint64_NoLock>("Uint64_NoLock_1Thread", 1);
+}
+
+// No Uint64_NoLock_4Threads test because it would cause data races.
+
+TEST(CounterPerfTest, Uint64_Lock_1Thread) {
+  RunIncrementPerfTest<Uint64_Lock>("Uint64_Lock_1Thread", 1);
+}
+
+TEST(CounterPerfTest, Uint64_Lock_4Threads) {
+  RunIncrementPerfTest<Uint64_Lock>("Uint64_Lock_4Threads", 4);
+}
+
+TEST(CounterPerfTest, AtomicUint64_NoBarrier_1Thread) {
+  RunIncrementPerfTest<AtomicUint64_NoBarrier>("AtomicUint64_NoBarrier_1Thread",
+                                               1);
+}
+
+TEST(CounterPerfTest, AtomicUint64_NoBarrier_4Threads) {
+  RunIncrementPerfTest<AtomicUint64_NoBarrier>(
+      "AtomicUint64_NoBarrier_4Threads", 4);
+}
+
+TEST(CounterPerfTest, AtomicUint64_Barrier_1Thread) {
+  RunIncrementPerfTest<AtomicUint64_Barrier>("AtomicUint64_Barrier_1Thread", 1);
+}
+
+TEST(CounterPerfTest, AtomicUint64_Barrier_4Threads) {
+  RunIncrementPerfTest<AtomicUint64_Barrier>("AtomicUint64_Barrier_4Threads",
+                                             4);
+}
+
+}  // namespace base
diff --git a/base/threading/hang_watcher.cc b/base/threading/hang_watcher.cc
new file mode 100644
index 0000000..db5d561
--- /dev/null
+++ b/base/threading/hang_watcher.cc
@@ -0,0 +1,1328 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/hang_watcher.h"
+
+#include <atomic>
+#include <utility>
+
+#include "base/containers/flat_map.h"
+#include "base/debug/alias.h"
+#include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
+#include "base/debug/leak_annotations.h"
+#include "base/feature_list.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/power_monitor/power_monitor.h"
+#include "base/ranges/algorithm.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/threading/threading_features.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/time.h"
+#include "base/trace_event/base_tracing.h"
+#include "build/build_config.h"
+#include "third_party/abseil-cpp/absl/base/attributes.h"
+
+#if defined(STARBOARD)
+#include <pthread.h>
+
+#include "base/check_op.h"
+#include "starboard/thread.h"
+#endif
+
+namespace base {
+
+namespace {
+
+// Defines how much logging happens when the HangWatcher monitors the threads.
+// Logging levels are set per thread type through Finch. It's important that
+// the order of the enum members stay the same and that their numerical
+// values be in increasing order. The implementation of
+// ThreadTypeLoggingLevelGreaterOrEqual() depends on it.
+enum class LoggingLevel { kNone = 0, kUmaOnly = 1, kUmaAndCrash = 2 };
+
+HangWatcher* g_instance = nullptr;
+
+#if defined(STARBOARD)
+ABSL_CONST_INIT pthread_once_t s_once_flag = PTHREAD_ONCE_INIT;
+ABSL_CONST_INIT pthread_key_t s_thread_local_key = 0;
+
+void InitThreadLocalKey() {
+  int res = pthread_key_create(&s_thread_local_key , NULL);
+  DCHECK(res == 0);
+}
+
+void EnsureThreadLocalKeyInited() {
+  pthread_once(&s_once_flag, InitThreadLocalKey);
+}
+
+internal::HangWatchState* GetHangWatchState() {
+  EnsureThreadLocalKeyInited();
+  return static_cast<internal::HangWatchState*>(
+      pthread_getspecific(s_thread_local_key));
+}
+#else
+ABSL_CONST_INIT thread_local internal::HangWatchState* hang_watch_state =
+    nullptr;
+#endif
+
+std::atomic<bool> g_use_hang_watcher{false};
+std::atomic<HangWatcher::ProcessType> g_hang_watcher_process_type{
+    HangWatcher::ProcessType::kBrowserProcess};
+
+std::atomic<LoggingLevel> g_threadpool_log_level{LoggingLevel::kNone};
+std::atomic<LoggingLevel> g_io_thread_log_level{LoggingLevel::kNone};
+std::atomic<LoggingLevel> g_main_thread_log_level{LoggingLevel::kNone};
+
+// Indicates whether HangWatcher::Run() should return after the next monitoring.
+std::atomic<bool> g_keep_monitoring{true};
+
+// Emits the hung thread count histogram. |count| is the number of threads
+// of type |thread_type| that were hung or became hung during the last
+// monitoring window. This function should be invoked for each thread type
+// encountered on each call to Monitor().
+void LogHungThreadCountHistogram(HangWatcher::ThreadType thread_type,
+                                 int count) {
+  // In the case of unique threads like the IO or UI/Main thread a count does
+  // not make sense.
+  const bool any_thread_hung = count >= 1;
+
+  const HangWatcher::ProcessType process_type =
+      g_hang_watcher_process_type.load(std::memory_order_relaxed);
+  switch (process_type) {
+    case HangWatcher::ProcessType::kUnknownProcess:
+      break;
+
+    case HangWatcher::ProcessType::kBrowserProcess:
+      switch (thread_type) {
+        case HangWatcher::ThreadType::kIOThread:
+          UMA_HISTOGRAM_BOOLEAN(
+              "HangWatcher.IsThreadHung.BrowserProcess."
+              "IOThread",
+              any_thread_hung);
+          break;
+        case HangWatcher::ThreadType::kMainThread:
+          UMA_HISTOGRAM_BOOLEAN(
+              "HangWatcher.IsThreadHung.BrowserProcess."
+              "UIThread",
+              any_thread_hung);
+          break;
+        case HangWatcher::ThreadType::kThreadPoolThread:
+          // Not recorded for now.
+          break;
+      }
+      break;
+
+    case HangWatcher::ProcessType::kGPUProcess:
+      // Not recorded for now.
+      break;
+
+    case HangWatcher::ProcessType::kRendererProcess:
+      switch (thread_type) {
+        case HangWatcher::ThreadType::kIOThread:
+          UMA_HISTOGRAM_BOOLEAN(
+              "HangWatcher.IsThreadHung.RendererProcess."
+              "IOThread",
+              any_thread_hung);
+          break;
+        case HangWatcher::ThreadType::kMainThread:
+          UMA_HISTOGRAM_BOOLEAN(
+              "HangWatcher.IsThreadHung.RendererProcess."
+              "MainThread",
+              any_thread_hung);
+          break;
+        case HangWatcher::ThreadType::kThreadPoolThread:
+          // Not recorded for now.
+          break;
+      }
+      break;
+
+    case HangWatcher::ProcessType::kUtilityProcess:
+      switch (thread_type) {
+        case HangWatcher::ThreadType::kIOThread:
+          UMA_HISTOGRAM_BOOLEAN(
+              "HangWatcher.IsThreadHung.UtilityProcess."
+              "IOThread",
+              any_thread_hung);
+          break;
+        case HangWatcher::ThreadType::kMainThread:
+          UMA_HISTOGRAM_BOOLEAN(
+              "HangWatcher.IsThreadHung.UtilityProcess."
+              "MainThread",
+              any_thread_hung);
+          break;
+        case HangWatcher::ThreadType::kThreadPoolThread:
+          // Not recorded for now.
+          break;
+      }
+      break;
+  }
+}
+
+// Returns true if |thread_type| was configured through Finch to have a logging
+// level that is equal to or exceeds |logging_level|.
+bool ThreadTypeLoggingLevelGreaterOrEqual(HangWatcher::ThreadType thread_type,
+                                          LoggingLevel logging_level) {
+  switch (thread_type) {
+    case HangWatcher::ThreadType::kIOThread:
+      return g_io_thread_log_level.load(std::memory_order_relaxed) >=
+             logging_level;
+    case HangWatcher::ThreadType::kMainThread:
+      return g_main_thread_log_level.load(std::memory_order_relaxed) >=
+             logging_level;
+    case HangWatcher::ThreadType::kThreadPoolThread:
+      return g_threadpool_log_level.load(std::memory_order_relaxed) >=
+             logging_level;
+  }
+}
+
+}  // namespace
+
+// Determines if the HangWatcher is activated. When false the HangWatcher
+// thread never started.
+BASE_FEATURE(kEnableHangWatcher,
+             "EnableHangWatcher",
+             FEATURE_ENABLED_BY_DEFAULT);
+
+// Browser process.
+constexpr base::FeatureParam<int> kIOThreadLogLevel{
+    &kEnableHangWatcher, "io_thread_log_level",
+    static_cast<int>(LoggingLevel::kUmaOnly)};
+constexpr base::FeatureParam<int> kUIThreadLogLevel{
+    &kEnableHangWatcher, "ui_thread_log_level",
+    static_cast<int>(LoggingLevel::kUmaOnly)};
+constexpr base::FeatureParam<int> kThreadPoolLogLevel{
+    &kEnableHangWatcher, "threadpool_log_level",
+    static_cast<int>(LoggingLevel::kUmaOnly)};
+
+// GPU process.
+constexpr base::FeatureParam<int> kGPUProcessIOThreadLogLevel{
+    &kEnableHangWatcher, "gpu_process_io_thread_log_level",
+    static_cast<int>(LoggingLevel::kNone)};
+constexpr base::FeatureParam<int> kGPUProcessMainThreadLogLevel{
+    &kEnableHangWatcher, "gpu_process_main_thread_log_level",
+    static_cast<int>(LoggingLevel::kNone)};
+constexpr base::FeatureParam<int> kGPUProcessThreadPoolLogLevel{
+    &kEnableHangWatcher, "gpu_process_threadpool_log_level",
+    static_cast<int>(LoggingLevel::kNone)};
+
+// Renderer process.
+constexpr base::FeatureParam<int> kRendererProcessIOThreadLogLevel{
+    &kEnableHangWatcher, "renderer_process_io_thread_log_level",
+    static_cast<int>(LoggingLevel::kUmaOnly)};
+constexpr base::FeatureParam<int> kRendererProcessMainThreadLogLevel{
+    &kEnableHangWatcher, "renderer_process_main_thread_log_level",
+    static_cast<int>(LoggingLevel::kUmaOnly)};
+constexpr base::FeatureParam<int> kRendererProcessThreadPoolLogLevel{
+    &kEnableHangWatcher, "renderer_process_threadpool_log_level",
+    static_cast<int>(LoggingLevel::kUmaOnly)};
+
+// Utility process.
+constexpr base::FeatureParam<int> kUtilityProcessIOThreadLogLevel{
+    &kEnableHangWatcher, "utility_process_io_thread_log_level",
+    static_cast<int>(LoggingLevel::kUmaOnly)};
+constexpr base::FeatureParam<int> kUtilityProcessMainThreadLogLevel{
+    &kEnableHangWatcher, "utility_process_main_thread_log_level",
+    static_cast<int>(LoggingLevel::kUmaOnly)};
+constexpr base::FeatureParam<int> kUtilityProcessThreadPoolLogLevel{
+    &kEnableHangWatcher, "utility_process_threadpool_log_level",
+    static_cast<int>(LoggingLevel::kUmaOnly)};
+
+constexpr const char* kThreadName = "HangWatcher";
+
+// The time that the HangWatcher thread will sleep for between calls to
+// Monitor(). Increasing or decreasing this does not modify the type of hangs
+// that can be detected. It instead increases the probability that a call to
+// Monitor() will happen at the right time to catch a hang. This has to be
+// balanced with power/cpu use concerns as busy looping would catch amost all
+// hangs but present unacceptable overhead. NOTE: If this period is ever changed
+// then all metrics that depend on it like
+// HangWatcher.IsThreadHung need to be updated.
+constexpr auto kMonitoringPeriod = base::Seconds(10);
+
+WatchHangsInScope::WatchHangsInScope(TimeDelta timeout) {
+  internal::HangWatchState* current_hang_watch_state =
+      HangWatcher::IsEnabled()
+          ? internal::HangWatchState::GetHangWatchStateForCurrentThread()
+          : nullptr;
+
+  DCHECK(timeout >= base::TimeDelta()) << "Negative timeouts are invalid.";
+
+  // Thread is not monitored, noop.
+  if (!current_hang_watch_state) {
+    took_effect_ = false;
+    return;
+  }
+
+#if DCHECK_IS_ON()
+  previous_watch_hangs_in_scope_ =
+      current_hang_watch_state->GetCurrentWatchHangsInScope();
+  current_hang_watch_state->SetCurrentWatchHangsInScope(this);
+#endif
+
+  auto [old_flags, old_deadline] =
+      current_hang_watch_state->GetFlagsAndDeadline();
+
+  // TODO(crbug.com/1034046): Check whether we are over deadline already for the
+  // previous WatchHangsInScope here by issuing only one TimeTicks::Now()
+  // and resuing the value.
+
+  previous_deadline_ = old_deadline;
+  TimeTicks deadline = TimeTicks::Now() + timeout;
+  current_hang_watch_state->SetDeadline(deadline);
+  current_hang_watch_state->IncrementNestingLevel();
+
+  const bool hangs_ignored_for_current_scope =
+      internal::HangWatchDeadline::IsFlagSet(
+          internal::HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope,
+          old_flags);
+
+  // If the current WatchHangsInScope is ignored, temporarily reactivate hang
+  // watching for newly created WatchHangsInScopes. On exiting hang watching
+  // is suspended again to return to the original state.
+  if (hangs_ignored_for_current_scope) {
+    current_hang_watch_state->UnsetIgnoreCurrentWatchHangsInScope();
+    set_hangs_ignored_on_exit_ = true;
+  }
+}
+
+WatchHangsInScope::~WatchHangsInScope() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  // If hang watching was not enabled at construction time there is nothing to
+  // validate or undo.
+  if (!took_effect_) {
+    return;
+  }
+
+  // If the thread was unregistered since construction there is also nothing to
+  // do.
+  auto* const state =
+      internal::HangWatchState::GetHangWatchStateForCurrentThread();
+  if (!state) {
+    return;
+  }
+
+  // If a hang is currently being captured we should block here so execution
+  // stops and we avoid recording unrelated stack frames in the crash.
+  if (state->IsFlagSet(internal::HangWatchDeadline::Flag::kShouldBlockOnHang)) {
+    base::HangWatcher::GetInstance()->BlockIfCaptureInProgress();
+  }
+
+#if DCHECK_IS_ON()
+  // Verify that no Scope was destructed out of order.
+  DCHECK_EQ(this, state->GetCurrentWatchHangsInScope());
+  state->SetCurrentWatchHangsInScope(previous_watch_hangs_in_scope_);
+#endif
+
+  if (state->nesting_level() == 1) {
+    // If a call to InvalidateActiveExpectations() suspended hang watching
+    // during the lifetime of this or any nested WatchHangsInScope it can now
+    // safely be reactivated by clearing the ignore bit since this is the
+    // outer-most scope.
+    state->UnsetIgnoreCurrentWatchHangsInScope();
+  } else if (set_hangs_ignored_on_exit_) {
+    // Return to ignoring hangs since this was the previous state before hang
+    // watching was temporarily enabled for this WatchHangsInScope only in the
+    // constructor.
+    state->SetIgnoreCurrentWatchHangsInScope();
+  }
+
+  // Reset the deadline to the value it had before entering this
+  // WatchHangsInScope.
+  state->SetDeadline(previous_deadline_);
+  // TODO(crbug.com/1034046): Log when a WatchHangsInScope exits after its
+  // deadline and that went undetected by the HangWatcher.
+
+  state->DecrementNestingLevel();
+}
+
+// static
+void HangWatcher::InitializeOnMainThread(ProcessType process_type) {
+  DCHECK(!g_use_hang_watcher);
+  DCHECK(g_io_thread_log_level == LoggingLevel::kNone);
+  DCHECK(g_main_thread_log_level == LoggingLevel::kNone);
+  DCHECK(g_threadpool_log_level == LoggingLevel::kNone);
+
+  bool enable_hang_watcher = base::FeatureList::IsEnabled(kEnableHangWatcher);
+
+  // Do not start HangWatcher in the GPU process until the issue related to
+  // invalid magic signature in the GPU WatchDog is fixed
+  // (https://crbug.com/1297760).
+  if (process_type == ProcessType::kGPUProcess)
+    enable_hang_watcher = false;
+
+  g_use_hang_watcher.store(enable_hang_watcher, std::memory_order_relaxed);
+
+  // Keep the process type.
+  g_hang_watcher_process_type.store(process_type, std::memory_order_relaxed);
+
+  // If hang watching is disabled as a whole there is no need to read the
+  // params.
+  if (!enable_hang_watcher)
+    return;
+
+  // Retrieve thread-specific config for hang watching.
+  switch (process_type) {
+    case HangWatcher::ProcessType::kUnknownProcess:
+      break;
+
+    case HangWatcher::ProcessType::kBrowserProcess:
+      g_threadpool_log_level.store(
+          static_cast<LoggingLevel>(kThreadPoolLogLevel.Get()),
+          std::memory_order_relaxed);
+      g_io_thread_log_level.store(
+          static_cast<LoggingLevel>(kIOThreadLogLevel.Get()),
+          std::memory_order_relaxed);
+      g_main_thread_log_level.store(
+          static_cast<LoggingLevel>(kUIThreadLogLevel.Get()),
+          std::memory_order_relaxed);
+      break;
+
+    case HangWatcher::ProcessType::kGPUProcess:
+      g_threadpool_log_level.store(
+          static_cast<LoggingLevel>(kGPUProcessThreadPoolLogLevel.Get()),
+          std::memory_order_relaxed);
+      g_io_thread_log_level.store(
+          static_cast<LoggingLevel>(kGPUProcessIOThreadLogLevel.Get()),
+          std::memory_order_relaxed);
+      g_main_thread_log_level.store(
+          static_cast<LoggingLevel>(kGPUProcessMainThreadLogLevel.Get()),
+          std::memory_order_relaxed);
+      break;
+
+    case HangWatcher::ProcessType::kRendererProcess:
+      g_threadpool_log_level.store(
+          static_cast<LoggingLevel>(kRendererProcessThreadPoolLogLevel.Get()),
+          std::memory_order_relaxed);
+      g_io_thread_log_level.store(
+          static_cast<LoggingLevel>(kRendererProcessIOThreadLogLevel.Get()),
+          std::memory_order_relaxed);
+      g_main_thread_log_level.store(
+          static_cast<LoggingLevel>(kRendererProcessMainThreadLogLevel.Get()),
+          std::memory_order_relaxed);
+      break;
+
+    case HangWatcher::ProcessType::kUtilityProcess:
+      g_threadpool_log_level.store(
+          static_cast<LoggingLevel>(kUtilityProcessThreadPoolLogLevel.Get()),
+          std::memory_order_relaxed);
+      g_io_thread_log_level.store(
+          static_cast<LoggingLevel>(kUtilityProcessIOThreadLogLevel.Get()),
+          std::memory_order_relaxed);
+      g_main_thread_log_level.store(
+          static_cast<LoggingLevel>(kUtilityProcessMainThreadLogLevel.Get()),
+          std::memory_order_relaxed);
+      break;
+  }
+}
+
+void HangWatcher::UnitializeOnMainThreadForTesting() {
+  g_use_hang_watcher.store(false, std::memory_order_relaxed);
+  g_threadpool_log_level.store(LoggingLevel::kNone, std::memory_order_relaxed);
+  g_io_thread_log_level.store(LoggingLevel::kNone, std::memory_order_relaxed);
+  g_main_thread_log_level.store(LoggingLevel::kNone, std::memory_order_relaxed);
+}
+
+// static
+bool HangWatcher::IsEnabled() {
+  return g_use_hang_watcher.load(std::memory_order_relaxed);
+}
+
+// static
+bool HangWatcher::IsThreadPoolHangWatchingEnabled() {
+  return g_threadpool_log_level.load(std::memory_order_relaxed) !=
+         LoggingLevel::kNone;
+}
+
+// static
+bool HangWatcher::IsIOThreadHangWatchingEnabled() {
+  return g_io_thread_log_level.load(std::memory_order_relaxed) !=
+         LoggingLevel::kNone;
+}
+
+// static
+bool HangWatcher::IsCrashReportingEnabled() {
+  if (g_main_thread_log_level.load(std::memory_order_relaxed) ==
+      LoggingLevel::kUmaAndCrash) {
+    return true;
+  }
+  if (g_io_thread_log_level.load(std::memory_order_relaxed) ==
+      LoggingLevel::kUmaAndCrash) {
+    return true;
+  }
+  if (g_threadpool_log_level.load(std::memory_order_relaxed) ==
+      LoggingLevel::kUmaAndCrash) {
+    return true;
+  }
+  return false;
+}
+
+// static
+void HangWatcher::InvalidateActiveExpectations() {
+  auto* const state =
+      internal::HangWatchState::GetHangWatchStateForCurrentThread();
+  if (!state) {
+    // If the current thread is not under watch there is nothing to invalidate.
+    return;
+  }
+  state->SetIgnoreCurrentWatchHangsInScope();
+}
+
+HangWatcher::HangWatcher()
+    : monitor_period_(kMonitoringPeriod),
+      should_monitor_(WaitableEvent::ResetPolicy::AUTOMATIC),
+      thread_(this, kThreadName),
+      tick_clock_(base::DefaultTickClock::GetInstance()),
+      memory_pressure_listener_(
+          FROM_HERE,
+          base::BindRepeating(&HangWatcher::OnMemoryPressure,
+                              base::Unretained(this))) {
+  // |thread_checker_| should not be bound to the constructing thread.
+  DETACH_FROM_THREAD(hang_watcher_thread_checker_);
+
+  should_monitor_.declare_only_used_while_idle();
+
+  DCHECK(!g_instance);
+  g_instance = this;
+}
+
+// static
+void HangWatcher::CreateHangWatcherInstance() {
+  DCHECK(!g_instance);
+  g_instance = new base::HangWatcher();
+  // The hang watcher is leaked to make sure it survives all watched threads.
+  ANNOTATE_LEAKING_OBJECT_PTR(g_instance);
+}
+
+#if !BUILDFLAG(IS_NACL)
+debug::ScopedCrashKeyString
+HangWatcher::GetTimeSinceLastCriticalMemoryPressureCrashKey() {
+  DCHECK_CALLED_ON_VALID_THREAD(hang_watcher_thread_checker_);
+
+  // The crash key size is large enough to hold the biggest possible return
+  // value from base::TimeDelta::InSeconds().
+  constexpr debug::CrashKeySize kCrashKeyContentSize =
+      debug::CrashKeySize::Size32;
+  DCHECK_GE(static_cast<uint64_t>(kCrashKeyContentSize),
+            base::NumberToString(std::numeric_limits<int64_t>::max()).size());
+
+  static debug::CrashKeyString* crash_key = AllocateCrashKeyString(
+      "seconds-since-last-memory-pressure", kCrashKeyContentSize);
+
+  const base::TimeTicks last_critical_memory_pressure_time =
+      last_critical_memory_pressure_.load(std::memory_order_relaxed);
+  if (last_critical_memory_pressure_time.is_null()) {
+    constexpr char kNoMemoryPressureMsg[] = "No critical memory pressure";
+    static_assert(
+        std::size(kNoMemoryPressureMsg) <=
+            static_cast<uint64_t>(kCrashKeyContentSize),
+        "The crash key is too small to hold \"No critical memory pressure\".");
+    return debug::ScopedCrashKeyString(crash_key, kNoMemoryPressureMsg);
+  } else {
+    base::TimeDelta time_since_last_critical_memory_pressure =
+        base::TimeTicks::Now() - last_critical_memory_pressure_time;
+    return debug::ScopedCrashKeyString(
+        crash_key, base::NumberToString(
+                       time_since_last_critical_memory_pressure.InSeconds()));
+  }
+}
+#endif
+
+std::string HangWatcher::GetTimeSinceLastSystemPowerResumeCrashKeyValue()
+    const {
+  DCHECK_CALLED_ON_VALID_THREAD(hang_watcher_thread_checker_);
+
+  const TimeTicks last_system_power_resume_time =
+      PowerMonitor::GetLastSystemResumeTime();
+  if (last_system_power_resume_time.is_null())
+    return "Never suspended";
+  if (last_system_power_resume_time == TimeTicks::Max())
+    return "Power suspended";
+
+  const TimeDelta time_since_last_system_resume =
+      TimeTicks::Now() - last_system_power_resume_time;
+  return NumberToString(time_since_last_system_resume.InSeconds());
+}
+
+void HangWatcher::OnMemoryPressure(
+    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+  if (memory_pressure_level ==
+      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
+    last_critical_memory_pressure_.store(base::TimeTicks::Now(),
+                                         std::memory_order_relaxed);
+  }
+}
+
+HangWatcher::~HangWatcher() {
+  DCHECK_CALLED_ON_VALID_THREAD(constructing_thread_checker_);
+  DCHECK_EQ(g_instance, this);
+  DCHECK(watch_states_.empty());
+  g_instance = nullptr;
+  Stop();
+}
+
+void HangWatcher::Start() {
+  thread_.Start();
+}
+
+void HangWatcher::Stop() {
+  g_keep_monitoring.store(false, std::memory_order_relaxed);
+  should_monitor_.Signal();
+  thread_.Join();
+
+  // In production HangWatcher is always leaked but during testing it's possibly
+  // stopped and restarted using a new instance. This makes sure the next call
+  // to Start() will actually monitor in that case.
+  g_keep_monitoring.store(true, std::memory_order_relaxed);
+}
+
+bool HangWatcher::IsWatchListEmpty() {
+  AutoLock auto_lock(watch_state_lock_);
+  return watch_states_.empty();
+}
+
+void HangWatcher::Wait() {
+  while (true) {
+    // Amount by which the actual time spent sleeping can deviate from
+    // the target time and still be considered timely.
+    constexpr base::TimeDelta kWaitDriftTolerance = base::Milliseconds(100);
+
+    const base::TimeTicks time_before_wait = tick_clock_->NowTicks();
+
+    // Sleep until next scheduled monitoring or until signaled.
+    const bool was_signaled = should_monitor_.TimedWait(monitor_period_);
+
+    if (after_wait_callback_)
+      after_wait_callback_.Run(time_before_wait);
+
+    const base::TimeTicks time_after_wait = tick_clock_->NowTicks();
+    const base::TimeDelta wait_time = time_after_wait - time_before_wait;
+    const bool wait_was_normal =
+        wait_time <= (monitor_period_ + kWaitDriftTolerance);
+
+    UMA_HISTOGRAM_TIMES("HangWatcher.SleepDrift.BrowserProcess",
+                        wait_time - monitor_period_);
+
+    if (!wait_was_normal) {
+      // If the time spent waiting was too high it might indicate the machine is
+      // very slow or that that it went to sleep. In any case we can't trust the
+      // WatchHangsInScopes that are currently live. Update the ignore
+      // threshold to make sure they don't trigger a hang on subsequent monitors
+      // then keep waiting.
+
+      base::AutoLock auto_lock(watch_state_lock_);
+
+      // Find the latest deadline among the live watch states. They might change
+      // atomically while iterating but that's fine because if they do that
+      // means the new WatchHangsInScope was constructed very soon after the
+      // abnormal sleep happened and might be affected by the root cause still.
+      // Ignoring it is cautious and harmless.
+      base::TimeTicks latest_deadline;
+      for (const auto& state : watch_states_) {
+        base::TimeTicks deadline = state->GetDeadline();
+        if (deadline > latest_deadline) {
+          latest_deadline = deadline;
+        }
+      }
+
+      deadline_ignore_threshold_ = latest_deadline;
+    }
+
+    // Stop waiting.
+    if (wait_was_normal || was_signaled)
+      return;
+  }
+}
+
+void HangWatcher::Run() {
+  // Monitor() should only run on |thread_|. Bind |thread_checker_| here to make
+  // sure of that.
+  DCHECK_CALLED_ON_VALID_THREAD(hang_watcher_thread_checker_);
+
+  while (g_keep_monitoring.load(std::memory_order_relaxed)) {
+    Wait();
+
+    if (!IsWatchListEmpty() &&
+        g_keep_monitoring.load(std::memory_order_relaxed)) {
+      Monitor();
+      if (after_monitor_closure_for_testing_) {
+        after_monitor_closure_for_testing_.Run();
+      }
+    }
+  }
+}
+
+// static
+HangWatcher* HangWatcher::GetInstance() {
+  return g_instance;
+}
+
+// static
+void HangWatcher::RecordHang() {
+  base::debug::DumpWithoutCrashing();
+  NO_CODE_FOLDING();
+}
+
+ScopedClosureRunner HangWatcher::RegisterThreadInternal(
+    ThreadType thread_type) {
+  AutoLock auto_lock(watch_state_lock_);
+  CHECK(base::FeatureList::GetInstance());
+
+  // Do not install a WatchState if the results would never be observable.
+  if (!ThreadTypeLoggingLevelGreaterOrEqual(thread_type,
+                                            LoggingLevel::kUmaOnly)) {
+    return ScopedClosureRunner(base::DoNothing());
+  }
+
+  watch_states_.push_back(
+      internal::HangWatchState::CreateHangWatchStateForCurrentThread(
+          thread_type));
+  return ScopedClosureRunner(BindOnce(&HangWatcher::UnregisterThread,
+                                      Unretained(HangWatcher::GetInstance())));
+}
+
+// static
+ScopedClosureRunner HangWatcher::RegisterThread(ThreadType thread_type) {
+  if (!GetInstance()) {
+    return ScopedClosureRunner();
+  }
+
+  return GetInstance()->RegisterThreadInternal(thread_type);
+}
+
+base::TimeTicks HangWatcher::WatchStateSnapShot::GetHighestDeadline() const {
+  DCHECK(IsActionable());
+
+  // Since entries are sorted in increasing order the last entry is the largest
+  // one.
+  return hung_watch_state_copies_.back().deadline;
+}
+
+HangWatcher::WatchStateSnapShot::WatchStateSnapShot() = default;
+
+void HangWatcher::WatchStateSnapShot::Init(
+    const HangWatchStates& watch_states,
+    base::TimeTicks deadline_ignore_threshold) {
+  DCHECK(!initialized_);
+
+  // No matter if the snapshot is actionable or not after this function
+  // it will have been initialized.
+  initialized_ = true;
+
+  const base::TimeTicks now = base::TimeTicks::Now();
+  bool all_threads_marked = true;
+  bool found_deadline_before_ignore_threshold = false;
+
+  // Use an std::array to store the hang counts to avoid allocations. The
+  // numerical values of the HangWatcher::ThreadType enum is used to index into
+  // the array. A |kInvalidHangCount| is used to signify there were no threads
+  // of the type found.
+  constexpr size_t kHangCountArraySize =
+      static_cast<std::size_t>(base::HangWatcher::ThreadType::kMax) + 1;
+  std::array<int, kHangCountArraySize> hung_counts_per_thread_type;
+
+  constexpr int kInvalidHangCount = -1;
+  hung_counts_per_thread_type.fill(kInvalidHangCount);
+
+  // Will be true if any of the hung threads has a logging level high enough,
+  // as defined through finch params, to warant dumping a crash.
+  bool any_hung_thread_has_dumping_enabled = false;
+
+  // Copy hung thread information.
+  for (const auto& watch_state : watch_states) {
+    uint64_t flags;
+    TimeTicks deadline;
+    std::tie(flags, deadline) = watch_state->GetFlagsAndDeadline();
+
+    if (deadline <= deadline_ignore_threshold) {
+      found_deadline_before_ignore_threshold = true;
+    }
+
+    if (internal::HangWatchDeadline::IsFlagSet(
+            internal::HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope,
+            flags)) {
+      continue;
+    }
+
+    // If a thread type is monitored and did not hang it still needs to be
+    // logged as a zero count;
+    const size_t hang_count_index =
+        static_cast<size_t>(watch_state.get()->thread_type());
+    if (hung_counts_per_thread_type[hang_count_index] == kInvalidHangCount) {
+      hung_counts_per_thread_type[hang_count_index] = 0;
+    }
+
+    // Only copy hung threads.
+    if (deadline <= now) {
+      ++hung_counts_per_thread_type[hang_count_index];
+
+      if (ThreadTypeLoggingLevelGreaterOrEqual(watch_state.get()->thread_type(),
+                                               LoggingLevel::kUmaAndCrash)) {
+        any_hung_thread_has_dumping_enabled = true;
+      }
+
+#if BUILDFLAG(ENABLE_BASE_TRACING)
+      // Emit trace events for monitored threads.
+      if (ThreadTypeLoggingLevelGreaterOrEqual(watch_state.get()->thread_type(),
+                                               LoggingLevel::kUmaOnly)) {
+        const PlatformThreadId thread_id = watch_state.get()->GetThreadID();
+        const auto track = perfetto::Track::FromPointer(
+            this, perfetto::ThreadTrack::ForThread(thread_id));
+        TRACE_EVENT_BEGIN("base", "HangWatcher::ThreadHung", track, deadline);
+        TRACE_EVENT_END("base", track, now);
+        // TODO(crbug.com/1021571): Remove this once fixed.
+        PERFETTO_INTERNAL_ADD_EMPTY_EVENT();
+      }
+#endif
+
+      // Attempt to mark the thread as needing to stay within its current
+      // WatchHangsInScope until capture is complete.
+      bool thread_marked = watch_state->SetShouldBlockOnHang(flags, deadline);
+
+      // If marking some threads already failed the snapshot won't be kept so
+      // there is no need to keep adding to it. The loop doesn't abort though
+      // to keep marking the other threads. If these threads remain hung until
+      // the next capture then they'll already be marked and will be included
+      // in the capture at that time.
+      if (thread_marked && all_threads_marked) {
+        hung_watch_state_copies_.push_back(
+            WatchStateCopy{deadline, watch_state.get()->GetThreadID()});
+      } else {
+        all_threads_marked = false;
+      }
+    }
+  }
+
+  // Log the hung thread counts to histograms for each thread type if any thread
+  // of the type were found.
+  for (size_t i = 0; i < kHangCountArraySize; ++i) {
+    const int hang_count = hung_counts_per_thread_type[i];
+    const HangWatcher::ThreadType thread_type =
+        static_cast<HangWatcher::ThreadType>(i);
+    if (hang_count != kInvalidHangCount &&
+        ThreadTypeLoggingLevelGreaterOrEqual(thread_type,
+                                             LoggingLevel::kUmaOnly)) {
+      LogHungThreadCountHistogram(thread_type, hang_count);
+    }
+  }
+
+  // Three cases can invalidate this snapshot and prevent the capture of the
+  // hang.
+  //
+  // 1. Some threads could not be marked for blocking so this snapshot isn't
+  // actionable since marked threads could be hung because of unmarked ones.
+  // If only the marked threads were captured the information would be
+  // incomplete.
+  //
+  // 2. Any of the threads have a deadline before |deadline_ignore_threshold|.
+  // If any thread is ignored it reduces the confidence in the whole state and
+  // it's better to avoid capturing misleading data.
+  //
+  // 3. The hung threads found were all of types that are not configured through
+  // Finch to trigger a crash dump.
+  //
+  if (!all_threads_marked || found_deadline_before_ignore_threshold ||
+      !any_hung_thread_has_dumping_enabled) {
+    hung_watch_state_copies_.clear();
+    return;
+  }
+
+  // Sort |hung_watch_state_copies_| by order of decreasing hang severity so the
+  // most severe hang is first in the list.
+  ranges::sort(hung_watch_state_copies_,
+               [](const WatchStateCopy& lhs, const WatchStateCopy& rhs) {
+                 return lhs.deadline < rhs.deadline;
+               });
+}
+
+void HangWatcher::WatchStateSnapShot::Clear() {
+  hung_watch_state_copies_.clear();
+  initialized_ = false;
+}
+
+HangWatcher::WatchStateSnapShot::WatchStateSnapShot(
+    const WatchStateSnapShot& other) = default;
+
+HangWatcher::WatchStateSnapShot::~WatchStateSnapShot() = default;
+
+std::string HangWatcher::WatchStateSnapShot::PrepareHungThreadListCrashKey()
+    const {
+  DCHECK(IsActionable());
+
+  // Build a crash key string that contains the ids of the hung threads.
+  constexpr char kSeparator{'|'};
+  std::string list_of_hung_thread_ids;
+
+  // Add as many thread ids to the crash key as possible.
+  for (const WatchStateCopy& copy : hung_watch_state_copies_) {
+    std::string fragment = base::NumberToString(copy.thread_id) + kSeparator;
+    if (list_of_hung_thread_ids.size() + fragment.size() <
+        static_cast<std::size_t>(debug::CrashKeySize::Size256)) {
+      list_of_hung_thread_ids += fragment;
+    } else {
+      // Respect the by priority ordering of thread ids in the crash key by
+      // stopping the construction as soon as one does not fit. This avoids
+      // including lesser priority ids while omitting more important ones.
+      break;
+    }
+  }
+
+  return list_of_hung_thread_ids;
+}
+
+bool HangWatcher::WatchStateSnapShot::IsActionable() const {
+  DCHECK(initialized_);
+  return !hung_watch_state_copies_.empty();
+}
+
+HangWatcher::WatchStateSnapShot HangWatcher::GrabWatchStateSnapshotForTesting()
+    const {
+  WatchStateSnapShot snapshot;
+  snapshot.Init(watch_states_, deadline_ignore_threshold_);
+  return snapshot;
+}
+
+void HangWatcher::Monitor() {
+  DCHECK_CALLED_ON_VALID_THREAD(hang_watcher_thread_checker_);
+  AutoLock auto_lock(watch_state_lock_);
+
+  // If all threads unregistered since this function was invoked there's
+  // nothing to do anymore.
+  if (watch_states_.empty())
+    return;
+
+  watch_state_snapshot_.Init(watch_states_, deadline_ignore_threshold_);
+
+  if (watch_state_snapshot_.IsActionable()) {
+    DoDumpWithoutCrashing(watch_state_snapshot_);
+  }
+
+  watch_state_snapshot_.Clear();
+}
+
+void HangWatcher::DoDumpWithoutCrashing(
+    const WatchStateSnapShot& watch_state_snapshot) {
+  TRACE_EVENT("base", "HangWatcher::DoDumpWithoutCrashing");
+
+  capture_in_progress_.store(true, std::memory_order_relaxed);
+  base::AutoLock scope_lock(capture_lock_);
+
+#if !BUILDFLAG(IS_NACL)
+  const std::string list_of_hung_thread_ids =
+      watch_state_snapshot.PrepareHungThreadListCrashKey();
+
+  static debug::CrashKeyString* crash_key = AllocateCrashKeyString(
+      "list-of-hung-threads", debug::CrashKeySize::Size256);
+
+  const debug::ScopedCrashKeyString list_of_hung_threads_crash_key_string(
+      crash_key, list_of_hung_thread_ids);
+
+  const debug::ScopedCrashKeyString
+      time_since_last_critical_memory_pressure_crash_key_string =
+          GetTimeSinceLastCriticalMemoryPressureCrashKey();
+
+  SCOPED_CRASH_KEY_STRING32("HangWatcher", "seconds-since-last-resume",
+                            GetTimeSinceLastSystemPowerResumeCrashKeyValue());
+#endif
+
+  // To avoid capturing more than one hang that blames a subset of the same
+  // threads it's necessary to keep track of what is the furthest deadline
+  // that contributed to declaring a hang. Only once
+  // all threads have deadlines past this point can we be sure that a newly
+  // discovered hang is not directly related.
+  // Example:
+  // **********************************************************************
+  // Timeline A : L------1-------2----------3-------4----------N-----------
+  // Timeline B : -------2----------3-------4----------L----5------N-------
+  // Timeline C : L----------------------------5------6----7---8------9---N
+  // **********************************************************************
+  // In the example when a Monitor() happens during timeline A
+  // |deadline_ignore_threshold_| (L) is at time zero and deadlines (1-4)
+  // are before Now() (N) . A hang is captured and L is updated. During
+  // the next Monitor() (timeline B) a new deadline is over but we can't
+  // capture a hang because deadlines 2-4 are still live and already counted
+  // toward a hang. During a third monitor (timeline C) all live deadlines
+  // are now after L and a second hang can be recorded.
+  base::TimeTicks latest_expired_deadline =
+      watch_state_snapshot.GetHighestDeadline();
+
+  if (on_hang_closure_for_testing_)
+    on_hang_closure_for_testing_.Run();
+  else
+    RecordHang();
+
+  // Update after running the actual capture.
+  deadline_ignore_threshold_ = latest_expired_deadline;
+
+  capture_in_progress_.store(false, std::memory_order_relaxed);
+}
+
+void HangWatcher::SetAfterMonitorClosureForTesting(
+    base::RepeatingClosure closure) {
+  DCHECK_CALLED_ON_VALID_THREAD(constructing_thread_checker_);
+  after_monitor_closure_for_testing_ = std::move(closure);
+}
+
+void HangWatcher::SetOnHangClosureForTesting(base::RepeatingClosure closure) {
+  DCHECK_CALLED_ON_VALID_THREAD(constructing_thread_checker_);
+  on_hang_closure_for_testing_ = std::move(closure);
+}
+
+void HangWatcher::SetMonitoringPeriodForTesting(base::TimeDelta period) {
+  DCHECK_CALLED_ON_VALID_THREAD(constructing_thread_checker_);
+  monitor_period_ = period;
+}
+
+void HangWatcher::SetAfterWaitCallbackForTesting(
+    RepeatingCallback<void(TimeTicks)> callback) {
+  DCHECK_CALLED_ON_VALID_THREAD(constructing_thread_checker_);
+  after_wait_callback_ = callback;
+}
+
+void HangWatcher::SignalMonitorEventForTesting() {
+  DCHECK_CALLED_ON_VALID_THREAD(constructing_thread_checker_);
+  should_monitor_.Signal();
+}
+
+// static
+void HangWatcher::StopMonitoringForTesting() {
+  g_keep_monitoring.store(false, std::memory_order_relaxed);
+}
+
+void HangWatcher::SetTickClockForTesting(const base::TickClock* tick_clock) {
+  tick_clock_ = tick_clock;
+}
+
+void HangWatcher::BlockIfCaptureInProgress() {
+  // Makes a best-effort attempt to block execution if a hang is currently being
+  // captured. Only block on |capture_lock| if |capture_in_progress_| hints that
+  // it's already held to avoid serializing all threads on this function when no
+  // hang capture is in-progress.
+  if (capture_in_progress_.load(std::memory_order_relaxed))
+    base::AutoLock hang_lock(capture_lock_);
+}
+
+void HangWatcher::UnregisterThread() {
+  AutoLock auto_lock(watch_state_lock_);
+
+  auto it = ranges::find(
+      watch_states_,
+      internal::HangWatchState::GetHangWatchStateForCurrentThread(),
+      &std::unique_ptr<internal::HangWatchState>::get);
+
+  // Thread should be registered to get unregistered.
+  DCHECK(it != watch_states_.end());
+
+  watch_states_.erase(it);
+}
+
+namespace internal {
+namespace {
+
+constexpr uint64_t kOnlyDeadlineMask = 0x00FF'FFFF'FFFF'FFFFu;
+constexpr uint64_t kOnlyFlagsMask = ~kOnlyDeadlineMask;
+constexpr uint64_t kMaximumFlag = 0x8000'0000'0000'0000u;
+
+// Use as a mask to keep persistent flags and the deadline.
+constexpr uint64_t kPersistentFlagsAndDeadlineMask =
+    kOnlyDeadlineMask |
+    static_cast<uint64_t>(
+        HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope);
+}  // namespace
+
+// Flag binary representation assertions.
+static_assert(
+    static_cast<uint64_t>(HangWatchDeadline::Flag::kMinValue) >
+        kOnlyDeadlineMask,
+    "Invalid numerical value for flag. Would interfere with bits of data.");
+static_assert(static_cast<uint64_t>(HangWatchDeadline::Flag::kMaxValue) <=
+                  kMaximumFlag,
+              "A flag can only set a single bit.");
+
+HangWatchDeadline::HangWatchDeadline() = default;
+HangWatchDeadline::~HangWatchDeadline() = default;
+
+std::pair<uint64_t, TimeTicks> HangWatchDeadline::GetFlagsAndDeadline() const {
+  uint64_t bits = bits_.load(std::memory_order_relaxed);
+  return std::make_pair(ExtractFlags(bits),
+                        DeadlineFromBits(ExtractDeadline((bits))));
+}
+
+TimeTicks HangWatchDeadline::GetDeadline() const {
+  return DeadlineFromBits(
+      ExtractDeadline(bits_.load(std::memory_order_relaxed)));
+}
+
+// static
+TimeTicks HangWatchDeadline::Max() {
+  // |kOnlyDeadlineMask| has all the bits reserved for the TimeTicks value
+  // set. This means it also represents the highest representable value.
+  return DeadlineFromBits(kOnlyDeadlineMask);
+}
+
+// static
+bool HangWatchDeadline::IsFlagSet(Flag flag, uint64_t flags) {
+  return static_cast<uint64_t>(flag) & flags;
+}
+
+void HangWatchDeadline::SetDeadline(TimeTicks new_deadline) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(new_deadline <= Max()) << "Value too high to be represented.";
+  DCHECK(new_deadline >= TimeTicks{}) << "Value cannot be negative.";
+
+  if (switch_bits_callback_for_testing_) {
+    const uint64_t switched_in_bits = SwitchBitsForTesting();
+    // If a concurrent deadline change is tested it cannot have a deadline or
+    // persistent flag change since those always happen on the same thread.
+    DCHECK((switched_in_bits & kPersistentFlagsAndDeadlineMask) == 0u);
+  }
+
+  // Discard all non-persistent flags and apply deadline change.
+  const uint64_t old_bits = bits_.load(std::memory_order_relaxed);
+  const uint64_t new_flags =
+      ExtractFlags(old_bits & kPersistentFlagsAndDeadlineMask);
+  bits_.store(new_flags | ExtractDeadline(static_cast<uint64_t>(
+                              new_deadline.ToInternalValue())),
+              std::memory_order_relaxed);
+}
+
+// TODO(crbug.com/1087026): Add flag DCHECKs here.
+bool HangWatchDeadline::SetShouldBlockOnHang(uint64_t old_flags,
+                                             TimeTicks old_deadline) {
+  DCHECK(old_deadline <= Max()) << "Value too high to be represented.";
+  DCHECK(old_deadline >= TimeTicks{}) << "Value cannot be negative.";
+
+  // Set the kShouldBlockOnHang flag only if |bits_| did not change since it was
+  // read. kShouldBlockOnHang is the only non-persistent flag and should never
+  // be set twice. Persistent flags and deadline changes are done from the same
+  // thread so there is no risk of losing concurrently added information.
+  uint64_t old_bits =
+      old_flags | static_cast<uint64_t>(old_deadline.ToInternalValue());
+  const uint64_t desired_bits =
+      old_bits | static_cast<uint64_t>(Flag::kShouldBlockOnHang);
+
+  // If a test needs to simulate |bits_| changing since calling this function
+  // this happens now.
+  if (switch_bits_callback_for_testing_) {
+    const uint64_t switched_in_bits = SwitchBitsForTesting();
+
+    // Injecting the flag being tested is invalid.
+    DCHECK(!IsFlagSet(Flag::kShouldBlockOnHang, switched_in_bits));
+  }
+
+  return bits_.compare_exchange_weak(old_bits, desired_bits,
+                                     std::memory_order_relaxed,
+                                     std::memory_order_relaxed);
+}
+
+void HangWatchDeadline::SetIgnoreCurrentWatchHangsInScope() {
+  SetPersistentFlag(Flag::kIgnoreCurrentWatchHangsInScope);
+}
+
+void HangWatchDeadline::UnsetIgnoreCurrentWatchHangsInScope() {
+  ClearPersistentFlag(Flag::kIgnoreCurrentWatchHangsInScope);
+}
+
+void HangWatchDeadline::SetPersistentFlag(Flag flag) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  if (switch_bits_callback_for_testing_)
+    SwitchBitsForTesting();
+  bits_.fetch_or(static_cast<uint64_t>(flag), std::memory_order_relaxed);
+}
+
+void HangWatchDeadline::ClearPersistentFlag(Flag flag) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  if (switch_bits_callback_for_testing_)
+    SwitchBitsForTesting();
+  bits_.fetch_and(~(static_cast<uint64_t>(flag)), std::memory_order_relaxed);
+}
+
+// static
+uint64_t HangWatchDeadline::ExtractFlags(uint64_t bits) {
+  return bits & kOnlyFlagsMask;
+}
+
+// static
+uint64_t HangWatchDeadline::ExtractDeadline(uint64_t bits) {
+  return bits & kOnlyDeadlineMask;
+}
+
+// static
+TimeTicks HangWatchDeadline::DeadlineFromBits(uint64_t bits) {
+  // |kOnlyDeadlineMask| has all the deadline bits set to 1 so is the largest
+  // representable value.
+  DCHECK(bits <= kOnlyDeadlineMask)
+      << "Flags bits are set. Remove them before returning deadline.";
+  static_assert(kOnlyDeadlineMask <= std::numeric_limits<int64_t>::max());
+  return TimeTicks::FromInternalValue(static_cast<int64_t>(bits));
+}
+
+bool HangWatchDeadline::IsFlagSet(Flag flag) const {
+  return bits_.load(std::memory_order_relaxed) & static_cast<uint64_t>(flag);
+}
+
+void HangWatchDeadline::SetSwitchBitsClosureForTesting(
+    RepeatingCallback<uint64_t(void)> closure) {
+  switch_bits_callback_for_testing_ = closure;
+}
+
+void HangWatchDeadline::ResetSwitchBitsClosureForTesting() {
+  DCHECK(switch_bits_callback_for_testing_);
+  switch_bits_callback_for_testing_.Reset();
+}
+
+uint64_t HangWatchDeadline::SwitchBitsForTesting() {
+  DCHECK(switch_bits_callback_for_testing_);
+
+  const uint64_t old_bits = bits_.load(std::memory_order_relaxed);
+  const uint64_t new_bits = switch_bits_callback_for_testing_.Run();
+  const uint64_t old_flags = ExtractFlags(old_bits);
+
+  const uint64_t switched_in_bits = old_flags | new_bits;
+  bits_.store(switched_in_bits, std::memory_order_relaxed);
+  return switched_in_bits;
+}
+
+HangWatchState::HangWatchState(HangWatcher::ThreadType thread_type)
+#if defined(STARBOARD)
+    : thread_type_(thread_type) {
+  EnsureThreadLocalKeyInited();
+  pthread_setspecific(s_thread_local_key, this);
+#else
+    : resetter_(&hang_watch_state, this, nullptr), thread_type_(thread_type) {
+#endif
+// TODO(crbug.com/1223033): Remove this once macOS uses system-wide ids.
+// On macOS the thread ids used by CrashPad are not the same as the ones
+// provided by PlatformThread. Make sure to use the same for correct
+// attribution.
+#if BUILDFLAG(IS_MAC)
+  uint64_t thread_id;
+  pthread_threadid_np(pthread_self(), &thread_id);
+  thread_id_ = checked_cast<PlatformThreadId>(thread_id);
+#else
+  thread_id_ = PlatformThread::CurrentId();
+#endif
+}
+
+HangWatchState::~HangWatchState() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  DCHECK_EQ(GetHangWatchStateForCurrentThread(), this);
+
+#if DCHECK_IS_ON()
+  // Destroying the HangWatchState should not be done if there are live
+  // WatchHangsInScopes.
+  DCHECK(!current_watch_hangs_in_scope_);
+#endif
+
+#if defined(STARBOARD)
+  EnsureThreadLocalKeyInited();
+  pthread_setspecific(s_thread_local_key, nullptr);
+#endif
+}
+
+// static
+std::unique_ptr<HangWatchState>
+HangWatchState::CreateHangWatchStateForCurrentThread(
+    HangWatcher::ThreadType thread_type) {
+  // Allocate a watch state object for this thread.
+  std::unique_ptr<HangWatchState> hang_state =
+      std::make_unique<HangWatchState>(thread_type);
+
+  // Setting the thread local worked.
+  DCHECK_EQ(GetHangWatchStateForCurrentThread(), hang_state.get());
+
+  // Transfer ownership to caller.
+  return hang_state;
+}
+
+TimeTicks HangWatchState::GetDeadline() const {
+  return deadline_.GetDeadline();
+}
+
+std::pair<uint64_t, TimeTicks> HangWatchState::GetFlagsAndDeadline() const {
+  return deadline_.GetFlagsAndDeadline();
+}
+
+void HangWatchState::SetDeadline(TimeTicks deadline) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  deadline_.SetDeadline(deadline);
+}
+
+bool HangWatchState::IsOverDeadline() const {
+  return TimeTicks::Now() > deadline_.GetDeadline();
+}
+
+void HangWatchState::SetIgnoreCurrentWatchHangsInScope() {
+  deadline_.SetIgnoreCurrentWatchHangsInScope();
+}
+
+void HangWatchState::UnsetIgnoreCurrentWatchHangsInScope() {
+  deadline_.UnsetIgnoreCurrentWatchHangsInScope();
+}
+
+bool HangWatchState::SetShouldBlockOnHang(uint64_t old_flags,
+                                          TimeTicks old_deadline) {
+  return deadline_.SetShouldBlockOnHang(old_flags, old_deadline);
+}
+
+bool HangWatchState::IsFlagSet(HangWatchDeadline::Flag flag) {
+  return deadline_.IsFlagSet(flag);
+}
+
+#if DCHECK_IS_ON()
+void HangWatchState::SetCurrentWatchHangsInScope(
+    WatchHangsInScope* current_hang_watch_scope_enable) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  current_watch_hangs_in_scope_ = current_hang_watch_scope_enable;
+}
+
+WatchHangsInScope* HangWatchState::GetCurrentWatchHangsInScope() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  return current_watch_hangs_in_scope_;
+}
+#endif
+
+HangWatchDeadline* HangWatchState::GetHangWatchDeadlineForTesting() {
+  return &deadline_;
+}
+
+void HangWatchState::IncrementNestingLevel() {
+  ++nesting_level_;
+}
+
+void HangWatchState::DecrementNestingLevel() {
+  --nesting_level_;
+}
+
+// static
+HangWatchState* HangWatchState::GetHangWatchStateForCurrentThread() {
+#if defined(STARBOARD)
+  return GetHangWatchState();
+#else
+  // Workaround false-positive MSAN use-of-uninitialized-value on
+  // thread_local storage for loaded libraries:
+  // https://github.com/google/sanitizers/issues/1265
+  MSAN_UNPOISON(&hang_watch_state, sizeof(internal::HangWatchState*));
+
+  return hang_watch_state;
+#endif
+}
+
+PlatformThreadId HangWatchState::GetThreadID() const {
+  return thread_id_;
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/threading/hang_watcher.h b/base/threading/hang_watcher.h
new file mode 100644
index 0000000..c74804a
--- /dev/null
+++ b/base/threading/hang_watcher.h
@@ -0,0 +1,688 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_HANG_WATCHER_H_
+#define BASE_THREADING_HANG_WATCHER_H_
+
+#include <atomic>
+#include <cstdint>
+#include <memory>
+#include <type_traits>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/auto_reset.h"
+#include "base/base_export.h"
+#include "base/bits.h"
+#include "base/compiler_specific.h"
+#include "base/dcheck_is_on.h"
+#include "base/debug/crash_logging.h"
+#include "base/functional/callback.h"
+#include "base/functional/callback_forward.h"
+#include "base/functional/callback_helpers.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ptr_exclusion.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/template_util.h"
+#include "base/thread_annotations.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+namespace base {
+class WatchHangsInScope;
+namespace internal {
+class HangWatchState;
+}  // namespace internal
+}  // namespace base
+
+namespace base {
+
+// Instantiate a WatchHangsInScope in a code scope to register to be
+// watched for hangs of more than |timeout| by the HangWatcher.
+//
+// Example usage:
+//
+//  void FooBar(){
+//    WatchHangsInScope scope(base::Seconds(5));
+//    DoWork();
+//  }
+//
+// If DoWork() takes more than 5s to run and the HangWatcher
+// inspects the thread state before Foobar returns a hang will be
+// reported.
+//
+// WatchHangsInScopes are typically meant to live on the stack. In some
+// cases it's necessary to keep a WatchHangsInScope instance as a class
+// member but special care is required when doing so as a WatchHangsInScope
+// that stays alive longer than intended will generate non-actionable hang
+// reports.
+class BASE_EXPORT [[maybe_unused, nodiscard]] WatchHangsInScope {
+ public:
+  // A good default value needs to be large enough to represent a significant
+  // hang and avoid noise while being small enough to not exclude too many
+  // hangs. The nature of the work that gets executed on the thread is also
+  // important. We can be much stricter when monitoring a UI thread compared to
+  // a ThreadPool thread for example.
+  static constexpr base::TimeDelta kDefaultHangWatchTime = base::Seconds(10);
+
+  // Constructing/destructing thread must be the same thread.
+  explicit WatchHangsInScope(TimeDelta timeout = kDefaultHangWatchTime);
+  ~WatchHangsInScope();
+
+  WatchHangsInScope(const WatchHangsInScope&) = delete;
+  WatchHangsInScope& operator=(const WatchHangsInScope&) = delete;
+
+ private:
+  // Will be true if the object actually set a deadline and false if not.
+  bool took_effect_ = true;
+
+  // This object should always be constructed and destructed on the same thread.
+  THREAD_CHECKER(thread_checker_);
+
+  // The deadline set by the previous WatchHangsInScope created on this
+  // thread. Stored so it can be restored when this WatchHangsInScope is
+  // destroyed.
+  TimeTicks previous_deadline_;
+
+  // Indicates whether the kIgnoreCurrentWatchHangsInScope flag must be set upon
+  // exiting this WatchHangsInScope if a call to InvalidateActiveExpectations()
+  // previously suspended hang watching.
+  bool set_hangs_ignored_on_exit_ = false;
+
+#if DCHECK_IS_ON()
+  // The previous WatchHangsInScope created on this thread.
+  // This field is not a raw_ptr<> because it was filtered by the rewriter for:
+  // #union
+  RAW_PTR_EXCLUSION WatchHangsInScope* previous_watch_hangs_in_scope_;
+#endif
+};
+
+// Monitors registered threads for hangs by inspecting their associated
+// HangWatchStates for deadline overruns. This happens at a regular interval on
+// a separate thread. Only one instance of HangWatcher can exist at a time
+// within a single process. This instance must outlive all monitored threads.
+class BASE_EXPORT HangWatcher : public DelegateSimpleThread::Delegate {
+ public:
+  // Describes the type of a process for logging purposes.
+  enum class ProcessType {
+    kUnknownProcess = 0,
+    kBrowserProcess = 1,
+    kGPUProcess = 2,
+    kRendererProcess = 3,
+    kUtilityProcess = 4,
+    kMax = kUtilityProcess
+  };
+
+  // Describes the type of a thread for logging purposes.
+  enum class ThreadType {
+    kIOThread = 0,
+    kMainThread = 1,
+    kThreadPoolThread = 2,
+    kMax = kThreadPoolThread
+  };
+
+  // Notes on lifetime:
+  //   1) The first invocation of the constructor will set the global instance
+  //      accessible through GetInstance().
+  //   2) In production HangWatcher is always purposefuly leaked.
+  //   3) If not leaked HangWatcher is always constructed and destructed from
+  //      the same thread.
+  //   4) There can never be more than one instance of HangWatcher at a time.
+  //      The class is not base::Singleton derived because it needs to destroyed
+  //      in tests.
+  HangWatcher();
+
+  // Clears the global instance for the class.
+  ~HangWatcher() override;
+
+  HangWatcher(const HangWatcher&) = delete;
+  HangWatcher& operator=(const HangWatcher&) = delete;
+
+  static void CreateHangWatcherInstance();
+
+  // Returns a non-owning pointer to the global HangWatcher instance.
+  static HangWatcher* GetInstance();
+
+  // Initializes HangWatcher. Must be called once on the main thread during
+  // startup while single-threaded.
+  static void InitializeOnMainThread(ProcessType process_type);
+
+  // Returns the values that were set through InitializeOnMainThread() to their
+  // default value. Used for testing since in prod initialization should happen
+  // only once.
+  static void UnitializeOnMainThreadForTesting();
+
+  // Thread safe functions to verify if hang watching is activated. If called
+  // before InitializeOnMainThread returns the default value which is false.
+  static bool IsEnabled();
+  static bool IsThreadPoolHangWatchingEnabled();
+  static bool IsIOThreadHangWatchingEnabled();
+
+  // Returns true if crash dump reporting is configured for any thread type.
+  static bool IsCrashReportingEnabled();
+
+  // Use to avoid capturing hangs for operations known to take unbounded time
+  // like waiting for user input. WatchHangsInScope objects created after this
+  // call will take effect. To resume watching for hangs create a new
+  // WatchHangsInScope after the unbounded operation finishes.
+  //
+  // Example usage:
+  //  {
+  //    WatchHangsInScope scope_1;
+  //    {
+  //      WatchHangsInScope scope_2;
+  //      InvalidateActiveExpectations();
+  //      WaitForUserInput();
+  //    }
+  //
+  //    WatchHangsInScope scope_4;
+  //  }
+  //
+  // WatchHangsInScope scope_5;
+  //
+  // In this example hang watching is disabled for WatchHangsInScopes 1 and 2
+  // since they were both active at the time of the invalidation.
+  // WatchHangsInScopes 4 and 5 are unaffected since they were created after the
+  // end of the WatchHangsInScope that was current at the time of invalidation.
+  //
+  static void InvalidateActiveExpectations();
+
+  // Sets up the calling thread to be monitored for threads. Returns a
+  // ScopedClosureRunner that unregisters the thread. This closure has to be
+  // called from the registered thread before it's joined. Returns a null
+  // closure in the case where there is no HangWatcher instance to register the
+  // thread with.
+  [[nodiscard]] static ScopedClosureRunner RegisterThread(
+      ThreadType thread_type);
+
+  // Choose a closure to be run at the end of each call to Monitor(). Use only
+  // for testing. Reentering the HangWatcher in the closure must be done with
+  // care. It should only be done through certain testing functions because
+  // deadlocks are possible.
+  void SetAfterMonitorClosureForTesting(base::RepeatingClosure closure);
+
+  // Choose a closure to be run instead of recording the hang. Used to test
+  // that certain conditions hold true at the time of recording. Use only
+  // for testing. Reentering the HangWatcher in the closure must be done with
+  // care. It should only be done through certain testing functions because
+  // deadlocks are possible.
+  void SetOnHangClosureForTesting(base::RepeatingClosure closure);
+
+  // Set a monitoring period other than the default. Use only for
+  // testing.
+  void SetMonitoringPeriodForTesting(base::TimeDelta period);
+
+  // Choose a callback to invoke right after waiting to monitor in Wait(). Use
+  // only for testing.
+  void SetAfterWaitCallbackForTesting(
+      RepeatingCallback<void(TimeTicks)> callback);
+
+  // Force the monitoring loop to resume and evaluate whether to continue.
+  // This can trigger a call to Monitor() or not depending on why the
+  // HangWatcher thread is sleeping. Use only for testing.
+  void SignalMonitorEventForTesting();
+
+  // Call to make sure no more monitoring takes place. The
+  // function is thread-safe and can be called at anytime but won't stop
+  // monitoring that is currently taking place. Use only for testing.
+  static void StopMonitoringForTesting();
+
+  // Replace the clock used when calculating time spent
+  // sleeping. Use only for testing.
+  void SetTickClockForTesting(const base::TickClock* tick_clock);
+
+  // Use to block until the hang is recorded. Allows the caller to halt
+  // execution so it does not overshoot the hang watch target and result in a
+  // non-actionable stack trace in the crash recorded.
+  void BlockIfCaptureInProgress();
+
+  // Begin executing the monitoring loop on the HangWatcher thread.
+  void Start();
+
+  // Returns the value of the crash key with the time since last system power
+  // resume.
+  std::string GetTimeSinceLastSystemPowerResumeCrashKeyValue() const;
+
+ private:
+  // See comment of ::RegisterThread() for details.
+  [[nodiscard]] ScopedClosureRunner RegisterThreadInternal(
+      ThreadType thread_type) LOCKS_EXCLUDED(watch_state_lock_);
+
+  // Use to assert that functions are called on the monitoring thread.
+  THREAD_CHECKER(hang_watcher_thread_checker_);
+
+  // Use to assert that functions are called on the constructing thread.
+  THREAD_CHECKER(constructing_thread_checker_);
+
+  // Invoked on memory pressure signal.
+  void OnMemoryPressure(
+      base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
+
+#if !BUILDFLAG(IS_NACL)
+  // Returns a ScopedCrashKeyString that sets the crash key with the time since
+  // last critical memory pressure signal.
+  [[nodiscard]] debug::ScopedCrashKeyString
+  GetTimeSinceLastCriticalMemoryPressureCrashKey();
+#endif
+
+  // Invoke base::debug::DumpWithoutCrashing() insuring that the stack frame
+  // right under it in the trace belongs to HangWatcher for easier attribution.
+  NOINLINE static void RecordHang();
+
+  using HangWatchStates =
+      std::vector<std::unique_ptr<internal::HangWatchState>>;
+
+  // Used to save a snapshots of the state of hang watching during capture.
+  // Only the state of hung threads is retained.
+  class BASE_EXPORT WatchStateSnapShot {
+   public:
+    struct WatchStateCopy {
+      base::TimeTicks deadline;
+      base::PlatformThreadId thread_id;
+    };
+
+    WatchStateSnapShot();
+    WatchStateSnapShot(const WatchStateSnapShot& other);
+    ~WatchStateSnapShot();
+
+    // Initialize the snapshot from provided data. |snapshot_time| can be
+    // different than now() to be coherent with other operations recently done
+    // on |watch_states|. |hung_watch_state_copies_| can be empty after
+    // initialization for a number of reasons:
+    // 1. If any deadline in |watch_states| is before
+    // |deadline_ignore_threshold|.
+    // 2. If some of the hung threads could not be marked as blocking on
+    // capture.
+    // 3. If none of the hung threads are of a type configured to trigger a
+    // crash dump.
+    //
+    // This function cannot be called more than once without an associated call
+    // to Clear().
+    void Init(const HangWatchStates& watch_states,
+              base::TimeTicks deadline_ignore_threshold);
+
+    // Reset the snapshot object to be reused. Can only be called after Init().
+    void Clear();
+
+    // Returns a string that contains the ids of the hung threads separated by a
+    // '|'. The size of the string is capped at debug::CrashKeySize::Size256. If
+    // no threads are hung returns an empty string. Can only be invoked if
+    // IsActionable(). Can only be called after Init().
+    std::string PrepareHungThreadListCrashKey() const;
+
+    // Return the highest deadline included in this snapshot. Can only be called
+    // if IsActionable(). Can only be called after Init().
+    base::TimeTicks GetHighestDeadline() const;
+
+    // Returns true if the snapshot can be used to record an actionable hang
+    // report and false if not. Can only be called after Init().
+    bool IsActionable() const;
+
+   private:
+    bool initialized_ = false;
+    std::vector<WatchStateCopy> hung_watch_state_copies_;
+  };
+
+  // Return a watch state snapshot taken Now() to be inspected in tests.
+  // NO_THREAD_SAFETY_ANALYSIS is needed because the analyzer can't figure out
+  // that calls to this function done from |on_hang_closure_| are properly
+  // locked.
+  WatchStateSnapShot GrabWatchStateSnapshotForTesting() const
+      NO_THREAD_SAFETY_ANALYSIS;
+
+  // Inspects the state of all registered threads to check if they are hung and
+  // invokes the appropriate closure if so.
+  void Monitor() LOCKS_EXCLUDED(watch_state_lock_);
+
+  // Record the hang crash dump and perform the necessary housekeeping before
+  // and after.
+  void DoDumpWithoutCrashing(const WatchStateSnapShot& watch_state_snapshot)
+      EXCLUSIVE_LOCKS_REQUIRED(watch_state_lock_) LOCKS_EXCLUDED(capture_lock_);
+
+  // Stop all monitoring and join the HangWatcher thread.
+  void Stop();
+
+  // Wait until it's time to monitor.
+  void Wait();
+
+  // Run the loop that periodically monitors the registered thread at a
+  // set time interval.
+  void Run() override;
+
+  base::TimeDelta monitor_period_;
+
+  // Use to make the HangWatcher thread wake or sleep to schedule the
+  // appropriate monitoring frequency.
+  WaitableEvent should_monitor_;
+
+  bool IsWatchListEmpty() LOCKS_EXCLUDED(watch_state_lock_);
+
+  // Stops hang watching on the calling thread by removing the entry from the
+  // watch list.
+  void UnregisterThread() LOCKS_EXCLUDED(watch_state_lock_);
+
+  Lock watch_state_lock_;
+
+  std::vector<std::unique_ptr<internal::HangWatchState>> watch_states_
+      GUARDED_BY(watch_state_lock_);
+
+  // Snapshot to be reused across hang captures. The point of keeping it
+  // around is reducing allocations during capture.
+  WatchStateSnapShot watch_state_snapshot_
+      GUARDED_BY_CONTEXT(hang_watcher_thread_checker_);
+
+  base::DelegateSimpleThread thread_;
+
+  RepeatingClosure after_monitor_closure_for_testing_;
+  RepeatingClosure on_hang_closure_for_testing_;
+  RepeatingCallback<void(TimeTicks)> after_wait_callback_;
+
+  base::Lock capture_lock_ ACQUIRED_AFTER(watch_state_lock_);
+  std::atomic<bool> capture_in_progress_{false};
+
+  raw_ptr<const base::TickClock> tick_clock_;
+
+  // Registration to receive memory pressure signals.
+  base::MemoryPressureListener memory_pressure_listener_;
+
+  // The last time at which a critical memory pressure signal was received, or
+  // null if no signal was ever received. Atomic because it's set and read from
+  // different threads.
+  std::atomic<base::TimeTicks> last_critical_memory_pressure_{
+      base::TimeTicks()};
+
+  // The time after which all deadlines in |watch_states_| need to be for a hang
+  // to be reported.
+  base::TimeTicks deadline_ignore_threshold_;
+
+  FRIEND_TEST_ALL_PREFIXES(HangWatcherTest, NestedScopes);
+  FRIEND_TEST_ALL_PREFIXES(HangWatcherSnapshotTest, HungThreadIDs);
+  FRIEND_TEST_ALL_PREFIXES(HangWatcherSnapshotTest, NonActionableReport);
+};
+
+// Classes here are exposed in the header only for testing. They are not
+// intended to be used outside of base.
+namespace internal {
+
+// Threadsafe class that manages a deadline of type TimeTicks alongside hang
+// watching specific flags. The flags are stored in the higher bits of the
+// underlying TimeTicks deadline. This enables setting the flags on thread T1 in
+// a way that's resilient to concurrent deadline or flag changes from thread T2.
+// Flags can be queried separately from the deadline and users of this class
+// should not have to care about them when doing so.
+class BASE_EXPORT HangWatchDeadline {
+ public:
+  // Masks to set flags by flipping a single bit in the TimeTicks value. There
+  // are two types of flags. Persistent flags remain set through a deadline
+  // change and non-persistent flags are cleared when the deadline changes.
+  enum class Flag : uint64_t {
+    // Minimum value for validation purposes. Not currently used.
+    kMinValue = bits::LeftmostBit<uint64_t>() >> 7,
+    // Persistent because if hang detection is disabled on a thread it should
+    // be re-enabled manually.
+    kIgnoreCurrentWatchHangsInScope = bits::LeftmostBit<uint64_t>() >> 1,
+    // Non-persistent because a new value means a new WatchHangsInScope started
+    // after the beginning of capture. It can't be implicated in the hang so we
+    // don't want it to block.
+    kShouldBlockOnHang = bits::LeftmostBit<uint64_t>() >> 0,
+    kMaxValue = kShouldBlockOnHang
+  };
+
+  HangWatchDeadline();
+  ~HangWatchDeadline();
+
+  // HangWatchDeadline should never be copied. To keep a copy of the deadline or
+  // flags use the appropriate accessors.
+  HangWatchDeadline(const HangWatchDeadline&) = delete;
+  HangWatchDeadline& operator=(const HangWatchDeadline&) = delete;
+
+  // Returns the underlying TimeTicks deadline. WARNING: The deadline and flags
+  // can change concurrently. To inspect both, use GetFlagsAndDeadline() to get
+  // a coherent race-free view of the state.
+  TimeTicks GetDeadline() const;
+
+  // Returns a mask containing the flags and the deadline as a pair. Use to
+  // inspect the flags and deadline and then optionally call
+  // SetShouldBlockOnHang() .
+  std::pair<uint64_t, TimeTicks> GetFlagsAndDeadline() const;
+
+  // Returns true if the flag is set and false if not. WARNING: The deadline and
+  // flags can change concurrently. To inspect both, use GetFlagsAndDeadline()
+  // to get a coherent race-free view of the state.
+  bool IsFlagSet(Flag flag) const;
+
+  // Returns true if a flag is set in |flags| and false if not. Use to inspect
+  // the flags mask returned by GetFlagsAndDeadline(). WARNING: The deadline and
+  // flags can change concurrently. If you need to inspect both you need to use
+  // GetFlagsAndDeadline() to get a coherent race-free view of the state.
+  static bool IsFlagSet(Flag flag, uint64_t flags);
+
+  // Replace the deadline value. |new_value| needs to be within [0,
+  // Max()]. This function can never fail.
+  void SetDeadline(TimeTicks new_value);
+
+  // Sets the kShouldBlockOnHang flag and returns true if current flags and
+  // deadline are still equal to |old_flags| and  |old_deadline|. Otherwise does
+  // not set the flag and returns false.
+  bool SetShouldBlockOnHang(uint64_t old_flags, TimeTicks old_deadline);
+
+  // Sets the kIgnoreCurrentWatchHangsInScope flag.
+  void SetIgnoreCurrentWatchHangsInScope();
+
+  // Clears the kIgnoreCurrentWatchHangsInScope flag.
+  void UnsetIgnoreCurrentWatchHangsInScope();
+
+  // Use to simulate the value of |bits_| changing between the calling a
+  // Set* function and the moment of atomically switching the values. The
+  // callback should return a value containing the desired flags and deadline
+  // bits. The flags that are already set will be preserved upon applying. Use
+  // only for testing.
+  void SetSwitchBitsClosureForTesting(
+      RepeatingCallback<uint64_t(void)> closure);
+
+  // Remove the deadline modification callback for when testing is done. Use
+  // only for testing.
+  void ResetSwitchBitsClosureForTesting();
+
+ private:
+  using TimeTicksInternalRepresentation =
+      std::invoke_result<decltype(&TimeTicks::ToInternalValue),
+                         TimeTicks>::type;
+  static_assert(std::is_same<TimeTicksInternalRepresentation, int64_t>::value,
+                "Bit manipulations made by HangWatchDeadline need to be"
+                "adapted if internal representation of TimeTicks changes.");
+
+  // Replace the bits with the ones provided through the callback. Preserves the
+  // flags that were already set. Returns the switched in bits. Only call if
+  // |switch_bits_callback_for_testing_| is installed.
+  uint64_t SwitchBitsForTesting();
+
+  // Atomically sets persitent flag |flag|. Cannot fail.
+  void SetPersistentFlag(Flag flag);
+
+  // Atomically clears persitent flag |flag|. Cannot fail.
+  void ClearPersistentFlag(Flag flag);
+
+  // Converts bits to TimeTicks with some sanity checks. Use to return the
+  // deadline outside of this class.
+  static TimeTicks DeadlineFromBits(uint64_t bits);
+
+  // Returns the largest representable deadline.
+  static TimeTicks Max();
+
+  // Extract the flag bits from |bits|.
+  static uint64_t ExtractFlags(uint64_t bits);
+
+  // Extract the deadline bits from |bits|.
+  static uint64_t ExtractDeadline(uint64_t bits);
+
+  // BitsType is uint64_t. This type is chosen for having
+  // std::atomic<BitsType>{}.is_lock_free() true on many platforms and having no
+  // undefined behaviors with regards to bit shift operations. Throughout this
+  // class this is the only type that is used to store, retrieve and manipulate
+  // the bits. When returning a TimeTicks value outside this class it's
+  // necessary to run the proper checks to insure correctness of the conversion
+  // that has to go through int_64t. (See DeadlineFromBits()).
+  using BitsType = uint64_t;
+  static_assert(std::is_same<std::underlying_type<Flag>::type, BitsType>::value,
+                "Flag should have the same underlying type as bits_ to "
+                "simplify thinking about bit operations");
+
+  // Holds the bits of both the flags and the TimeTicks deadline.
+  // TimeTicks values represent a count of microseconds since boot which may or
+  // may not include suspend time depending on the platform. Using the seven
+  // highest order bits and the sign bit to store flags still enables the
+  // storing of TimeTicks values that can represent up to ~1142 years of uptime
+  // in the remaining bits. Should never be directly accessed from outside the
+  // class. Starts out at Max() to provide a base-line deadline that will not be
+  // reached during normal execution.
+  //
+  // Binary format: 0xFFDDDDDDDDDDDDDDDD
+  // F = Flags
+  // D = Deadline
+  std::atomic<BitsType> bits_{static_cast<uint64_t>(Max().ToInternalValue())};
+
+  RepeatingCallback<uint64_t(void)> switch_bits_callback_for_testing_;
+
+  THREAD_CHECKER(thread_checker_);
+
+  FRIEND_TEST_ALL_PREFIXES(HangWatchDeadlineTest, BitsPreservedThroughExtract);
+};
+
+// Contains the information necessary for hang watching a specific
+// thread. Instances of this class are accessed concurrently by the associated
+// thread and the HangWatcher. The HangWatcher owns instances of this
+// class and outside of it they are accessed through
+// GetHangWatchStateForCurrentThread().
+class BASE_EXPORT HangWatchState {
+ public:
+  // |thread_type| is the type of thread the watch state will
+  // be associated with. It's the responsibility of the creating
+  // code to choose the correct type.
+  explicit HangWatchState(HangWatcher::ThreadType thread_type);
+  ~HangWatchState();
+
+  HangWatchState(const HangWatchState&) = delete;
+  HangWatchState& operator=(const HangWatchState&) = delete;
+
+  // Allocates a new state object bound to the calling thread and returns an
+  // owning pointer to it.
+  static std::unique_ptr<HangWatchState> CreateHangWatchStateForCurrentThread(
+      HangWatcher::ThreadType thread_type);
+
+  // Retrieves the hang watch state associated with the calling thread.
+  // Returns nullptr if no HangWatchState exists for the current thread (see
+  // CreateHangWatchStateForCurrentThread()).
+  static HangWatchState* GetHangWatchStateForCurrentThread();
+
+  // Returns the current deadline. Use this function if you need to
+  // store the value. To test if the deadline has expired use IsOverDeadline().
+  // WARNING: The deadline and flags can change concurrently. If you need to
+  // inspect both you need to use GetFlagsAndDeadline() to get a coherent
+  // race-free view of the state.
+  TimeTicks GetDeadline() const;
+
+  // Returns a mask containing the hang watching flags and the value as a pair.
+  // Use to inspect the flags and deadline and optionally call
+  // SetShouldBlockOnHang(flags, deadline).
+  std::pair<uint64_t, TimeTicks> GetFlagsAndDeadline() const;
+
+  // Sets the deadline to a new value.
+  void SetDeadline(TimeTicks deadline);
+
+  // Mark this thread as ignored for hang watching. This means existing
+  // WatchHangsInScope will not trigger hangs.
+  void SetIgnoreCurrentWatchHangsInScope();
+
+  // Reactivate hang watching on this thread. Should be called when all
+  // WatchHangsInScope instances that were ignored have completed.
+  void UnsetIgnoreCurrentWatchHangsInScope();
+
+  // Mark the current state as having to block in its destruction until hang
+  // capture completes.
+  bool SetShouldBlockOnHang(uint64_t old_flags, TimeTicks old_deadline);
+
+  // Returns true if |flag| is set and false if not. WARNING: The deadline and
+  // flags can change concurrently. If you need to inspect both you need to use
+  // GetFlagsAndDeadline() to get a coherent race-free view of the state.
+  bool IsFlagSet(HangWatchDeadline::Flag flag);
+
+  // Tests whether the associated thread's execution has gone over the deadline.
+  bool IsOverDeadline() const;
+
+#if DCHECK_IS_ON()
+  // Saves the supplied WatchHangsInScope as the currently active
+  // WatchHangsInScope.
+  void SetCurrentWatchHangsInScope(WatchHangsInScope* scope);
+
+  // Retrieve the currently active scope.
+  WatchHangsInScope* GetCurrentWatchHangsInScope();
+#endif
+
+  PlatformThreadId GetThreadID() const;
+
+  // Retrieve the current hang watch deadline directly. For testing only.
+  HangWatchDeadline* GetHangWatchDeadlineForTesting();
+
+  // Returns the current nesting level.
+  int nesting_level() { return nesting_level_; }
+
+  // Increase the nesting level by 1;
+  void IncrementNestingLevel();
+
+  // Reduce the nesting level by 1;
+  void DecrementNestingLevel();
+
+  // Returns the type of the thread under watch.
+  HangWatcher::ThreadType thread_type() const { return thread_type_; }
+
+ private:
+  // The thread that creates the instance should be the class that updates
+  // the deadline.
+  THREAD_CHECKER(thread_checker_);
+
+#if !defined(STARBOARD)
+  const AutoReset<HangWatchState*> resetter_;
+#endif
+
+  // If the deadline fails to be updated before TimeTicks::Now() ever
+  // reaches the value contained in it this constistutes a hang.
+  HangWatchDeadline deadline_;
+
+  // A unique ID of the thread under watch. Used for logging in crash reports
+  // only.
+  PlatformThreadId thread_id_;
+
+  // Number of active HangWatchScopeEnables on this thread.
+  int nesting_level_ = 0;
+
+  // The type of the thread under watch.
+  const HangWatcher::ThreadType thread_type_;
+
+#if DCHECK_IS_ON()
+  // Used to keep track of the current WatchHangsInScope and detect improper
+  // usage. Scopes should always be destructed in reverse order from the one
+  // they were constructed in. Example of improper use:
+  //
+  // {
+  //   std::unique_ptr<Scope> scope = std::make_unique<Scope>(...);
+  //   Scope other_scope;
+  //   |scope| gets deallocated first, violating reverse destruction order.
+  //   scope.reset();
+  // }
+  raw_ptr<WatchHangsInScope> current_watch_hangs_in_scope_{nullptr};
+#endif
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_THREADING_HANG_WATCHER_H_
diff --git a/base/threading/hang_watcher_unittest.cc b/base/threading/hang_watcher_unittest.cc
new file mode 100644
index 0000000..badffab
--- /dev/null
+++ b/base/threading/hang_watcher_unittest.cc
@@ -0,0 +1,1293 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/hang_watcher.h"
+#include <atomic>
+#include <memory>
+
+#include "base/barrier_closure.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/functional/callback_helpers.h"
+#include "base/memory/raw_ptr.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/bind.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/power_monitor_test.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/threading_features.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+using testing::ElementsAre;
+using testing::IsEmpty;
+
+namespace base {
+namespace {
+
+// Use with a FeatureList to activate crash dumping for threads marked as
+// threadpool threads.
+const std::vector<base::test::FeatureRefAndParams> kFeatureAndParams{
+    {base::kEnableHangWatcher, {{"ui_thread_log_level", "2"}}}};
+
+// Use this value to mark things very far off in the future. Adding this
+// to TimeTicks::Now() gives a point that will never be reached during the
+// normal execution of a test.
+constexpr TimeDelta kVeryLongDelta{base::Days(365)};
+
+// A relatively small time delta to ensure ordering of hung threads list.
+constexpr TimeDelta kSmallCPUQuantum{base::Milliseconds(1)};
+
+constexpr uint64_t kArbitraryDeadline = 0x0000C0FFEEC0FFEEu;
+constexpr uint64_t kAllOnes = 0xFFFFFFFFFFFFFFFFu;
+constexpr uint64_t kAllZeros = 0x0000000000000000u;
+constexpr uint64_t kOnesThenZeroes = 0xAAAAAAAAAAAAAAAAu;
+constexpr uint64_t kZeroesThenOnes = 0x5555555555555555u;
+
+// Waits on provided WaitableEvent before executing and signals when done.
+class BlockingThread : public DelegateSimpleThread::Delegate {
+ public:
+  explicit BlockingThread(base::WaitableEvent* unblock_thread,
+                          base::TimeDelta timeout)
+      : thread_(this, "BlockingThread"),
+        unblock_thread_(unblock_thread),
+        timeout_(timeout) {}
+
+  ~BlockingThread() override = default;
+
+  void Run() override {
+    // (Un)Register the thread here instead of in ctor/dtor so that the action
+    // happens on the right thread.
+    base::ScopedClosureRunner unregister_closure =
+        base::HangWatcher::RegisterThread(
+            base::HangWatcher::ThreadType::kMainThread);
+
+    WatchHangsInScope scope(timeout_);
+    wait_until_entered_scope_.Signal();
+
+    unblock_thread_->Wait();
+    run_event_.Signal();
+  }
+
+  bool IsDone() { return run_event_.IsSignaled(); }
+
+  void StartAndWaitForScopeEntered() {
+    thread_.Start();
+    // Block until this thread registered itself for hang watching and has
+    // entered a WatchHangsInScope.
+    wait_until_entered_scope_.Wait();
+  }
+
+  void Join() { thread_.Join(); }
+
+  PlatformThreadId GetId() { return thread_.tid(); }
+
+ private:
+  base::DelegateSimpleThread thread_;
+
+  // Will be signaled once the thread is properly registered for watching and
+  // the WatchHangsInScope has been entered.
+  WaitableEvent wait_until_entered_scope_;
+
+  // Will be signaled once ThreadMain has run.
+  WaitableEvent run_event_;
+
+  const raw_ptr<base::WaitableEvent> unblock_thread_;
+
+  base::TimeDelta timeout_;
+};
+
+class HangWatcherTest : public testing::Test {
+ public:
+  const base::TimeDelta kTimeout = base::Seconds(10);
+  const base::TimeDelta kHangTime = kTimeout + base::Seconds(1);
+
+  HangWatcherTest() {
+    feature_list_.InitWithFeaturesAndParameters(kFeatureAndParams, {});
+    hang_watcher_.InitializeOnMainThread(
+        HangWatcher::ProcessType::kBrowserProcess);
+
+    hang_watcher_.SetAfterMonitorClosureForTesting(base::BindRepeating(
+        &WaitableEvent::Signal, base::Unretained(&monitor_event_)));
+
+    hang_watcher_.SetOnHangClosureForTesting(base::BindRepeating(
+        &WaitableEvent::Signal, base::Unretained(&hang_event_)));
+
+    // We're not testing the monitoring loop behavior in this test so we want to
+    // trigger monitoring manually.
+    hang_watcher_.SetMonitoringPeriodForTesting(kVeryLongDelta);
+
+    // Start the monitoring loop.
+    hang_watcher_.Start();
+  }
+
+  void TearDown() override { hang_watcher_.UnitializeOnMainThreadForTesting(); }
+
+  HangWatcherTest(const HangWatcherTest& other) = delete;
+  HangWatcherTest& operator=(const HangWatcherTest& other) = delete;
+
+ protected:
+  // Used to wait for monitoring. Will be signaled by the HangWatcher thread and
+  // so needs to outlive it.
+  WaitableEvent monitor_event_;
+
+  // Signaled from the HangWatcher thread when a hang is detected. Needs to
+  // outlive the HangWatcher thread.
+  WaitableEvent hang_event_;
+
+  base::test::ScopedFeatureList feature_list_;
+
+  // Used exclusively for MOCK_TIME. No tasks will be run on the environment.
+  // Single threaded to avoid ThreadPool WorkerThreads registering.
+  test::SingleThreadTaskEnvironment task_environment_{
+      test::TaskEnvironment::TimeSource::MOCK_TIME};
+
+  // This must be declared last (after task_environment_, for example) so that
+  // the watcher thread is joined before objects like the mock timer are
+  // destroyed, causing racy crashes.
+  HangWatcher hang_watcher_;
+};
+
+class HangWatcherBlockingThreadTest : public HangWatcherTest {
+ public:
+  HangWatcherBlockingThreadTest() : thread_(&unblock_thread_, kTimeout) {}
+
+  HangWatcherBlockingThreadTest(const HangWatcherBlockingThreadTest& other) =
+      delete;
+  HangWatcherBlockingThreadTest& operator=(
+      const HangWatcherBlockingThreadTest& other) = delete;
+
+ protected:
+  void JoinThread() {
+    unblock_thread_.Signal();
+
+    // Thread is joinable since we signaled |unblock_thread_|.
+    thread_.Join();
+
+    // If thread is done then it signaled.
+    ASSERT_TRUE(thread_.IsDone());
+  }
+
+  void StartBlockedThread() {
+    // Thread has not run yet.
+    ASSERT_FALSE(thread_.IsDone());
+
+    // Start the thread. It will block since |unblock_thread_| was not
+    // signaled yet.
+    thread_.StartAndWaitForScopeEntered();
+
+    // Thread registration triggered a call to HangWatcher::Monitor() which
+    // signaled |monitor_event_|. Reset it so it's ready for waiting later on.
+    monitor_event_.Reset();
+  }
+
+  void MonitorHangs() {
+    // HangWatcher::Monitor() should not be set which would mean a call to
+    // HangWatcher::Monitor() happened and was unacounted for.
+    // ASSERT_FALSE(monitor_event_.IsSignaled());
+
+    // Trigger a monitoring on HangWatcher thread and verify results.
+    hang_watcher_.SignalMonitorEventForTesting();
+    monitor_event_.Wait();
+  }
+
+  // Used to unblock the monitored thread. Signaled from the test main thread.
+  WaitableEvent unblock_thread_;
+
+  BlockingThread thread_;
+};
+}  // namespace
+
+TEST_F(HangWatcherTest, InvalidatingExpectationsPreventsCapture) {
+  // Register the main test thread for hang watching.
+  auto unregister_thread_closure =
+      HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
+
+  // Create a hang.
+  WatchHangsInScope expires_instantly(base::TimeDelta{});
+  task_environment_.FastForwardBy(kHangTime);
+
+  // de-activate hang watching,
+  base::HangWatcher::InvalidateActiveExpectations();
+
+  // Trigger a monitoring on HangWatcher thread and verify results.
+  // Hang is not detected.
+  hang_watcher_.SignalMonitorEventForTesting();
+  monitor_event_.Wait();
+  ASSERT_FALSE(hang_event_.IsSignaled());
+}
+
+TEST_F(HangWatcherTest, MultipleInvalidateExpectationsDoNotCancelOut) {
+  // Register the main test thread for hang watching.
+  auto unregister_thread_closure =
+      HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
+
+  // Create a hang.
+  WatchHangsInScope expires_instantly(base::TimeDelta{});
+  task_environment_.FastForwardBy(kHangTime);
+
+  // de-activate hang watching,
+  base::HangWatcher::InvalidateActiveExpectations();
+
+  // Redundently de-activate hang watching.
+  base::HangWatcher::InvalidateActiveExpectations();
+
+  // Trigger a monitoring on HangWatcher thread and verify results.
+  // Hang is not detected.
+  hang_watcher_.SignalMonitorEventForTesting();
+  monitor_event_.Wait();
+  ASSERT_FALSE(hang_event_.IsSignaled());
+}
+
+TEST_F(HangWatcherTest, NewInnerWatchHangsInScopeAfterInvalidationDetectsHang) {
+  // Register the main test thread for hang watching.
+  auto unregister_thread_closure =
+      HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
+
+  WatchHangsInScope expires_instantly(base::TimeDelta{});
+  task_environment_.FastForwardBy(kHangTime);
+
+  // De-activate hang watching.
+  base::HangWatcher::InvalidateActiveExpectations();
+
+  {
+    WatchHangsInScope also_expires_instantly(base::TimeDelta{});
+    task_environment_.FastForwardBy(kHangTime);
+
+    // Trigger a monitoring on HangWatcher thread and verify results.
+    hang_watcher_.SignalMonitorEventForTesting();
+    monitor_event_.Wait();
+
+    // Hang is detected since the new WatchHangsInScope temporarily
+    // re-activated hang_watching.
+    monitor_event_.Wait();
+    ASSERT_TRUE(hang_event_.IsSignaled());
+  }
+
+  // Reset to attempt capture again.
+  monitor_event_.Reset();
+  hang_event_.Reset();
+
+  // Trigger a monitoring on HangWatcher thread and verify results.
+  hang_watcher_.SignalMonitorEventForTesting();
+  monitor_event_.Wait();
+
+  // Hang is not detected since execution is back to being covered by
+  // |expires_instantly| for which expectations were invalidated.
+  monitor_event_.Wait();
+  ASSERT_FALSE(hang_event_.IsSignaled());
+}
+
+TEST_F(HangWatcherTest,
+       NewSeparateWatchHangsInScopeAfterInvalidationDetectsHang) {
+  // Register the main test thread for hang watching.
+  auto unregister_thread_closure =
+      HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
+
+  {
+    WatchHangsInScope expires_instantly(base::TimeDelta{});
+    task_environment_.FastForwardBy(kHangTime);
+
+    // De-activate hang watching.
+    base::HangWatcher::InvalidateActiveExpectations();
+  }
+
+  WatchHangsInScope also_expires_instantly(base::TimeDelta{});
+  task_environment_.FastForwardBy(kHangTime);
+
+  // Trigger a monitoring on HangWatcher thread and verify results.
+  hang_watcher_.SignalMonitorEventForTesting();
+  monitor_event_.Wait();
+
+  // Hang is detected since the new WatchHangsInScope did not have its
+  // expectations invalidated.
+  monitor_event_.Wait();
+  ASSERT_TRUE(hang_event_.IsSignaled());
+}
+
+// Test that invalidating expectations from inner WatchHangsInScope will also
+// prevent hang detection in outer scopes.
+TEST_F(HangWatcherTest, ScopeDisabledObjectInnerScope) {
+  // Register the main test thread for hang watching.
+  auto unregister_thread_closure =
+      HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
+
+  // Start a WatchHangsInScope that expires right away. Then advance
+  // time to make sure no hang is detected.
+  WatchHangsInScope expires_instantly(base::TimeDelta{});
+  task_environment_.FastForwardBy(kHangTime);
+  {
+    WatchHangsInScope also_expires_instantly(base::TimeDelta{});
+
+    // De-activate hang watching.
+    base::HangWatcher::InvalidateActiveExpectations();
+    task_environment_.FastForwardBy(kHangTime);
+  }
+
+  // Trigger a monitoring on HangWatcher thread and verify results.
+  hang_watcher_.SignalMonitorEventForTesting();
+  monitor_event_.Wait();
+
+  // Hang is ignored since it concerns a scope for which one of the inner scope
+  // was ignored.
+  ASSERT_FALSE(hang_event_.IsSignaled());
+}
+
+TEST_F(HangWatcherTest, NewScopeAfterDisabling) {
+  // Register the main test thread for hang watching.
+  auto unregister_thread_closure =
+      HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
+
+  // Start a WatchHangsInScope that expires right away. Then advance
+  // time to make sure no hang is detected.
+  WatchHangsInScope expires_instantly(base::TimeDelta{});
+  task_environment_.FastForwardBy(kHangTime);
+  {
+    WatchHangsInScope also_expires_instantly(base::TimeDelta{});
+
+    // De-activate hang watching.
+    base::HangWatcher::InvalidateActiveExpectations();
+    task_environment_.FastForwardBy(kHangTime);
+  }
+
+  // New scope for which expecations are never invalidated.
+  WatchHangsInScope also_expires_instantly(base::TimeDelta{});
+  task_environment_.FastForwardBy(kHangTime);
+
+  // Trigger a monitoring on HangWatcher thread and verify results.
+  hang_watcher_.SignalMonitorEventForTesting();
+  monitor_event_.Wait();
+
+  // Hang is detected because it's unrelated to the hangs that were disabled.
+  ASSERT_TRUE(hang_event_.IsSignaled());
+}
+
+TEST_F(HangWatcherTest, NestedScopes) {
+  // Create a state object for the test thread since this test is single
+  // threaded.
+  auto current_hang_watch_state =
+      base::internal::HangWatchState::CreateHangWatchStateForCurrentThread(
+          HangWatcher::ThreadType::kMainThread);
+
+  ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
+  base::TimeTicks original_deadline = current_hang_watch_state->GetDeadline();
+
+  constexpr base::TimeDelta kFirstTimeout(base::Milliseconds(500));
+  base::TimeTicks first_deadline = base::TimeTicks::Now() + kFirstTimeout;
+
+  constexpr base::TimeDelta kSecondTimeout(base::Milliseconds(250));
+  base::TimeTicks second_deadline = base::TimeTicks::Now() + kSecondTimeout;
+
+  // At this point we have not set any timeouts.
+  {
+    // Create a first timeout which is more restrictive than the default.
+    WatchHangsInScope first_scope(kFirstTimeout);
+
+    // We are on mock time. There is no time advancement and as such no hangs.
+    ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
+    ASSERT_EQ(current_hang_watch_state->GetDeadline(), first_deadline);
+    {
+      // Set a yet more restrictive deadline. Still no hang.
+      WatchHangsInScope second_scope(kSecondTimeout);
+      ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
+      ASSERT_EQ(current_hang_watch_state->GetDeadline(), second_deadline);
+    }
+    // First deadline we set should be restored.
+    ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
+    ASSERT_EQ(current_hang_watch_state->GetDeadline(), first_deadline);
+  }
+
+  // Original deadline should now be restored.
+  ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
+  ASSERT_EQ(current_hang_watch_state->GetDeadline(), original_deadline);
+}
+
+TEST_F(HangWatcherBlockingThreadTest, HistogramsLoggedOnHang) {
+  base::HistogramTester histogram_tester;
+  StartBlockedThread();
+
+  // Simulate hang.
+  task_environment_.FastForwardBy(kHangTime);
+
+  // First monitoring catches the hang and emits the histogram.
+  MonitorHangs();
+  EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
+                                             "BrowserProcess.UIThread"),
+              ElementsAre(base::Bucket(true, /*count=*/1)));
+
+  // Reset to attempt capture again.
+  hang_event_.Reset();
+  monitor_event_.Reset();
+
+  // Hang is logged again even if it would not trigger a crash dump.
+  MonitorHangs();
+  EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
+                                             "BrowserProcess.UIThread"),
+              ElementsAre(base::Bucket(true, /*count=*/2)));
+
+  // Thread types that are not monitored should not get any samples.
+  EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
+                                             "BrowserProcess.IOThread"),
+              IsEmpty());
+  JoinThread();
+}
+
+TEST_F(HangWatcherBlockingThreadTest, HistogramsLoggedWithoutHangs) {
+  base::HistogramTester histogram_tester;
+  StartBlockedThread();
+
+  // No hang to catch so nothing is recorded.
+  MonitorHangs();
+  ASSERT_FALSE(hang_event_.IsSignaled());
+
+  // A thread of type ThreadForTesting was monitored but didn't hang. This is
+  // logged.
+  EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
+                                             "BrowserProcess.UIThread"),
+              ElementsAre(base::Bucket(false, /*count=*/1)));
+
+  // Thread types that are not monitored should not get any samples.
+  EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
+                                             "BrowserProcess.IOThread"),
+              IsEmpty());
+  JoinThread();
+}
+
+TEST_F(HangWatcherBlockingThreadTest, Hang) {
+  StartBlockedThread();
+
+  // Simulate hang.
+  task_environment_.FastForwardBy(kHangTime);
+
+  // First monitoring catches and records the hang.
+  MonitorHangs();
+  ASSERT_TRUE(hang_event_.IsSignaled());
+
+  JoinThread();
+}
+
+TEST_F(HangWatcherBlockingThreadTest, HangAlreadyRecorded) {
+  StartBlockedThread();
+
+  // Simulate hang.
+  task_environment_.FastForwardBy(kHangTime);
+
+  // First monitoring catches and records the hang.
+  MonitorHangs();
+  ASSERT_TRUE(hang_event_.IsSignaled());
+
+  // Reset to attempt capture again.
+  hang_event_.Reset();
+  monitor_event_.Reset();
+
+  // Second monitoring does not record because a hang that was already recorded
+  // is still live.
+  MonitorHangs();
+  ASSERT_FALSE(hang_event_.IsSignaled());
+
+  JoinThread();
+}
+
+TEST_F(HangWatcherBlockingThreadTest, NoHang) {
+  StartBlockedThread();
+
+  // No hang to catch so nothing is recorded.
+  MonitorHangs();
+  ASSERT_FALSE(hang_event_.IsSignaled());
+
+  JoinThread();
+}
+
+namespace {
+class HangWatcherSnapshotTest : public testing::Test {
+ public:
+  void SetUp() override {
+    feature_list_.InitWithFeaturesAndParameters(kFeatureAndParams, {});
+    hang_watcher_.InitializeOnMainThread(
+        HangWatcher::ProcessType::kBrowserProcess);
+
+    // The monitoring loop behavior is not verified in this test so we want to
+    // trigger monitoring manually.
+    hang_watcher_.SetMonitoringPeriodForTesting(kVeryLongDelta);
+  }
+
+  void TearDown() override { hang_watcher_.UnitializeOnMainThreadForTesting(); }
+
+  HangWatcherSnapshotTest() = default;
+  HangWatcherSnapshotTest(const HangWatcherSnapshotTest& other) = delete;
+  HangWatcherSnapshotTest& operator=(const HangWatcherSnapshotTest& other) =
+      delete;
+
+ protected:
+  void TriggerMonitorAndWaitForCompletion() {
+    monitor_event_.Reset();
+    hang_watcher_.SignalMonitorEventForTesting();
+    monitor_event_.Wait();
+  }
+
+  // Verify that a capture takes place and that at the time of the capture the
+  // list of hung thread ids is correct.
+  void TestIDList(const std::string& id_list) {
+    list_of_hung_thread_ids_during_capture_ = id_list;
+    task_environment_.AdvanceClock(kSmallCPUQuantum);
+    TriggerMonitorAndWaitForCompletion();
+    ASSERT_EQ(++reference_capture_count_, hang_capture_count_);
+  }
+
+  // Verify that even if hang monitoring takes place no hangs are detected.
+  void ExpectNoCapture() {
+    int old_capture_count = hang_capture_count_;
+    task_environment_.AdvanceClock(kSmallCPUQuantum);
+    TriggerMonitorAndWaitForCompletion();
+    ASSERT_EQ(old_capture_count, hang_capture_count_);
+  }
+
+  std::string ConcatenateThreadIds(
+      const std::vector<base::PlatformThreadId>& ids) const {
+    std::string result;
+    constexpr char kSeparator{'|'};
+
+    for (PlatformThreadId id : ids) {
+      result += base::NumberToString(id) + kSeparator;
+    }
+
+    return result;
+  }
+
+  // Will be signaled once monitoring took place. Marks the end of the test.
+  WaitableEvent monitor_event_;
+
+  const PlatformThreadId test_thread_id_ = PlatformThread::CurrentId();
+
+  // This is written to by the test main thread and read from the hang watching
+  // thread. It does not need to be protected because access to it is
+  // synchronized by always setting before triggering the execution of the
+  // reading code through HangWatcher::SignalMonitorEventForTesting().
+  std::string list_of_hung_thread_ids_during_capture_;
+
+  // This is written to by from the hang watching thread and read the test main
+  // thread. It does not need to be protected because access to it is
+  // synchronized by always reading  after monitor_event_ has been signaled.
+  int hang_capture_count_ = 0;
+
+  // Increases at the same time as |hang_capture_count_| to test that capture
+  // actually took place.
+  int reference_capture_count_ = 0;
+
+  std::string seconds_since_last_power_resume_crash_key_;
+
+  base::test::ScopedFeatureList feature_list_;
+
+  // Used exclusively for MOCK_TIME.
+  test::SingleThreadTaskEnvironment task_environment_{
+      test::TaskEnvironment::TimeSource::MOCK_TIME};
+
+  HangWatcher hang_watcher_;
+};
+}  // namespace
+
+// Verify that the hang capture fails when marking a thread for blocking fails.
+// This simulates a WatchHangsInScope completing between the time the hang
+// was dected and the time it is recorded which would create a non-actionable
+// report.
+TEST_F(HangWatcherSnapshotTest, NonActionableReport) {
+  hang_watcher_.SetOnHangClosureForTesting(
+      base::BindLambdaForTesting([this]() { ++hang_capture_count_; }));
+  hang_watcher_.SetAfterMonitorClosureForTesting(
+      base::BindLambdaForTesting([this]() { monitor_event_.Signal(); }));
+
+  hang_watcher_.Start();
+
+  // Register the main test thread for hang watching.
+  auto unregister_thread_closure =
+      HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
+  {
+    // Start a WatchHangsInScope that expires right away. Ensures that
+    // the first monitor will detect a hang.
+    WatchHangsInScope expires_instantly(base::TimeDelta{});
+
+    internal::HangWatchState* current_hang_watch_state =
+        internal::HangWatchState::GetHangWatchStateForCurrentThread();
+
+    // Simulate the deadline changing concurrently during the capture. This
+    // makes the capture fail since marking of the deadline fails.
+    ASSERT_NE(current_hang_watch_state->GetDeadline(),
+              base::TimeTicks::FromInternalValue(kArbitraryDeadline));
+    current_hang_watch_state->GetHangWatchDeadlineForTesting()
+        ->SetSwitchBitsClosureForTesting(
+            base::BindLambdaForTesting([]() { return kArbitraryDeadline; }));
+
+    ExpectNoCapture();
+
+    // Marking failed.
+    ASSERT_FALSE(current_hang_watch_state->IsFlagSet(
+        internal::HangWatchDeadline::Flag::kShouldBlockOnHang));
+
+    current_hang_watch_state->GetHangWatchDeadlineForTesting()
+        ->ResetSwitchBitsClosureForTesting();
+  }
+}
+
+// TODO(crbug.com/1223033): On MAC, the base::PlatformThread::CurrentId(...)
+// should return the system wide IDs. The HungThreadIDs test fails because the
+// reported process ids do not match.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_HungThreadIDs DISABLED_HungThreadIDs
+#else
+#define MAYBE_HungThreadIDs HungThreadIDs
+#endif
+
+TEST_F(HangWatcherSnapshotTest, MAYBE_HungThreadIDs) {
+  // During hang capture the list of hung threads should be populated.
+  hang_watcher_.SetOnHangClosureForTesting(base::BindLambdaForTesting([this]() {
+    EXPECT_EQ(hang_watcher_.GrabWatchStateSnapshotForTesting()
+                  .PrepareHungThreadListCrashKey(),
+              list_of_hung_thread_ids_during_capture_);
+    ++hang_capture_count_;
+  }));
+
+  // When hang capture is over the list should be empty.
+  hang_watcher_.SetAfterMonitorClosureForTesting(
+      base::BindLambdaForTesting([this]() {
+        monitor_event_.Signal();
+      }));
+
+  hang_watcher_.Start();
+
+  // Register the main test thread for hang watching.
+  auto unregister_thread_closure =
+      HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
+
+  BlockingThread blocking_thread(&monitor_event_, base::TimeDelta{});
+  blocking_thread.StartAndWaitForScopeEntered();
+  {
+    // Ensure the blocking thread entered the scope before the main thread. This
+    // will guarantee an ordering while reporting the list of hung threads.
+    task_environment_.AdvanceClock(kSmallCPUQuantum);
+
+    // Start a WatchHangsInScope that expires right away. Ensures that
+    // the first monitor will detect a hang. This scope will naturally have a
+    // later deadline than the one in |blocking_thread_| since it was created
+    // after.
+    WatchHangsInScope expires_instantly(base::TimeDelta{});
+
+    // Hung thread list should contain the id the blocking thread and then the
+    // id of the test main thread since that is the order of increasing
+    // deadline.
+    TestIDList(
+        ConcatenateThreadIds({blocking_thread.GetId(), test_thread_id_}));
+
+    // |expires_instantly| and the scope from |blocking_thread| are still live
+    // but already recorded so should be ignored.
+    ExpectNoCapture();
+
+    // Thread is joinable since we signaled |monitor_event_|. This closes the
+    // scope in |blocking_thread|.
+    blocking_thread.Join();
+
+    // |expires_instantly| is still live but already recorded so should be
+    // ignored.
+    ExpectNoCapture();
+  }
+
+  // All HangWatchScopeEnables are over. There should be no capture.
+  ExpectNoCapture();
+
+  // Once all recorded scopes are over creating a new one and monitoring will
+  // trigger a hang detection.
+  WatchHangsInScope expires_instantly(base::TimeDelta{});
+  TestIDList(ConcatenateThreadIds({test_thread_id_}));
+}
+
+TEST_F(HangWatcherSnapshotTest, TimeSinceLastSystemPowerResumeCrashKey) {
+  // Override the capture of hangs. Simulate a crash key capture.
+  hang_watcher_.SetOnHangClosureForTesting(base::BindLambdaForTesting([this]() {
+    ++hang_capture_count_;
+    seconds_since_last_power_resume_crash_key_ =
+        hang_watcher_.GetTimeSinceLastSystemPowerResumeCrashKeyValue();
+  }));
+
+  // When hang capture is over, unblock the main thread.
+  hang_watcher_.SetAfterMonitorClosureForTesting(
+      base::BindLambdaForTesting([this]() { monitor_event_.Signal(); }));
+
+  hang_watcher_.Start();
+
+  // Register the main test thread for hang watching.
+  auto unregister_thread_closure =
+      HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
+
+  {
+    WatchHangsInScope expires_instantly(base::TimeDelta{});
+    task_environment_.AdvanceClock(kSmallCPUQuantum);
+
+    TriggerMonitorAndWaitForCompletion();
+    EXPECT_EQ(1, hang_capture_count_);
+    EXPECT_EQ("Never suspended", seconds_since_last_power_resume_crash_key_);
+  }
+
+  {
+    test::ScopedPowerMonitorTestSource power_monitor_source;
+    power_monitor_source.Suspend();
+    task_environment_.AdvanceClock(kSmallCPUQuantum);
+
+    {
+      WatchHangsInScope expires_instantly(base::TimeDelta{});
+      task_environment_.AdvanceClock(kSmallCPUQuantum);
+      TriggerMonitorAndWaitForCompletion();
+      EXPECT_EQ(2, hang_capture_count_);
+      EXPECT_EQ("Power suspended", seconds_since_last_power_resume_crash_key_);
+    }
+
+    power_monitor_source.Resume();
+    constexpr TimeDelta kAfterResumeTime{base::Seconds(5)};
+    task_environment_.AdvanceClock(kAfterResumeTime);
+
+    {
+      WatchHangsInScope expires_instantly(base::TimeDelta{});
+      TriggerMonitorAndWaitForCompletion();
+      EXPECT_EQ(3, hang_capture_count_);
+      EXPECT_EQ(base::NumberToString(kAfterResumeTime.InSeconds()),
+                seconds_since_last_power_resume_crash_key_);
+    }
+  }
+}
+
+namespace {
+
+// Determines how long the HangWatcher will wait between calls to
+// Monitor(). Choose a low value so that that successive invocations happens
+// fast. This makes tests that wait for monitoring run fast and makes tests that
+// expect no monitoring fail fast.
+const base::TimeDelta kMonitoringPeriod = base::Milliseconds(1);
+
+// Test if and how often the HangWatcher periodically monitors for hangs.
+class HangWatcherPeriodicMonitoringTest : public testing::Test {
+ public:
+  HangWatcherPeriodicMonitoringTest() {
+    hang_watcher_.InitializeOnMainThread(
+        HangWatcher::ProcessType::kBrowserProcess);
+
+    hang_watcher_.SetMonitoringPeriodForTesting(kMonitoringPeriod);
+    hang_watcher_.SetOnHangClosureForTesting(base::BindRepeating(
+        &WaitableEvent::Signal, base::Unretained(&hang_event_)));
+
+    // HangWatcher uses a TickClock to detect how long it slept in between calls
+    // to Monitor(). Override that clock to control its subjective passage of
+    // time.
+    hang_watcher_.SetTickClockForTesting(&test_clock_);
+  }
+
+  HangWatcherPeriodicMonitoringTest(
+      const HangWatcherPeriodicMonitoringTest& other) = delete;
+  HangWatcherPeriodicMonitoringTest& operator=(
+      const HangWatcherPeriodicMonitoringTest& other) = delete;
+
+  void TearDown() override { hang_watcher_.UnitializeOnMainThreadForTesting(); }
+
+ protected:
+  // Setup the callback invoked after waiting in HangWatcher to advance the
+  // tick clock by the desired time delta.
+  void InstallAfterWaitCallback(base::TimeDelta time_delta) {
+    hang_watcher_.SetAfterWaitCallbackForTesting(base::BindLambdaForTesting(
+        [this, time_delta](base::TimeTicks time_before_wait) {
+          test_clock_.Advance(time_delta);
+        }));
+  }
+
+  base::SimpleTestTickClock test_clock_;
+
+  // Single threaded to avoid ThreadPool WorkerThreads registering. Will run
+  // delayed tasks created by the tests.
+  test::SingleThreadTaskEnvironment task_environment_;
+
+  std::unique_ptr<base::TickClock> fake_tick_clock_;
+  HangWatcher hang_watcher_;
+
+  // Signaled when a hang is detected.
+  WaitableEvent hang_event_;
+
+  base::ScopedClosureRunner unregister_thread_closure_;
+};
+}  // namespace
+
+// Don't register any threads for hang watching. HangWatcher should not monitor.
+TEST_F(HangWatcherPeriodicMonitoringTest,
+       NoPeriodicMonitoringWithoutRegisteredThreads) {
+  RunLoop run_loop;
+
+  // If a call to HangWatcher::Monitor() takes place the test will instantly
+  // fail.
+  hang_watcher_.SetAfterMonitorClosureForTesting(
+      base::BindLambdaForTesting([&run_loop]() {
+        ADD_FAILURE() << "Monitoring took place!";
+        run_loop.Quit();
+      }));
+
+  // Make the HangWatcher tick clock advance by exactly the monitoring period
+  // after waiting so it will never detect oversleeping between attempts to call
+  // Monitor(). This would inhibit monitoring and make the test pass for the
+  // wrong reasons.
+  InstallAfterWaitCallback(kMonitoringPeriod);
+
+  hang_watcher_.Start();
+
+  // Unblock the test thread. No thread ever registered after the HangWatcher
+  // was created in the test's constructor. No monitoring should have taken
+  // place.
+  task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
+  run_loop.Run();
+
+  // NOTE:
+  // A lack of calls could technically also be caused by the HangWatcher thread
+  // executing too slowly / being descheduled. This is a known limitation.
+  // It's expected for |TestTimeouts::tiny_timeout()| to be large enough that
+  // this is rare.
+}
+
+// During normal execution periodic monitorings should take place.
+TEST_F(HangWatcherPeriodicMonitoringTest, PeriodicCallsTakePlace) {
+  // HangWatcher::Monitor() will run once right away on thread registration.
+  // We want to make sure it runs at a couple more times from being scheduled.
+  constexpr int kMinimumMonitorCount = 3;
+
+  RunLoop run_loop;
+
+  // Setup the HangWatcher to unblock run_loop when the Monitor() has been
+  // invoked enough times.
+  hang_watcher_.SetAfterMonitorClosureForTesting(BarrierClosure(
+      kMinimumMonitorCount, base::BindLambdaForTesting([&run_loop]() {
+        // Test condition are confirmed, stop monitoring.
+        HangWatcher::StopMonitoringForTesting();
+
+        // Unblock the test main thread.
+        run_loop.Quit();
+      })));
+
+  // Make the HangWatcher tick clock advance by exactly the monitoring period
+  // after waiting so it will never detect oversleeping between attempts to call
+  // Monitor(). This would inhibit monitoring.
+  InstallAfterWaitCallback(kMonitoringPeriod);
+
+  hang_watcher_.Start();
+
+  // Register a thread,
+  unregister_thread_closure_ =
+      HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
+
+  run_loop.Run();
+
+  // No monitored scope means no possible hangs.
+  ASSERT_FALSE(hang_event_.IsSignaled());
+}
+
+// If the HangWatcher detects it slept for longer than expected it will not
+// monitor.
+TEST_F(HangWatcherPeriodicMonitoringTest, NoMonitorOnOverSleep) {
+  RunLoop run_loop;
+
+  // If a call to HangWatcher::Monitor() takes place the test will instantly
+  // fail.
+  hang_watcher_.SetAfterMonitorClosureForTesting(
+      base::BindLambdaForTesting([&run_loop]() {
+        ADD_FAILURE() << "Monitoring took place!";
+        run_loop.Quit();
+      }));
+
+  // Make the HangWatcher tick clock advance so much after waiting that it will
+  // detect oversleeping every time. This will keep it from monitoring.
+  InstallAfterWaitCallback(base::Minutes(1));
+
+  hang_watcher_.Start();
+
+  // Register a thread.
+  unregister_thread_closure_ =
+      HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
+
+  // Unblock the test thread. All waits were perceived as oversleeping so all
+  // monitoring was inhibited.
+  task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
+  run_loop.Run();
+
+  // NOTE: A lack of calls could technically also be caused by the HangWatcher
+  // thread executing too slowly / being descheduled. This is a known
+  // limitation. It's expected for |TestTimeouts::tiny_timeout()| to be large
+  // enough that this happens rarely.
+}
+
+namespace {
+class WatchHangsInScopeBlockingTest : public testing::Test {
+ public:
+  WatchHangsInScopeBlockingTest() {
+    feature_list_.InitWithFeaturesAndParameters(kFeatureAndParams, {});
+    hang_watcher_.InitializeOnMainThread(
+        HangWatcher::ProcessType::kBrowserProcess);
+
+    hang_watcher_.SetOnHangClosureForTesting(base::BindLambdaForTesting([&] {
+      capture_started_.Signal();
+      // Simulate capturing that takes a long time.
+      PlatformThread::Sleep(base::Milliseconds(500));
+
+      continue_capture_.Wait();
+      completed_capture_ = true;
+    }));
+
+    hang_watcher_.SetAfterMonitorClosureForTesting(
+        base::BindLambdaForTesting([&] {
+          // Simulate monitoring that takes a long time.
+          PlatformThread::Sleep(base::Milliseconds(500));
+          completed_monitoring_.Signal();
+        }));
+
+    // Make sure no periodic monitoring takes place.
+    hang_watcher_.SetMonitoringPeriodForTesting(kVeryLongDelta);
+
+    hang_watcher_.Start();
+
+    // Register the test main thread for hang watching.
+    unregister_thread_closure_ =
+        HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
+  }
+
+  void TearDown() override { hang_watcher_.UnitializeOnMainThreadForTesting(); }
+
+  WatchHangsInScopeBlockingTest(const WatchHangsInScopeBlockingTest& other) =
+      delete;
+  WatchHangsInScopeBlockingTest& operator=(
+      const WatchHangsInScopeBlockingTest& other) = delete;
+
+  void VerifyScopesDontBlock() {
+    // Start a WatchHangsInScope that cannot possibly cause a hang to be
+    // detected.
+    {
+      WatchHangsInScope long_scope(kVeryLongDelta);
+
+      // Manually trigger a monitoring.
+      hang_watcher_.SignalMonitorEventForTesting();
+
+      // Execution has to continue freely here as no capture is in progress.
+    }
+
+    // Monitoring should not be over yet because the test code should execute
+    // faster when not blocked.
+    EXPECT_FALSE(completed_monitoring_.IsSignaled());
+
+    // Wait for the full monitoring process to be complete. This is to prove
+    // that monitoring truly executed and that we raced the signaling.
+    completed_monitoring_.Wait();
+
+    // No hang means no capture.
+    EXPECT_FALSE(completed_capture_);
+  }
+
+ protected:
+  base::WaitableEvent capture_started_;
+  base::WaitableEvent completed_monitoring_;
+
+  // The HangWatcher waits on this event via the "on hang" closure when a hang
+  // is detected.
+  base::WaitableEvent continue_capture_;
+  bool completed_capture_{false};
+
+  base::test::ScopedFeatureList feature_list_;
+  HangWatcher hang_watcher_;
+  base::ScopedClosureRunner unregister_thread_closure_;
+};
+}  // namespace
+
+// Tests that execution is unimpeded by ~WatchHangsInScope() when no capture
+// ever takes place.
+TEST_F(WatchHangsInScopeBlockingTest, ScopeDoesNotBlocksWithoutCapture) {
+  // No capture should take place so |continue_capture_| is not signaled to
+  // create a test hang if one ever does.
+  VerifyScopesDontBlock();
+}
+
+// Test that execution blocks in ~WatchHangsInScope() for a thread under
+// watch during the capturing of a hang.
+TEST_F(WatchHangsInScopeBlockingTest, ScopeBlocksDuringCapture) {
+  // The capture completing is not dependent on any test event. Signal to make
+  // sure the test is not blocked.
+  continue_capture_.Signal();
+
+  // Start a WatchHangsInScope that expires in the past already. Ensures
+  // that the first monitor will detect a hang.
+  {
+    // Start a WatchHangsInScope that expires right away. Ensures that the
+    // first monitor will detect a hang.
+    WatchHangsInScope expires_right_away(base::TimeDelta{});
+
+    // Manually trigger a monitoring.
+    hang_watcher_.SignalMonitorEventForTesting();
+
+    // Ensure that the hang capturing started.
+    capture_started_.Wait();
+
+    // Execution will get stuck in the outer scope because it can't escape
+    // ~WatchHangsInScope() if a hang capture is under way.
+  }
+
+  // A hang was in progress so execution should have been blocked in
+  // BlockWhileCaptureInProgress() until capture finishes.
+  EXPECT_TRUE(completed_capture_);
+  completed_monitoring_.Wait();
+
+  // Reset expectations
+  completed_monitoring_.Reset();
+  capture_started_.Reset();
+  completed_capture_ = false;
+
+  // Verify that scopes don't block just because a capture happened in the past.
+  VerifyScopesDontBlock();
+}
+
+#if BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)
+// Flaky hangs on arm64 Macs: https://crbug.com/1140207
+#define MAYBE_NewScopeDoesNotBlockDuringCapture \
+  DISABLED_NewScopeDoesNotBlockDuringCapture
+#else
+#define MAYBE_NewScopeDoesNotBlockDuringCapture \
+  NewScopeDoesNotBlockDuringCapture
+#endif
+
+// Test that execution does not block in ~WatchHangsInScope() when the scope
+// was created after the start of a capture.
+TEST_F(WatchHangsInScopeBlockingTest, MAYBE_NewScopeDoesNotBlockDuringCapture) {
+  // Start a WatchHangsInScope that expires right away. Ensures that the
+  // first monitor will detect a hang.
+  WatchHangsInScope expires_right_away(base::TimeDelta{});
+
+  // Manually trigger a monitoring.
+  hang_watcher_.SignalMonitorEventForTesting();
+
+  // Ensure that the hang capturing started.
+  capture_started_.Wait();
+
+  // A scope started once a capture is already under way should not block
+  // execution.
+  { WatchHangsInScope also_expires_right_away(base::TimeDelta{}); }
+
+  // Wait for the new WatchHangsInScope to be destroyed to let the capture
+  // finish. If the new scope block waiting for the capture to finish this would
+  // create a deadlock and the test would hang.
+  continue_capture_.Signal();
+}
+
+namespace internal {
+namespace {
+
+constexpr std::array<HangWatchDeadline::Flag, 3> kAllFlags{
+    {HangWatchDeadline::Flag::kMinValue,
+     HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope,
+     HangWatchDeadline::Flag::kShouldBlockOnHang}};
+}  // namespace
+
+class HangWatchDeadlineTest : public testing::Test {
+ protected:
+  void AssertNoFlagsSet() const {
+    for (HangWatchDeadline::Flag flag : kAllFlags) {
+      ASSERT_FALSE(deadline_.IsFlagSet(flag));
+    }
+  }
+
+  // Return a flag mask without one of the flags for test purposes. Use to
+  // ignore that effect of setting a flag that was just set.
+  uint64_t FlagsMinus(uint64_t flags, HangWatchDeadline::Flag flag) {
+    return flags & ~(static_cast<uint64_t>(flag));
+  }
+
+  HangWatchDeadline deadline_;
+};
+
+// Verify that the extract functions don't mangle any bits.
+TEST_F(HangWatchDeadlineTest, BitsPreservedThroughExtract) {
+  for (auto bits : {kAllOnes, kAllZeros, kOnesThenZeroes, kZeroesThenOnes}) {
+    ASSERT_TRUE((HangWatchDeadline::ExtractFlags(bits) |
+                 HangWatchDeadline::ExtractDeadline(bits)) == bits);
+  }
+}
+
+// Verify that setting and clearing a persistent flag works and has no unwanted
+// side-effects. Neither the flags nor the deadline change concurrently in this
+// test.
+TEST_F(HangWatchDeadlineTest, SetAndClearPersistentFlag) {
+  AssertNoFlagsSet();
+
+  // Grab the original values for flags and deadline.
+  auto [old_flags, old_deadline] = deadline_.GetFlagsAndDeadline();
+
+  // Set the flag. Operation cannot fail.
+  deadline_.SetIgnoreCurrentWatchHangsInScope();
+
+  // Get new flags and deadline.
+  auto [new_flags, new_deadline] = deadline_.GetFlagsAndDeadline();
+
+  // Flag was set properly.
+  ASSERT_TRUE(HangWatchDeadline::IsFlagSet(
+      HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope, new_flags));
+
+  // No side-effect on deadline.
+  ASSERT_EQ(new_deadline, old_deadline);
+
+  // No side-effect on other flags.
+  ASSERT_EQ(
+      FlagsMinus(new_flags,
+                 HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope),
+      old_flags);
+
+  // Clear the flag, operation cannot fail.
+  deadline_.UnsetIgnoreCurrentWatchHangsInScope();
+
+  // Update new values.
+  std::tie(new_flags, new_deadline) = deadline_.GetFlagsAndDeadline();
+
+  // All flags back to original state.
+  ASSERT_EQ(new_flags, old_flags);
+
+  // Deadline still unnafected.
+  ASSERT_EQ(new_deadline, old_deadline);
+}
+
+// Verify setting the TimeTicks value works and has no unwanted side-effects.
+TEST_F(HangWatchDeadlineTest, SetDeadline) {
+  TimeTicks ticks;
+
+  AssertNoFlagsSet();
+  ASSERT_NE(deadline_.GetDeadline(), ticks);
+
+  // Set the deadline and verify it stuck.
+  deadline_.SetDeadline(ticks);
+  ASSERT_EQ(deadline_.GetDeadline(), ticks);
+
+  // Only the value was modified, no flags should be set.
+  AssertNoFlagsSet();
+}
+
+// Verify that setting a non-persistent flag (kShouldBlockOnHang)
+// when the TimeTicks value changed since calling the flag setting
+// function fails and has no side-effects.
+TEST_F(HangWatchDeadlineTest, SetShouldBlockOnHangDeadlineChanged) {
+  AssertNoFlagsSet();
+
+  auto [flags, deadline] = deadline_.GetFlagsAndDeadline();
+
+  // Simulate value change. Flags are constant.
+  const base::TimeTicks new_deadline =
+      base::TimeTicks::FromInternalValue(kArbitraryDeadline);
+  ASSERT_NE(deadline, new_deadline);
+  deadline_.SetSwitchBitsClosureForTesting(
+      base::BindLambdaForTesting([]() { return kArbitraryDeadline; }));
+
+  // kShouldBlockOnHangs does not persist through value change.
+  ASSERT_FALSE(deadline_.SetShouldBlockOnHang(flags, deadline));
+
+  // Flag was not applied.
+  ASSERT_FALSE(
+      deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
+
+  // New value that was changed concurrently is preserved.
+  ASSERT_EQ(deadline_.GetDeadline(), new_deadline);
+}
+
+// Verify that clearing a persistent (kIgnoreCurrentWatchHangsInScope) when
+// the value changed succeeds and has non side-effects.
+TEST_F(HangWatchDeadlineTest, ClearIgnoreHangsDeadlineChanged) {
+  AssertNoFlagsSet();
+
+  auto [flags, deadline] = deadline_.GetFlagsAndDeadline();
+
+  deadline_.SetIgnoreCurrentWatchHangsInScope();
+  std::tie(flags, deadline) = deadline_.GetFlagsAndDeadline();
+  ASSERT_TRUE(HangWatchDeadline::IsFlagSet(
+      HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope, flags));
+
+  // Simulate deadline change. Flags are constant.
+  const base::TimeTicks new_deadline =
+      base::TimeTicks::FromInternalValue(kArbitraryDeadline);
+  ASSERT_NE(deadline, new_deadline);
+  deadline_.SetSwitchBitsClosureForTesting(base::BindLambdaForTesting([]() {
+    return static_cast<uint64_t>(HangWatchDeadline::Flag::kShouldBlockOnHang) |
+           kArbitraryDeadline;
+  }));
+
+  // Clearing kIgnoreHang is unaffected by deadline or flags change.
+  deadline_.UnsetIgnoreCurrentWatchHangsInScope();
+  ASSERT_FALSE(deadline_.IsFlagSet(
+      HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope));
+
+  // New deadline that was changed concurrently is preserved.
+  ASSERT_TRUE(deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
+  ASSERT_EQ(deadline_.GetDeadline(), new_deadline);
+}
+
+// Verify that setting a persistent (kIgnoreCurrentWatchHangsInScope) when
+// the deadline or flags changed succeeds and has non side-effects.
+TEST_F(HangWatchDeadlineTest,
+       SetIgnoreCurrentHangWatchScopeEnableDeadlineChangedd) {
+  AssertNoFlagsSet();
+
+  auto [flags, deadline] = deadline_.GetFlagsAndDeadline();
+
+  // Simulate deadline change. Flags are constant.
+  const base::TimeTicks new_deadline =
+      base::TimeTicks::FromInternalValue(kArbitraryDeadline);
+
+  ASSERT_NE(deadline, new_deadline);
+  deadline_.SetSwitchBitsClosureForTesting(base::BindLambdaForTesting([]() {
+    return static_cast<uint64_t>(HangWatchDeadline::Flag::kShouldBlockOnHang) |
+           kArbitraryDeadline;
+  }));
+
+  // kIgnoreHang persists through value change.
+  deadline_.SetIgnoreCurrentWatchHangsInScope();
+  ASSERT_TRUE(deadline_.IsFlagSet(
+      HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope));
+
+  // New deadline and flags that changed concurrently are preserved.
+  ASSERT_TRUE(deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
+  ASSERT_EQ(deadline_.GetDeadline(), new_deadline);
+}
+
+// Setting a new deadline should wipe flags that a not persistent.
+// Persistent flags should not be disturbed.
+TEST_F(HangWatchDeadlineTest, SetDeadlineWipesFlags) {
+  auto [flags, deadline] = deadline_.GetFlagsAndDeadline();
+
+  ASSERT_TRUE(deadline_.SetShouldBlockOnHang(flags, deadline));
+  ASSERT_TRUE(deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
+
+  std::tie(flags, deadline) = deadline_.GetFlagsAndDeadline();
+
+  deadline_.SetIgnoreCurrentWatchHangsInScope();
+  ASSERT_TRUE(deadline_.IsFlagSet(
+      HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope));
+
+  // Change the deadline.
+  deadline_.SetDeadline(TimeTicks{});
+  ASSERT_EQ(deadline_.GetDeadline(), TimeTicks{});
+
+  // Verify the persistent flag stuck and the non-persistent one was unset.
+  ASSERT_FALSE(
+      deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
+  ASSERT_TRUE(deadline_.IsFlagSet(
+      HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope));
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/threading/platform_thread.cc b/base/threading/platform_thread.cc
new file mode 100644
index 0000000..33abed1
--- /dev/null
+++ b/base/threading/platform_thread.cc
@@ -0,0 +1,157 @@
+// Copyright 2018 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread.h"
+
+#include "base/task/current_thread.h"
+#include "third_party/abseil-cpp/absl/base/attributes.h"
+
+#if BUILDFLAG(IS_FUCHSIA)
+#include "base/fuchsia/scheduler.h"
+#endif
+
+#if defined(STARBOARD)
+#include <pthread.h>
+
+#include "base/check_op.h"
+#endif
+
+namespace base {
+
+namespace {
+
+#if defined(STARBOARD)
+
+enum TlsValue {
+  kDefault = 0,
+  kBackground = 1,
+  kUtility = 2,
+  kResourceEfficient = 3 ,
+  kCompositing = 4,
+  kDisplayCritical = 5,
+  kRealtimeAudio = 6,
+  kMaxValue = kRealtimeAudio,
+};
+
+TlsValue ThreadTypeToTlsValue(ThreadType type) {
+  if (type == ThreadType::kMaxValue) {
+    type = ThreadType::kRealtimeAudio;
+  }
+  switch(type) {
+    case ThreadType::kDefault:
+      return TlsValue::kDefault;
+    case ThreadType::kBackground:
+      return TlsValue::kBackground;
+    case  ThreadType::kUtility:
+      return TlsValue::kUtility;
+    case  ThreadType::kResourceEfficient:
+      return TlsValue::kResourceEfficient;
+    case  ThreadType::kCompositing:
+      return TlsValue::kCompositing;
+    case  ThreadType::kDisplayCritical:
+      return TlsValue::kDisplayCritical;
+    case  ThreadType::kRealtimeAudio:
+      return TlsValue::kRealtimeAudio;
+  }
+}
+
+ThreadType TlsValueToThreadType(TlsValue tls_value) {
+  if (tls_value == TlsValue::kMaxValue) {
+    tls_value = TlsValue::kRealtimeAudio;
+  }
+  switch(tls_value) {
+    case TlsValue::kDefault:
+      return ThreadType::kDefault;
+    case TlsValue::kBackground:
+      return ThreadType::kBackground;
+    case TlsValue::kUtility:
+      return ThreadType::kUtility;
+    case TlsValue::kResourceEfficient:
+      return ThreadType::kResourceEfficient;
+    case TlsValue::kCompositing:
+      return ThreadType::kCompositing;
+    case  TlsValue::kDisplayCritical:
+      return ThreadType::kDisplayCritical;
+    case TlsValue::kRealtimeAudio:
+      return ThreadType::kRealtimeAudio;
+  }
+}
+
+ABSL_CONST_INIT pthread_once_t s_once_flag = PTHREAD_ONCE_INIT;
+ABSL_CONST_INIT pthread_key_t s_thread_local_key = 0;
+
+void InitThreadLocalKey() {
+  int res = pthread_key_create(&s_thread_local_key , NULL);
+  DCHECK(res == 0);
+}
+
+void EnsureThreadLocalKeyInited() {
+  pthread_once(&s_once_flag, InitThreadLocalKey);
+}
+
+ThreadType GetCurrentThreadTypeValue() {
+  EnsureThreadLocalKeyInited();
+  return TlsValueToThreadType(TlsValue(reinterpret_cast<intptr_t>(pthread_getspecific(s_thread_local_key))));
+}
+#else
+ABSL_CONST_INIT thread_local ThreadType current_thread_type =
+    ThreadType::kDefault;
+#endif
+
+}  // namespace
+
+// static
+void PlatformThread::SetCurrentThreadType(ThreadType thread_type) {
+  MessagePumpType message_pump_type = MessagePumpType::DEFAULT;
+  if (CurrentIOThread::IsSet()) {
+    message_pump_type = MessagePumpType::IO;
+  }
+#if !BUILDFLAG(IS_NACL)
+  else if (CurrentUIThread::IsSet()) {
+    message_pump_type = MessagePumpType::UI;
+  }
+#endif
+  internal::SetCurrentThreadType(thread_type, message_pump_type);
+}
+
+// static
+ThreadType PlatformThread::GetCurrentThreadType() {
+#if defined(STARBOARD)
+  ThreadType type = GetCurrentThreadTypeValue(); 
+  return type;
+#else
+  return current_thread_type;
+#endif
+}
+
+// static
+absl::optional<TimeDelta> PlatformThread::GetThreadLeewayOverride() {
+#if BUILDFLAG(IS_FUCHSIA)
+  // On Fuchsia, all audio threads run with the CPU scheduling profile that uses
+  // an interval of |kAudioSchedulingPeriod|. Using the default leeway may lead
+  // to some tasks posted to audio threads to be executed too late (see
+  // http://crbug.com/1368858).
+  if (GetCurrentThreadType() == ThreadType::kRealtimeAudio)
+    return kAudioSchedulingPeriod;
+#endif
+  return absl::nullopt;
+}
+
+namespace internal {
+
+void SetCurrentThreadType(ThreadType thread_type,
+                          MessagePumpType pump_type_hint) {
+  CHECK_LE(thread_type, ThreadType::kMaxValue);
+  SetCurrentThreadTypeImpl(thread_type, pump_type_hint);
+#if defined(STARBOARD)
+  EnsureThreadLocalKeyInited();
+  pthread_setspecific(s_thread_local_key, reinterpret_cast<void*>(ThreadTypeToTlsValue(thread_type)));
+#else
+  current_thread_type = thread_type;
+#endif
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h
index 1882df8..0623f59 100644
--- a/base/threading/platform_thread.h
+++ b/base/threading/platform_thread.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -9,26 +9,30 @@
 #ifndef BASE_THREADING_PLATFORM_THREAD_H_
 #define BASE_THREADING_PLATFORM_THREAD_H_
 
+#include <stddef.h>
+
+#include <iosfwd>
+#include <type_traits>
+
 #include "base/base_export.h"
-#include "base/macros.h"
+#include "base/message_loop/message_pump_type.h"
+#include "base/threading/platform_thread_ref.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 #if defined(STARBOARD)
 #include "starboard/thread.h"
-#else
-#if defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
 #include "base/win/windows_types.h"
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
 #include <zircon/types.h>
-#elif defined(OS_MACOSX)
+#elif BUILDFLAG(IS_APPLE)
 #include <mach/mach_types.h>
-#elif defined(OS_POSIX)
+#elif BUILDFLAG(IS_POSIX)
 #include <pthread.h>
 #include <unistd.h>
-
-#include "starboard/types.h"
-#endif
 #endif
 
 namespace base {
@@ -36,65 +40,30 @@
 // Used for logging. Always an integer value.
 #if defined(STARBOARD)
 typedef SbThreadId PlatformThreadId;
-#else
-#if defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
 typedef DWORD PlatformThreadId;
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
 typedef zx_handle_t PlatformThreadId;
-#elif defined(OS_MACOSX)
+#elif BUILDFLAG(IS_APPLE)
 typedef mach_port_t PlatformThreadId;
-#elif defined(OS_POSIX)
+#elif BUILDFLAG(IS_POSIX)
 typedef pid_t PlatformThreadId;
 #endif
-#endif
-
-// Used for thread checking and debugging.
-// Meant to be as fast as possible.
-// These are produced by PlatformThread::CurrentRef(), and used to later
-// check if we are on the same thread or not by using ==. These are safe
-// to copy between threads, but can't be copied to another process as they
-// have no meaning there. Also, the internal identifier can be re-used
-// after a thread dies, so a PlatformThreadRef cannot be reliably used
-// to distinguish a new thread from an old, dead thread.
-class PlatformThreadRef {
- public:
-#if defined(STARBOARD)
-  typedef SbThread RefType;
-#else
-#if defined(OS_WIN)
-  typedef DWORD RefType;
-#else  //  OS_POSIX
-  typedef pthread_t RefType;
-#endif
-#endif
-  constexpr PlatformThreadRef() : id_(0) {}
-
-  explicit constexpr PlatformThreadRef(RefType id) : id_(id) {}
-
-  bool operator==(PlatformThreadRef other) const {
-    return id_ == other.id_;
-  }
-
-  bool operator!=(PlatformThreadRef other) const { return id_ != other.id_; }
-
-  bool is_null() const {
-    return id_ == 0;
-  }
- private:
-  RefType id_;
-};
+static_assert(std::is_integral_v<PlatformThreadId>, "Always an integer value.");
 
 // Used to operate on threads.
 class PlatformThreadHandle {
  public:
 #if defined(STARBOARD)
+#if SB_API_VERSION < 16
   typedef SbThread Handle;
 #else
-#if defined(OS_WIN)
-  typedef void* Handle;
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
   typedef pthread_t Handle;
 #endif
+#elif BUILDFLAG(IS_WIN)
+  typedef void* Handle;
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
+  typedef pthread_t Handle;
 #endif
 
   constexpr PlatformThreadHandle() : handle_(0) {}
@@ -119,29 +88,64 @@
 
 const PlatformThreadId kInvalidThreadId(0);
 
-// Valid values for priority of Thread::Options and SimpleThread::Options, and
-// SetCurrentThreadPriority(), listed in increasing order of importance.
-enum class ThreadPriority : int {
-#if defined(STARBOARD)
-  DEFAULT = kSbThreadNoPriority,
-  LOWEST = kSbThreadPriorityLowest,
-  BACKGROUND = kSbThreadPriorityLow,
-  NORMAL = kSbThreadPriorityNormal,
-  DISPLAY = kSbThreadPriorityHigh,
-  HIGHEST = kSbThreadPriorityHighest,
-  REALTIME_AUDIO = kSbThreadPriorityRealTime,  // Could be equal to HIGHEST.
-#else
-  // Suitable for threads that shouldn't disrupt high priority work.
-  BACKGROUND,
-  // Default priority level.
-  NORMAL,
-  // Suitable for threads which generate data for the display (at ~60Hz).
-  DISPLAY,
+// Valid values for `thread_type` of Thread::Options, SimpleThread::Options,
+// and SetCurrentThreadType(), listed in increasing order of importance.
+//
+// It is up to each platform-specific implementation what these translate to.
+// Callers should avoid setting different ThreadTypes on different platforms
+// (ifdefs) at all cost, instead the platform differences should be encoded in
+// the platform-specific implementations. Some implementations may treat
+// adjacent ThreadTypes in this enum as equivalent.
+//
+// Reach out to //base/task/OWNERS (scheduler-dev@chromium.org) before changing
+// thread type assignments in your component, as such decisions affect the whole
+// of Chrome.
+//
+// Refer to PlatformThreadTest.SetCurrentThreadTypeTest in
+// platform_thread_unittest.cc for the most up-to-date state of each platform's
+// handling of ThreadType.
+enum class ThreadType : int {
+  // Suitable for threads that have the least urgency and lowest priority, and
+  // can be interrupted or delayed by other types.
+  kBackground,
+  // Suitable for threads that are less important than normal type, and can be
+  // interrupted or delayed by threads with kDefault type.
+  kUtility,
+  // Suitable for threads that produce user-visible artifacts but aren't
+  // latency sensitive. The underlying platform will try to be economic
+  // in its usage of resources for this thread, if possible.
+  kResourceEfficient,
+  // Default type. The thread priority or quality of service will be set to
+  // platform default. In Chrome, this is suitable for handling user
+  // interactions (input), only display and audio can get a higher priority.
+  kDefault,
+  // Suitable for threads which are critical to compositing the foreground
+  // content.
+  kCompositing,
+  // Suitable for display critical threads.
+  kDisplayCritical,
   // Suitable for low-latency, glitch-resistant audio.
-  REALTIME_AUDIO,
-#endif
+  kRealtimeAudio,
+  kMaxValue = kRealtimeAudio,
 };
 
+// Cross-platform mapping of physical thread priorities. Used by tests to verify
+// the underlying effects of SetCurrentThreadType.
+enum class ThreadPriorityForTest : int {
+  kBackground,
+  kUtility,
+  kNormal,
+  // The priority obtained via ThreadType::kDisplayCritical (and potentially
+  // other ThreadTypes).
+  kDisplay,
+  kRealtimeAudio,
+  kMaxValue = kRealtimeAudio,
+};
+
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+class ThreadTypeDelegate;
+#endif
+
 // A namespace for low-level thread functions.
 class BASE_EXPORT PlatformThread {
  public:
@@ -149,12 +153,24 @@
   // ThreadMain method will be called on the newly created thread.
   class BASE_EXPORT Delegate {
    public:
+#if BUILDFLAG(IS_APPLE)
+    // The interval at which the thread expects to have work to do. Zero if
+    // unknown. (Example: audio buffer duration for real-time audio.) Is used to
+    // optimize the thread real-time behavior. Is called on the newly created
+    // thread before ThreadMain().
+    virtual TimeDelta GetRealtimePeriod();
+#endif
+
     virtual void ThreadMain() = 0;
 
    protected:
     virtual ~Delegate() = default;
   };
 
+  PlatformThread() = delete;
+  PlatformThread(const PlatformThread&) = delete;
+  PlatformThread& operator=(const PlatformThread&) = delete;
+
   // Gets the current thread id, which may be useful for logging purposes.
   static PlatformThreadId CurrentId();
 
@@ -169,9 +185,19 @@
   static PlatformThreadHandle CurrentHandle();
 
   // Yield the current thread so another thread can be scheduled.
+  //
+  // Note: this is likely not the right call to make in most situations. If this
+  // is part of a spin loop, consider base::Lock, which likely has better tail
+  // latency. Yielding the thread has different effects depending on the
+  // platform, system load, etc., and can result in yielding the CPU for less
+  // than 1us, or many tens of ms.
   static void YieldCurrentThread();
 
-  // Sleeps for the specified duration.
+  // Sleeps for the specified duration (real-time; ignores time overrides).
+  // Note: The sleep duration may be in base::Time or base::TimeTicks, depending
+  // on platform. If you're looking to use this in unit tests testing delayed
+  // tasks, this will be unreliable - instead, use
+  // base::test::TaskEnvironment with MOCK_TIME mode.
   static void Sleep(base::TimeDelta duration);
 
   // Sets the thread name visible to debuggers/tools. This will try to
@@ -181,10 +207,10 @@
   // Gets the thread name, if previously set by SetName.
   static const char* GetName();
 
-  // Creates a new thread.  The |stack_size| parameter can be 0 to indicate
+  // Creates a new thread.  The `stack_size` parameter can be 0 to indicate
   // that the default stack size should be used.  Upon success,
-  // |*thread_handle| will be assigned a handle to the newly created thread,
-  // and |delegate|'s ThreadMain method will be executed on the newly created
+  // `*thread_handle` will be assigned a handle to the newly created thread,
+  // and `delegate`'s ThreadMain method will be executed on the newly created
   // thread.
   // NOTE: When you are done with the thread handle, you must call Join to
   // release system resources associated with the thread.  You must ensure that
@@ -192,75 +218,114 @@
   static bool Create(size_t stack_size,
                      Delegate* delegate,
                      PlatformThreadHandle* thread_handle) {
-    return CreateWithPriority(stack_size, delegate, thread_handle,
-                              ThreadPriority::NORMAL);
+    return CreateWithType(stack_size, delegate, thread_handle,
+                          ThreadType::kDefault);
   }
 
-  // CreateWithPriority() does the same thing as Create() except the priority of
-  // the thread is set based on |priority|.
-  static bool CreateWithPriority(size_t stack_size, Delegate* delegate,
-                                 PlatformThreadHandle* thread_handle,
-                                 ThreadPriority priority);
+  // CreateWithType() does the same thing as Create() except the priority and
+  // possibly the QoS of the thread is set based on `thread_type`.
+  // `pump_type_hint` must be provided if the thread will be using a
+  // MessagePumpForUI or MessagePumpForIO as this affects the application of
+  // `thread_type`.
+  static bool CreateWithType(
+      size_t stack_size,
+      Delegate* delegate,
+      PlatformThreadHandle* thread_handle,
+      ThreadType thread_type,
+      MessagePumpType pump_type_hint = MessagePumpType::DEFAULT);
 
   // CreateNonJoinable() does the same thing as Create() except the thread
   // cannot be Join()'d.  Therefore, it also does not output a
   // PlatformThreadHandle.
   static bool CreateNonJoinable(size_t stack_size, Delegate* delegate);
 
-  // CreateNonJoinableWithPriority() does the same thing as CreateNonJoinable()
-  // except the priority of the thread is set based on |priority|.
-  static bool CreateNonJoinableWithPriority(size_t stack_size,
-                                            Delegate* delegate,
-                                            ThreadPriority priority);
+  // CreateNonJoinableWithType() does the same thing as CreateNonJoinable()
+  // except the type of the thread is set based on `type`. `pump_type_hint` must
+  // be provided if the thread will be using a MessagePumpForUI or
+  // MessagePumpForIO as this affects the application of `thread_type`.
+  static bool CreateNonJoinableWithType(
+      size_t stack_size,
+      Delegate* delegate,
+      ThreadType thread_type,
+      MessagePumpType pump_type_hint = MessagePumpType::DEFAULT);
 
   // Joins with a thread created via the Create function.  This function blocks
   // the caller until the designated thread exits.  This will invalidate
-  // |thread_handle|.
+  // `thread_handle`.
   static void Join(PlatformThreadHandle thread_handle);
 
   // Detaches and releases the thread handle. The thread is no longer joinable
-  // and |thread_handle| is invalidated after this call.
+  // and `thread_handle` is invalidated after this call.
   static void Detach(PlatformThreadHandle thread_handle);
 
-  // Returns true if SetCurrentThreadPriority() should be able to increase the
-  // priority of a thread to |priority|.
-  static bool CanIncreaseThreadPriority(ThreadPriority priority);
+  // Returns true if SetCurrentThreadType() should be able to change the type
+  // of a thread in current process from `from` to `to`.
+  static bool CanChangeThreadType(ThreadType from, ThreadType to);
 
-  // Toggles the current thread's priority at runtime.
-  //
-  // A thread may not be able to raise its priority back up after lowering it if
-  // the process does not have a proper permission, e.g. CAP_SYS_NICE on Linux.
-  // A thread may not be able to lower its priority back down after raising it
-  // to REALTIME_AUDIO.
-  //
-  // This function must not be called from the main thread on Mac. This is to
-  // avoid performance regressions (https://crbug.com/601270).
-  //
-  // Since changing other threads' priority is not permitted in favor of
-  // security, this interface is restricted to change only the current thread
-  // priority (https://crbug.com/399473).
-  static void SetCurrentThreadPriority(ThreadPriority priority);
+  // Declares the type of work running on the current thread. This will affect
+  // things like thread priority and thread QoS (Quality of Service) to the best
+  // of the current platform's abilities.
+  static void SetCurrentThreadType(ThreadType thread_type);
 
-  static ThreadPriority GetCurrentThreadPriority();
+  // Get the last `thread_type` set by SetCurrentThreadType, no matter if the
+  // underlying priority successfully changed or not.
+  static ThreadType GetCurrentThreadType();
 
-#if defined(OS_LINUX)
-  // Toggles a specific thread's priority at runtime. This can be used to
+  // Returns a realtime period provided by `delegate`.
+  static TimeDelta GetRealtimePeriod(Delegate* delegate);
+
+  // Returns the override of task leeway if any.
+  static absl::optional<TimeDelta> GetThreadLeewayOverride();
+
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+  // Sets a delegate which handles thread type changes for this process. This
+  // must be externally synchronized with any call to SetCurrentThreadType.
+  static void SetThreadTypeDelegate(ThreadTypeDelegate* delegate);
+
+  // Toggles a specific thread's type at runtime. This can be used to
   // change the priority of a thread in a different process and will fail
   // if the calling process does not have proper permissions. The
-  // SetCurrentThreadPriority() function above is preferred in favor of
+  // SetCurrentThreadType() function above is preferred in favor of
   // security but on platforms where sandboxed processes are not allowed to
   // change priority this function exists to allow a non-sandboxed process
   // to change the priority of sandboxed threads for improved performance.
   // Warning: Don't use this for a main thread because that will change the
   // whole thread group's (i.e. process) priority.
-  static void SetThreadPriority(PlatformThreadId thread_id,
-                                ThreadPriority priority);
+  static void SetThreadType(PlatformThreadId process_id,
+                            PlatformThreadId thread_id,
+                            ThreadType thread_type);
 #endif
 
- private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
+#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_APPLE)
+  // Signals that the feature list has been initialized which allows to check
+  // the feature's value now and initialize state. This prevents race
+  // conditions where the feature is being checked while it is being
+  // initialized, which can cause a crash.
+  static void InitFeaturesPostFieldTrial();
+#endif
+
+  // Returns the default thread stack size set by chrome. If we do not
+  // explicitly set default size then returns 0.
+  static size_t GetDefaultThreadStackSize();
+
+#if BUILDFLAG(IS_APPLE)
+  // Stores the period value in TLS.
+  static void SetCurrentThreadRealtimePeriodValue(TimeDelta realtime_period);
+#endif
+
+  static ThreadPriorityForTest GetCurrentThreadPriorityForTest();
 };
 
+namespace internal {
+
+void SetCurrentThreadType(ThreadType thread_type,
+                          MessagePumpType pump_type_hint);
+
+void SetCurrentThreadTypeImpl(ThreadType thread_type,
+                              MessagePumpType pump_type_hint);
+
+}  // namespace internal
+
 }  // namespace base
 
 #endif  // BASE_THREADING_PLATFORM_THREAD_H_
diff --git a/base/threading/platform_thread_android.cc b/base/threading/platform_thread_android.cc
index 8605d96..13453e1 100644
--- a/base/threading/platform_thread_android.cc
+++ b/base/threading/platform_thread_android.cc
@@ -1,60 +1,87 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/platform_thread.h"
 
 #include <errno.h>
+#include <stddef.h>
 #include <sys/prctl.h>
-#include <sys/resource.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include "base/android/jni_android.h"
+#include "base/base_jni_headers/ThreadUtils_jni.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/threading/platform_thread_internal_posix.h"
 #include "base/threading/thread_id_name_manager.h"
-#include "jni/ThreadUtils_jni.h"
-#include "starboard/types.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
 
 namespace internal {
 
-// - BACKGROUND corresponds to Android's PRIORITY_BACKGROUND = 10 value and can
+// - kRealtimeAudio corresponds to Android's PRIORITY_AUDIO = -16 value.
+// - kDisplay corresponds to Android's PRIORITY_DISPLAY = -4 value.
+// - kBackground corresponds to Android's PRIORITY_BACKGROUND = 10 value and can
 // result in heavy throttling and force the thread onto a little core on
 // big.LITTLE devices.
-// - DISPLAY corresponds to Android's PRIORITY_DISPLAY = -4 value.
-// - REALTIME_AUDIO corresponds to Android's PRIORITY_AUDIO = -16 value.
-const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
-    {ThreadPriority::BACKGROUND, 10},
-    {ThreadPriority::NORMAL, 0},
-    {ThreadPriority::DISPLAY, -4},
-    {ThreadPriority::REALTIME_AUDIO, -16},
+const ThreadPriorityToNiceValuePairForTest
+    kThreadPriorityToNiceValueMapForTest[5] = {
+        {ThreadPriorityForTest::kRealtimeAudio, -16},
+        {ThreadPriorityForTest::kDisplay, -4},
+        {ThreadPriorityForTest::kNormal, 0},
+        {ThreadPriorityForTest::kUtility, 1},
+        {ThreadPriorityForTest::kBackground, 10},
 };
 
-bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority) {
+// - kBackground corresponds to Android's PRIORITY_BACKGROUND = 10 value and can
+// result in heavy throttling and force the thread onto a little core on
+// big.LITTLE devices.
+// - kUtility corresponds to Android's THREAD_PRIORITY_LESS_FAVORABLE = 1 value.
+// - kCompositing and kDisplayCritical corresponds to Android's PRIORITY_DISPLAY
+// = -4 value.
+// - kRealtimeAudio corresponds to Android's PRIORITY_AUDIO = -16 value.
+const ThreadTypeToNiceValuePair kThreadTypeToNiceValueMap[7] = {
+    {ThreadType::kBackground, 10},       {ThreadType::kUtility, 1},
+    {ThreadType::kResourceEfficient, 0}, {ThreadType::kDefault, 0},
+    {ThreadType::kCompositing, -4},      {ThreadType::kDisplayCritical, -4},
+    {ThreadType::kRealtimeAudio, -16},
+};
+
+bool CanSetThreadTypeToRealtimeAudio() {
+  return true;
+}
+
+bool SetCurrentThreadTypeForPlatform(ThreadType thread_type,
+                                     MessagePumpType pump_type_hint) {
   // On Android, we set the Audio priority through JNI as Audio priority
   // will also allow the process to run while it is backgrounded.
-  if (priority == ThreadPriority::REALTIME_AUDIO) {
+  if (thread_type == ThreadType::kRealtimeAudio) {
     JNIEnv* env = base::android::AttachCurrentThread();
     Java_ThreadUtils_setThreadPriorityAudio(env, PlatformThread::CurrentId());
     return true;
   }
+  // Recent versions of Android (O+) up the priority of the UI thread
+  // automatically.
+  if (thread_type == ThreadType::kCompositing &&
+      pump_type_hint == MessagePumpType::UI &&
+      GetCurrentThreadNiceValue() <=
+          ThreadTypeToNiceValue(ThreadType::kCompositing)) {
+    return true;
+  }
   return false;
 }
 
-bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority) {
-  DCHECK(priority);
-  *priority = ThreadPriority::NORMAL;
+absl::optional<ThreadPriorityForTest>
+GetCurrentThreadPriorityForPlatformForTest() {
   JNIEnv* env = base::android::AttachCurrentThread();
   if (Java_ThreadUtils_isThreadPriorityAudio(
       env, PlatformThread::CurrentId())) {
-    *priority = ThreadPriority::REALTIME_AUDIO;
-    return true;
+    return absl::make_optional(ThreadPriorityForTest::kRealtimeAudio);
   }
-  return false;
+  return absl::nullopt;
 }
 
 }  // namespace internal
diff --git a/base/threading/platform_thread_fuchsia.cc b/base/threading/platform_thread_fuchsia.cc
index be8ac50..fd3ab6dd 100644
--- a/base/threading/platform_thread_fuchsia.cc
+++ b/base/threading/platform_thread_fuchsia.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -8,12 +8,73 @@
 #include <sched.h>
 #include <zircon/syscalls.h>
 
+#include <mutex>
+
+#include <fidl/fuchsia.media/cpp/fidl.h>
+#include <lib/fdio/directory.h>
+#include <lib/sys/cpp/component_context.h>
+
+#include "base/fuchsia/fuchsia_component_connect.h"
+#include "base/fuchsia/fuchsia_logging.h"
+#include "base/fuchsia/scheduler.h"
+#include "base/no_destructor.h"
 #include "base/threading/platform_thread_internal_posix.h"
 #include "base/threading/thread_id_name_manager.h"
-#include "starboard/types.h"
+#include "base/threading/thread_local_storage.h"
 
 namespace base {
 
+namespace {
+
+fidl::SyncClient<fuchsia_media::ProfileProvider> ConnectProfileProvider() {
+  auto profile_provider_client_end =
+      base::fuchsia_component::Connect<fuchsia_media::ProfileProvider>();
+  if (profile_provider_client_end.is_error()) {
+    LOG(ERROR) << base::FidlConnectionErrorMessage(profile_provider_client_end);
+    return {};
+  }
+  return fidl::SyncClient(std::move(profile_provider_client_end.value()));
+}
+
+// Sets the current thread to the given scheduling role, optionally including
+// hints about the workload period and max CPU runtime (capacity * period) in
+// that period.
+// TODO(crbug.com/1365682): Migrate to the new fuchsia.scheduler.ProfileProvider
+// API when available.
+void SetThreadRole(StringPiece role_name,
+                   TimeDelta period = {},
+                   float capacity = 0.0f) {
+  DCHECK_GE(capacity, 0.0);
+  DCHECK_LE(capacity, 1.0);
+
+  static const base::NoDestructor<
+      fidl::SyncClient<fuchsia_media::ProfileProvider>>
+      profile_provider(ConnectProfileProvider());
+
+  if (!profile_provider->is_valid()) {
+    return;
+  }
+
+  zx::thread dup_thread;
+  zx_status_t status =
+      zx::thread::self()->duplicate(ZX_RIGHT_SAME_RIGHTS, &dup_thread);
+  ZX_CHECK(status == ZX_OK, status) << "zx_object_duplicate";
+
+  std::string role_selector{role_name};
+  auto result = (*profile_provider)
+                    ->RegisterHandlerWithCapacity(
+                        {{.thread_handle = std::move(dup_thread),
+                          .name = role_selector,
+                          .period = period.ToZxDuration(),
+                          .capacity = capacity}});
+  if (result.is_error()) {
+    ZX_DLOG(ERROR, result.error_value().status())
+        << "Failed call to RegisterHandlerWithCapacity";
+  }
+}
+
+}  // namespace
+
 void InitThreading() {}
 
 void TerminateOnThread() {}
@@ -32,20 +93,69 @@
 }
 
 // static
-bool PlatformThread::CanIncreaseThreadPriority(ThreadPriority priority) {
-  return false;
+bool PlatformThread::CanChangeThreadType(ThreadType from, ThreadType to) {
+  return from == to || to == ThreadType::kDisplayCritical ||
+         to == ThreadType::kRealtimeAudio;
 }
 
-// static
-void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
-  if (priority != ThreadPriority::NORMAL) {
-    NOTIMPLEMENTED() << "setting ThreadPriority " << static_cast<int>(priority);
+namespace internal {
+
+void SetCurrentThreadTypeImpl(ThreadType thread_type,
+                              MessagePumpType pump_type_hint) {
+  switch (thread_type) {
+    case ThreadType::kDefault:
+      SetThreadRole("chromium.base.threading.default");
+
+      break;
+
+    case ThreadType::kBackground:
+      SetThreadRole("chromium.base.threading.background");
+      break;
+
+    case ThreadType::kUtility:
+      SetThreadRole("chromium.base.threading.utility");
+      break;
+
+    case ThreadType::kResourceEfficient:
+      SetThreadRole("chromium.base.threading.resource-efficient");
+      break;
+
+    case ThreadType::kCompositing:
+      SetThreadRole("chromium.base.threading.compositing",
+                    kDisplaySchedulingPeriod, kDisplaySchedulingCapacity);
+      break;
+
+    case ThreadType::kDisplayCritical:
+      SetThreadRole("chromium.base.threading.display", kDisplaySchedulingPeriod,
+                    kDisplaySchedulingCapacity);
+      break;
+
+    case ThreadType::kRealtimeAudio:
+      SetThreadRole("chromium.base.threading.realtime-audio",
+                    kAudioSchedulingPeriod, kAudioSchedulingCapacity);
+      break;
   }
 }
 
+}  // namespace internal
+
 // static
-ThreadPriority PlatformThread::GetCurrentThreadPriority() {
-  return ThreadPriority::NORMAL;
+ThreadPriorityForTest PlatformThread::GetCurrentThreadPriorityForTest() {
+  // Fuchsia doesn't provide a way to get the current thread's priority.
+  // Use ThreadType stored in TLS as a proxy.
+  const ThreadType thread_type = PlatformThread::GetCurrentThreadType();
+  switch (thread_type) {
+    case ThreadType::kBackground:
+    case ThreadType::kUtility:
+    case ThreadType::kResourceEfficient:
+    case ThreadType::kDefault:
+    case ThreadType::kCompositing:
+      return ThreadPriorityForTest::kNormal;
+    case ThreadType::kDisplayCritical:
+      return ThreadPriorityForTest::kDisplay;
+    case ThreadType::kRealtimeAudio:
+      return ThreadPriorityForTest::kRealtimeAudio;
+  }
 }
 
 }  // namespace base
diff --git a/base/threading/platform_thread_internal_posix.cc b/base/threading/platform_thread_internal_posix.cc
index 378a24d..b7d0bdf 100644
--- a/base/threading/platform_thread_internal_posix.cc
+++ b/base/threading/platform_thread_internal_posix.cc
@@ -1,37 +1,63 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/platform_thread_internal_posix.h"
 
+#include <errno.h>
+#include <sys/resource.h>
+
+#include <ostream>
+
 #include "base/containers/adapters.h"
 #include "base/logging.h"
+#include "base/notreached.h"
 
 namespace base {
 
 namespace internal {
 
-int ThreadPriorityToNiceValue(ThreadPriority priority) {
-  for (const auto& pair : kThreadPriorityToNiceValueMap) {
-    if (pair.priority == priority)
+int ThreadTypeToNiceValue(ThreadType thread_type) {
+  for (const auto& pair : kThreadTypeToNiceValueMap) {
+    if (pair.thread_type == thread_type)
       return pair.nice_value;
   }
-  NOTREACHED() << "Unknown ThreadPriority";
+  NOTREACHED() << "Unknown ThreadType";
   return 0;
 }
 
-ThreadPriority NiceValueToThreadPriority(int nice_value) {
+ThreadPriorityForTest NiceValueToThreadPriorityForTest(int nice_value) {
   // Try to find a priority that best describes |nice_value|. If there isn't
   // an exact match, this method returns the closest priority whose nice value
   // is higher (lower priority) than |nice_value|.
-  for (const auto& pair : Reversed(kThreadPriorityToNiceValueMap)) {
+  for (const auto& pair : kThreadPriorityToNiceValueMapForTest) {
     if (pair.nice_value >= nice_value)
       return pair.priority;
   }
 
   // Reaching here means |nice_value| is more than any of the defined
   // priorities. The lowest priority is suitable in this case.
-  return ThreadPriority::BACKGROUND;
+  return ThreadPriorityForTest::kBackground;
+}
+
+int GetCurrentThreadNiceValue() {
+#if BUILDFLAG(IS_NACL)
+  NOTIMPLEMENTED();
+  return 0;
+#else
+
+  // Need to clear errno before calling getpriority():
+  // http://man7.org/linux/man-pages/man2/getpriority.2.html
+  errno = 0;
+  int nice_value = getpriority(PRIO_PROCESS, 0);
+  if (errno != 0) {
+    DVPLOG(1) << "Failed to get nice value of thread ("
+              << PlatformThread::CurrentId() << ")";
+    return 0;
+  }
+
+  return nice_value;
+#endif
 }
 
 }  // namespace internal
diff --git a/base/threading/platform_thread_internal_posix.h b/base/threading/platform_thread_internal_posix.h
index 5f4a215..120abae 100644
--- a/base/threading/platform_thread_internal_posix.h
+++ b/base/threading/platform_thread_internal_posix.h
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -7,39 +7,66 @@
 
 #include "base/base_export.h"
 #include "base/threading/platform_thread.h"
+#include "build/build_config.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
 
 namespace internal {
 
-struct ThreadPriorityToNiceValuePair {
-  ThreadPriority priority;
+struct ThreadTypeToNiceValuePair {
+  ThreadType thread_type;
   int nice_value;
 };
+
+struct ThreadPriorityToNiceValuePairForTest {
+  ThreadPriorityForTest priority;
+  int nice_value;
+};
+
 // The elements must be listed in the order of increasing priority (lowest
 // priority first), that is, in the order of decreasing nice values (highest
 // nice value first).
-BASE_EXPORT extern
-const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4];
+extern const ThreadTypeToNiceValuePair kThreadTypeToNiceValueMap[7];
+
+// The elements must be listed in the order of decreasing priority (highest
+// priority first), that is, in the order of increasing nice values (lowest nice
+// value first).
+extern const ThreadPriorityToNiceValuePairForTest
+    kThreadPriorityToNiceValueMapForTest[5];
 
 // Returns the nice value matching |priority| based on the platform-specific
-// implementation of kThreadPriorityToNiceValueMap.
-int ThreadPriorityToNiceValue(ThreadPriority priority);
+// implementation of kThreadTypeToNiceValueMap.
+int ThreadTypeToNiceValue(ThreadType thread_type);
 
-// Returns the ThreadPrioirty matching |nice_value| based on the platform-
-// specific implementation of kThreadPriorityToNiceValueMap.
-BASE_EXPORT ThreadPriority NiceValueToThreadPriority(int nice_value);
+// Returns whether SetCurrentThreadTypeForPlatform can set a thread as
+// kRealtimeAudio.
+bool CanSetThreadTypeToRealtimeAudio();
 
 // Allows platform specific tweaks to the generic POSIX solution for
-// SetCurrentThreadPriority. Returns true if the platform-specific
-// implementation handled this |priority| change, false if the generic
+// SetCurrentThreadType(). Returns true if the platform-specific
+// implementation handled this |thread_type| change, false if the generic
 // implementation should instead proceed.
-bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority);
+bool SetCurrentThreadTypeForPlatform(ThreadType thread_type,
+                                     MessagePumpType pump_type_hint);
 
-// Returns true if there is a platform-specific ThreadPriority set on the
-// current thread (and returns the actual ThreadPriority via |priority|).
-// Returns false otherwise, leaving |priority| untouched.
-bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority);
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+// Current thread id is cached in thread local storage for performance reasons.
+// In some rare cases it's important to invalidate that cache explicitly (e.g.
+// after going through clone() syscall which does not call pthread_atfork()
+// handlers).
+// This can only be called when the process is single-threaded.
+BASE_EXPORT void InvalidateTidCache();
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
+// Returns the ThreadPrioirtyForTest matching |nice_value| based on the
+// platform-specific implementation of kThreadPriorityToNiceValueMapForTest.
+ThreadPriorityForTest NiceValueToThreadPriorityForTest(int nice_value);
+
+absl::optional<ThreadPriorityForTest>
+GetCurrentThreadPriorityForPlatformForTest();
+
+int GetCurrentThreadNiceValue();
 
 }  // namespace internal
 
diff --git a/base/threading/platform_thread_linux.cc b/base/threading/platform_thread_linux.cc
index d1c6a5c..b365237 100644
--- a/base/threading/platform_thread_linux.cc
+++ b/base/threading/platform_thread_linux.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -6,41 +6,163 @@
 
 #include <errno.h>
 #include <sched.h>
+#include <stddef.h>
+#include <cstdint>
+#include <atomic>
 
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/feature_list.h"
 #include "base/files/file_util.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/notreached.h"
+#include "base/process/internal_linux.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/threading/platform_thread_internal_posix.h"
 #include "base/threading/thread_id_name_manager.h"
+#include "base/threading/thread_type_delegate.h"
 #include "build/build_config.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
-#if !defined(OS_NACL) && !defined(OS_AIX)
+#if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_AIX)
 #include <pthread.h>
 #include <sys/prctl.h>
 #include <sys/resource.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
-
-#include "starboard/types.h"
 #endif
 
 namespace base {
+
+#if BUILDFLAG(IS_CHROMEOS)
+BASE_FEATURE(kSchedUtilHints,
+             "SchedUtilHints",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+#endif
+
 namespace {
-#if !defined(OS_NACL)
+
+#if !BUILDFLAG(IS_NACL)
+ThreadTypeDelegate* g_thread_type_delegate = nullptr;
+#endif
+
+#if BUILDFLAG(IS_CHROMEOS)
+std::atomic<bool> g_use_sched_util(true);
+std::atomic<bool> g_scheduler_hints_adjusted(false);
+
+// When a device doesn't specify uclamp values via chrome switches,
+// default boosting for urgent tasks is hardcoded here as 20%.
+// Higher values can lead to higher power consumption thus this value
+// is chosen conservatively where it does not show noticeable
+// power usage increased from several perf/power tests.
+const int kSchedulerBoostDef = 20;
+const int kSchedulerLimitDef = 100;
+const bool kSchedulerUseLatencyTuneDef = true;
+
+int g_scheduler_boost_adj;
+int g_scheduler_limit_adj;
+bool g_scheduler_use_latency_tune_adj;
+
+#if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_AIX)
+
+// Defined by linux uclamp ABI of sched_setattr().
+const uint32_t kSchedulerUclampMin = 0;
+const uint32_t kSchedulerUclampMax = 1024;
+
+// sched_attr is used to set scheduler attributes for Linux. It is not a POSIX
+// struct and glibc does not expose it.
+struct sched_attr {
+  uint32_t size;
+
+  uint32_t sched_policy;
+  uint64_t sched_flags;
+
+  /* SCHED_NORMAL, SCHED_BATCH */
+  __s32 sched_nice;
+
+  /* SCHED_FIFO, SCHED_RR */
+  uint32_t sched_priority;
+
+  /* SCHED_DEADLINE */
+  uint64_t sched_runtime;
+  uint64_t sched_deadline;
+  uint64_t sched_period;
+
+  /* Utilization hints */
+  uint32_t sched_util_min;
+  uint32_t sched_util_max;
+};
+
+#if !defined(__NR_sched_setattr)
+#if defined(__x86_64__)
+#define __NR_sched_setattr 314
+#define __NR_sched_getattr 315
+#elif defined(__i386__)
+#define __NR_sched_setattr 351
+#define __NR_sched_getattr 352
+#elif defined(__arm__)
+#define __NR_sched_setattr 380
+#define __NR_sched_getattr 381
+#elif defined(__aarch64__)
+#define __NR_sched_setattr 274
+#define __NR_sched_getattr 275
+#else
+#error "We don't have an __NR_sched_setattr for this architecture."
+#endif
+#endif
+
+#if !defined(SCHED_FLAG_UTIL_CLAMP_MIN)
+#define SCHED_FLAG_UTIL_CLAMP_MIN 0x20
+#endif
+
+#if !defined(SCHED_FLAG_UTIL_CLAMP_MAX)
+#define SCHED_FLAG_UTIL_CLAMP_MAX 0x40
+#endif
+
+long sched_getattr(pid_t pid,
+                   const struct sched_attr* attr,
+                   unsigned int size,
+                   unsigned int flags) {
+  return syscall(__NR_sched_getattr, pid, attr, size, flags);
+}
+
+long sched_setattr(pid_t pid,
+                   const struct sched_attr* attr,
+                   unsigned int flags) {
+  return syscall(__NR_sched_setattr, pid, attr, flags);
+}
+#endif  // !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_AIX)
+#endif  // BUILDFLAG(IS_CHROMEOS)
+
+#if !BUILDFLAG(IS_NACL)
 const FilePath::CharType kCgroupDirectory[] =
     FILE_PATH_LITERAL("/sys/fs/cgroup");
 
-FilePath ThreadPriorityToCgroupDirectory(const FilePath& cgroup_filepath,
-                                         ThreadPriority priority) {
-  switch (priority) {
-    case ThreadPriority::NORMAL:
-      return cgroup_filepath;
-    case ThreadPriority::BACKGROUND:
+FilePath ThreadTypeToCgroupDirectory(const FilePath& cgroup_filepath,
+                                     ThreadType thread_type) {
+  switch (thread_type) {
+    case ThreadType::kBackground:
+    case ThreadType::kUtility:
+    case ThreadType::kResourceEfficient:
       return cgroup_filepath.Append(FILE_PATH_LITERAL("non-urgent"));
-    case ThreadPriority::DISPLAY:
-    case ThreadPriority::REALTIME_AUDIO:
+    case ThreadType::kDefault:
+      return cgroup_filepath;
+    case ThreadType::kCompositing:
+#if BUILDFLAG(IS_CHROMEOS)
+      // On ChromeOS, kCompositing is also considered urgent.
+      return cgroup_filepath.Append(FILE_PATH_LITERAL("urgent"));
+#else
+      // TODO(1329208): Experiment with bringing IS_LINUX inline with
+      // IS_CHROMEOS.
+      return cgroup_filepath;
+#endif
+    case ThreadType::kDisplayCritical:
+    case ThreadType::kRealtimeAudio:
       return cgroup_filepath.Append(FILE_PATH_LITERAL("urgent"));
   }
   NOTREACHED();
@@ -50,19 +172,21 @@
 void SetThreadCgroup(PlatformThreadId thread_id,
                      const FilePath& cgroup_directory) {
   FilePath tasks_filepath = cgroup_directory.Append(FILE_PATH_LITERAL("tasks"));
-  std::string tid = IntToString(thread_id);
-  int bytes_written = WriteFile(tasks_filepath, tid.c_str(), tid.size());
-  if (bytes_written != static_cast<int>(tid.size())) {
+  std::string tid = NumberToString(thread_id);
+  // TODO(crbug.com/1333521): Remove cast.
+  const int size = static_cast<int>(tid.size());
+  int bytes_written = WriteFile(tasks_filepath, tid.data(), size);
+  if (bytes_written != size) {
     DVLOG(1) << "Failed to add " << tid << " to " << tasks_filepath.value();
   }
 }
 
-void SetThreadCgroupForThreadPriority(PlatformThreadId thread_id,
-                                      const FilePath& cgroup_filepath,
-                                      ThreadPriority priority) {
+void SetThreadCgroupForThreadType(PlatformThreadId thread_id,
+                                  const FilePath& cgroup_filepath,
+                                  ThreadType thread_type) {
   // Append "chrome" suffix.
-  FilePath cgroup_directory = ThreadPriorityToCgroupDirectory(
-      cgroup_filepath.Append(FILE_PATH_LITERAL("chrome")), priority);
+  FilePath cgroup_directory = ThreadTypeToCgroupDirectory(
+      cgroup_filepath.Append(FILE_PATH_LITERAL("chrome")), thread_type);
 
   // Silently ignore request if cgroup directory doesn't exist.
   if (!DirectoryExists(cgroup_directory))
@@ -71,14 +195,117 @@
   SetThreadCgroup(thread_id, cgroup_directory);
 }
 
-void SetThreadCgroupsForThreadPriority(PlatformThreadId thread_id,
-                                       ThreadPriority priority) {
+#if BUILDFLAG(IS_CHROMEOS)
+// thread_id should always be the value in the root PID namespace (see
+// FindThreadID).
+void SetThreadLatencySensitivity(ProcessId process_id,
+                                 PlatformThreadId thread_id,
+                                 ThreadType thread_type) {
+  struct sched_attr attr;
+  bool is_urgent = false;
+  int boost_percent, limit_percent;
+  int latency_sensitive_urgent;
+
+  // Scheduler boost defaults to true unless disabled.
+  if (!g_use_sched_util.load())
+    return;
+
+  // FieldTrial API can be called only once features were parsed.
+  if (g_scheduler_hints_adjusted.load()) {
+    boost_percent = g_scheduler_boost_adj;
+    limit_percent = g_scheduler_limit_adj;
+    latency_sensitive_urgent = g_scheduler_use_latency_tune_adj;
+  } else {
+    boost_percent = kSchedulerBoostDef;
+    limit_percent = kSchedulerLimitDef;
+    latency_sensitive_urgent = kSchedulerUseLatencyTuneDef;
+  }
+
+  // The thread_id passed in here is either 0 (in which case we ste for current
+  // thread), or is a tid that is not the NS tid but the global one. The
+  // conversion from NS tid to global tid is done by the callers using
+  // FindThreadID().
+  std::string thread_dir;
+  if (thread_id)
+    thread_dir = base::StringPrintf("/proc/%d/task/%d/", process_id, thread_id);
+  else
+    thread_dir = "/proc/thread-self/";
+
+  // Silently ignore request if thread directory doesn't exist.
+  if (!DirectoryExists(FilePath(thread_dir)))
+    return;
+
+  FilePath latency_sensitive_file = FilePath(thread_dir + "latency_sensitive");
+
+  if (!PathExists(latency_sensitive_file))
+    return;
+
+  // Silently ignore if getattr fails due to sandboxing.
+  if (sched_getattr(thread_id, &attr, sizeof(attr), 0) == -1 ||
+      attr.size != sizeof(attr))
+    return;
+
+  switch (thread_type) {
+    case ThreadType::kBackground:
+    case ThreadType::kUtility:
+    case ThreadType::kResourceEfficient:
+    case ThreadType::kDefault:
+      break;
+    case ThreadType::kCompositing:
+    case ThreadType::kDisplayCritical:
+      // Compositing and display critical threads need a boost for consistent 60
+      // fps.
+      [[fallthrough]];
+    case ThreadType::kRealtimeAudio:
+      is_urgent = true;
+      break;
+  }
+
+  if (is_urgent && latency_sensitive_urgent) {
+    PLOG_IF(ERROR, !WriteFile(latency_sensitive_file, "1", 1))
+        << "Failed to write latency file.\n";
+  } else {
+    PLOG_IF(ERROR, !WriteFile(latency_sensitive_file, "0", 1))
+        << "Failed to write latency file.\n";
+  }
+
+  attr.sched_flags |= SCHED_FLAG_UTIL_CLAMP_MIN;
+  attr.sched_flags |= SCHED_FLAG_UTIL_CLAMP_MAX;
+
+  if (is_urgent) {
+    attr.sched_util_min =
+        (saturated_cast<uint32_t>(boost_percent) * kSchedulerUclampMax + 50) /
+        100;
+    attr.sched_util_max = kSchedulerUclampMax;
+  } else {
+    attr.sched_util_min = kSchedulerUclampMin;
+    attr.sched_util_max =
+        (saturated_cast<uint32_t>(limit_percent) * kSchedulerUclampMax + 50) /
+        100;
+  }
+
+  DCHECK_GE(attr.sched_util_min, kSchedulerUclampMin);
+  DCHECK_LE(attr.sched_util_max, kSchedulerUclampMax);
+
+  attr.size = sizeof(struct sched_attr);
+  if (sched_setattr(thread_id, &attr, 0) == -1) {
+    // We log it as an error because, if the PathExists above succeeded, we
+    // expect this syscall to also work since the kernel is new'ish.
+    PLOG_IF(ERROR, errno != E2BIG)
+        << "Failed to set sched_util_min, performance may be effected.\n";
+  }
+}
+#endif
+
+void SetThreadCgroupsForThreadType(PlatformThreadId thread_id,
+                                   ThreadType thread_type) {
   FilePath cgroup_filepath(kCgroupDirectory);
-  SetThreadCgroupForThreadPriority(
-      thread_id, cgroup_filepath.Append(FILE_PATH_LITERAL("cpuset")), priority);
-  SetThreadCgroupForThreadPriority(
+  SetThreadCgroupForThreadType(
+      thread_id, cgroup_filepath.Append(FILE_PATH_LITERAL("cpuset")),
+      thread_type);
+  SetThreadCgroupForThreadType(
       thread_id, cgroup_filepath.Append(FILE_PATH_LITERAL("schedtune")),
-      priority);
+      thread_type);
 }
 #endif
 }  // namespace
@@ -86,41 +313,82 @@
 namespace internal {
 
 namespace {
-#if !defined(OS_NACL)
+#if !BUILDFLAG(IS_NACL)
 const struct sched_param kRealTimePrio = {8};
 #endif
 }  // namespace
 
-const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
-    {ThreadPriority::BACKGROUND, 10},
-    {ThreadPriority::NORMAL, 0},
-    {ThreadPriority::DISPLAY, -8},
-    {ThreadPriority::REALTIME_AUDIO, -10},
+const ThreadPriorityToNiceValuePairForTest
+    kThreadPriorityToNiceValueMapForTest[5] = {
+        {ThreadPriorityForTest::kRealtimeAudio, -10},
+        {ThreadPriorityForTest::kDisplay, -8},
+        {ThreadPriorityForTest::kNormal, 0},
+        {ThreadPriorityForTest::kUtility, 1},
+        {ThreadPriorityForTest::kBackground, 10},
 };
 
-bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority) {
-#if !defined(OS_NACL)
-  SetThreadCgroupsForThreadPriority(PlatformThread::CurrentId(), priority);
-  return priority == ThreadPriority::REALTIME_AUDIO &&
+const ThreadTypeToNiceValuePair kThreadTypeToNiceValueMap[7] = {
+    {ThreadType::kBackground, 10},       {ThreadType::kUtility, 1},
+    {ThreadType::kResourceEfficient, 0}, {ThreadType::kDefault, 0},
+#if BUILDFLAG(IS_CHROMEOS)
+    {ThreadType::kCompositing, -8},
+#else
+    // TODO(1329208): Experiment with bringing IS_LINUX inline with IS_CHROMEOS.
+    {ThreadType::kCompositing, 0},
+#endif
+    {ThreadType::kDisplayCritical, -8},  {ThreadType::kRealtimeAudio, -10},
+};
+
+bool CanSetThreadTypeToRealtimeAudio() {
+#if !BUILDFLAG(IS_NACL)
+  // A non-zero soft-limit on RLIMIT_RTPRIO is required to be allowed to invoke
+  // pthread_setschedparam in SetCurrentThreadTypeForPlatform().
+  struct rlimit rlim;
+  return getrlimit(RLIMIT_RTPRIO, &rlim) != 0 && rlim.rlim_cur != 0;
+#else
+  return false;
+#endif
+}
+
+bool SetCurrentThreadTypeForPlatform(ThreadType thread_type,
+                                     MessagePumpType pump_type_hint) {
+#if !BUILDFLAG(IS_NACL)
+  const PlatformThreadId tid = PlatformThread::CurrentId();
+
+  if (g_thread_type_delegate &&
+      g_thread_type_delegate->HandleThreadTypeChange(tid, thread_type)) {
+    return true;
+  }
+
+  // For legacy schedtune interface
+  SetThreadCgroupsForThreadType(tid, thread_type);
+
+#if BUILDFLAG(IS_CHROMEOS)
+  // For upstream uclamp interface. We try both legacy (schedtune, as done
+  // earlier) and upstream (uclamp) interfaces, and whichever succeeds wins.
+  SetThreadLatencySensitivity(0 /* ignore */, 0 /* thread-self */, thread_type);
+#endif
+
+  return thread_type == ThreadType::kRealtimeAudio &&
          pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0;
 #else
   return false;
 #endif
 }
 
-bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority) {
-#if !defined(OS_NACL)
+absl::optional<ThreadPriorityForTest>
+GetCurrentThreadPriorityForPlatformForTest() {
+#if !BUILDFLAG(IS_NACL)
   int maybe_sched_rr = 0;
   struct sched_param maybe_realtime_prio = {0};
   if (pthread_getschedparam(pthread_self(), &maybe_sched_rr,
                             &maybe_realtime_prio) == 0 &&
       maybe_sched_rr == SCHED_RR &&
       maybe_realtime_prio.sched_priority == kRealTimePrio.sched_priority) {
-    *priority = ThreadPriority::REALTIME_AUDIO;
-    return true;
+    return absl::make_optional(ThreadPriorityForTest::kRealtimeAudio);
   }
 #endif
-  return false;
+  return absl::nullopt;
 }
 
 }  // namespace internal
@@ -129,7 +397,7 @@
 void PlatformThread::SetName(const std::string& name) {
   ThreadIdNameManager::GetInstance()->SetName(name);
 
-#if !defined(OS_NACL) && !defined(OS_AIX)
+#if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_AIX)
   // On linux we can get the thread names to show up in the debugger by setting
   // the process name for the LWP.  We don't want to do this for the main
   // thread because that would rename the process, causing tools like killall
@@ -146,35 +414,91 @@
   // We expect EPERM failures in sandboxed processes, just ignore those.
   if (err < 0 && errno != EPERM)
     DPLOG(ERROR) << "prctl(PR_SET_NAME)";
-#endif  //  !defined(OS_NACL) && !defined(OS_AIX)
+#endif  //  !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_AIX)
 }
 
-#if !defined(OS_NACL) && !defined(OS_AIX)
+#if !BUILDFLAG(IS_NACL)
 // static
-void PlatformThread::SetThreadPriority(PlatformThreadId thread_id,
-                                       ThreadPriority priority) {
-  // Changing current main threads' priority is not permitted in favor of
-  // security, this interface is restricted to change only non-main thread
-  // priority.
-  CHECK_NE(thread_id, getpid());
+void PlatformThread::SetThreadTypeDelegate(ThreadTypeDelegate* delegate) {
+  // A component cannot override a delegate set by another component, thus
+  // disallow setting a delegate when one already exists.
+  DCHECK(!g_thread_type_delegate || !delegate);
 
-  SetThreadCgroupsForThreadPriority(thread_id, priority);
+  g_thread_type_delegate = delegate;
+}
+#endif
 
-  const int nice_setting = internal::ThreadPriorityToNiceValue(priority);
-  if (setpriority(PRIO_PROCESS, thread_id, nice_setting)) {
+#if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_AIX)
+// static
+void PlatformThread::SetThreadType(ProcessId process_id,
+                                   PlatformThreadId thread_id,
+                                   ThreadType thread_type) {
+  // For legacy schedtune interface
+  SetThreadCgroupsForThreadType(thread_id, thread_type);
+
+#if BUILDFLAG(IS_CHROMEOS)
+  // For upstream uclamp interface. We try both legacy (schedtune, as done
+  // earlier) and upstream (uclamp) interfaces, and whichever succeeds wins.
+  SetThreadLatencySensitivity(process_id, thread_id, thread_type);
+#endif
+
+  const int nice_setting = internal::ThreadTypeToNiceValue(thread_type);
+  if (setpriority(PRIO_PROCESS, static_cast<id_t>(thread_id), nice_setting)) {
     DVPLOG(1) << "Failed to set nice value of thread (" << thread_id << ") to "
               << nice_setting;
   }
 }
-#endif  //  !defined(OS_NACL) && !defined(OS_AIX)
+#endif  //  !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_AIX)
+
+#if BUILDFLAG(IS_CHROMEOS)
+void PlatformThread::InitFeaturesPostFieldTrial() {
+  DCHECK(FeatureList::GetInstance());
+  if (!FeatureList::IsEnabled(kSchedUtilHints)) {
+    g_use_sched_util.store(false);
+    return;
+  }
+
+  int boost_def = kSchedulerBoostDef;
+
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSchedulerBoostUrgent)) {
+    std::string boost_switch_str =
+        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+            switches::kSchedulerBoostUrgent);
+
+    int boost_switch_val;
+    if (!StringToInt(boost_switch_str, &boost_switch_val) ||
+        boost_switch_val < 0 || boost_switch_val > 100) {
+      DVPLOG(1) << "Invalid input for " << switches::kSchedulerBoostUrgent;
+    } else {
+      boost_def = boost_switch_val;
+    }
+  }
+
+  g_scheduler_boost_adj = GetFieldTrialParamByFeatureAsInt(
+      kSchedUtilHints, "BoostUrgent", boost_def);
+  g_scheduler_limit_adj = GetFieldTrialParamByFeatureAsInt(
+      kSchedUtilHints, "LimitNonUrgent", kSchedulerLimitDef);
+  g_scheduler_use_latency_tune_adj = GetFieldTrialParamByFeatureAsBool(
+      kSchedUtilHints, "LatencyTune", kSchedulerUseLatencyTuneDef);
+
+  g_scheduler_hints_adjusted.store(true);
+}
+#endif
 
 void InitThreading() {}
 
 void TerminateOnThread() {}
 
 size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) {
-#if !defined(THREAD_SANITIZER)
+#if !defined(THREAD_SANITIZER) && defined(__GLIBC__)
+  // Generally glibc sets ample default stack sizes, so use the default there.
   return 0;
+#elif !defined(THREAD_SANITIZER)
+  // Other libcs (uclibc, musl, etc) tend to use smaller stacks, often too small
+  // for chromium. Make sure we have enough space to work with here. Note that
+  // for comparison glibc stacks are generally around 8MB.
+  return 2 * (1 << 20);
 #else
   // ThreadSanitizer bloats the stack heavily. Evidence has been that the
   // default stack size isn't enough for some browser tests.
diff --git a/base/threading/platform_thread_mac.mm b/base/threading/platform_thread_mac.mm
index c470ce0..fa192b7 100644
--- a/base/threading/platform_thread_mac.mm
+++ b/base/threading/platform_thread_mac.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -8,22 +8,30 @@
 #include <mach/mach.h>
 #include <mach/mach_time.h>
 #include <mach/thread_policy.h>
+#include <mach/thread_switch.h>
 #include <stddef.h>
 #include <sys/resource.h>
 
 #include <algorithm>
+#include <atomic>
 
+#include "base/feature_list.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
+#include "base/mac/mac_util.h"
 #include "base/mac/mach_logging.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/threading/thread_id_name_manager.h"
+#include "base/threading/threading_features.h"
+#include "build/blink_buildflags.h"
 #include "build/build_config.h"
 
 namespace base {
 
 namespace {
-NSString* const kThreadPriorityKey = @"CrThreadPriorityKey";
+NSString* const kThreadPriorityForTestKey = @"CrThreadPriorityForTestKey";
+NSString* const kRealtimePeriodNsKey = @"CrRealtimePeriodNsKey";
 }  // namespace
 
 // If Cocoa is to be used on more than one thread, it must know that the
@@ -47,6 +55,21 @@
   }
 }
 
+TimeDelta PlatformThread::Delegate::GetRealtimePeriod() {
+  return TimeDelta();
+}
+
+// static
+void PlatformThread::YieldCurrentThread() {
+  // Don't use sched_yield(), as it can lead to 10ms delays.
+  //
+  // This only depresses the thread priority for 1ms, which is more in line
+  // with what calling code likely wants. See this bug in webkit for context:
+  // https://bugs.webkit.org/show_bug.cgi?id=204871
+  mach_msg_timeout_t timeout_ms = 1;
+  thread_switch(MACH_PORT_NULL, SWITCH_OPTION_DEPRESS, timeout_ms);
+}
+
 // static
 void PlatformThread::SetName(const std::string& name) {
   ThreadIdNameManager::GetInstance()->SetName(name);
@@ -60,47 +83,126 @@
   pthread_setname_np(shortened_name.c_str());
 }
 
+// Whether optimized realt-time thread config should be used for audio.
+BASE_FEATURE(kOptimizedRealtimeThreadingMac,
+             "OptimizedRealtimeThreadingMac",
+#if BUILDFLAG(IS_MAC)
+             FEATURE_ENABLED_BY_DEFAULT
+#else
+             FEATURE_DISABLED_BY_DEFAULT
+#endif
+);
+
 namespace {
 
-// Enables time-contraint policy and priority suitable for low-latency,
-// glitch-resistant audio.
-void SetPriorityRealtimeAudio() {
-  // Increase thread priority to real-time.
+bool IsOptimizedRealtimeThreadingMacEnabled() {
+#if BUILDFLAG(IS_MAC)
+  // There is some platform bug on 10.14.
+  if (mac::IsOS10_14())
+    return false;
+#endif
 
-  // Please note that the thread_policy_set() calls may fail in
-  // rare cases if the kernel decides the system is under heavy load
-  // and is unable to handle boosting the thread priority.
-  // In these cases we just return early and go on with life.
+  return FeatureList::IsEnabled(kOptimizedRealtimeThreadingMac);
+}
 
-  mach_port_t mach_thread_id =
-      pthread_mach_thread_np(PlatformThread::CurrentHandle().platform_handle());
+}  // namespace
 
-  // Make thread fixed priority.
-  thread_extended_policy_data_t policy;
-  policy.timeshare = 0;  // Set to 1 for a non-fixed thread.
-  kern_return_t result =
-      thread_policy_set(mach_thread_id,
-                        THREAD_EXTENDED_POLICY,
-                        reinterpret_cast<thread_policy_t>(&policy),
-                        THREAD_EXTENDED_POLICY_COUNT);
-  if (result != KERN_SUCCESS) {
-    MACH_DVLOG(1, result) << "thread_policy_set";
-    return;
+// Fine-tuning optimized realt-time thread config:
+// Whether or not the thread should be preeptible.
+const FeatureParam<bool> kOptimizedRealtimeThreadingMacPreemptible{
+    &kOptimizedRealtimeThreadingMac, "preemptible", true};
+// Portion of the time quantum the thread is expected to be busy, (0, 1].
+const FeatureParam<double> kOptimizedRealtimeThreadingMacBusy{
+    &kOptimizedRealtimeThreadingMac, "busy", 0.5};
+// Maximum portion of the time quantum the thread is expected to be busy,
+// (kOptimizedRealtimeThreadingMacBusy, 1].
+const FeatureParam<double> kOptimizedRealtimeThreadingMacBusyLimit{
+    &kOptimizedRealtimeThreadingMac, "busy_limit", 1.0};
+
+namespace {
+
+struct TimeConstraints {
+  bool preemptible{kOptimizedRealtimeThreadingMacPreemptible.default_value};
+  double busy{kOptimizedRealtimeThreadingMacBusy.default_value};
+  double busy_limit{kOptimizedRealtimeThreadingMacBusyLimit.default_value};
+
+  static TimeConstraints ReadFromFeatureParams() {
+    double busy_limit = kOptimizedRealtimeThreadingMacBusyLimit.Get();
+    return TimeConstraints{
+        kOptimizedRealtimeThreadingMacPreemptible.Get(),
+        std::min(busy_limit, kOptimizedRealtimeThreadingMacBusy.Get()),
+        busy_limit};
+  }
+};
+
+// Use atomics to access FeatureList values when setting up a thread, since
+// there are cases when FeatureList initialization is not synchronized with
+// PlatformThread creation.
+std::atomic<bool> g_use_optimized_realtime_threading(
+    kOptimizedRealtimeThreadingMac.default_state == FEATURE_ENABLED_BY_DEFAULT);
+std::atomic<TimeConstraints> g_time_constraints;
+
+}  // namespace
+
+// static
+void PlatformThread::InitFeaturesPostFieldTrial() {
+  // A DCHECK is triggered on FeatureList initialization if the state of a
+  // feature has been checked before. To avoid triggering this DCHECK in unit
+  // tests that call this before initializing the FeatureList, only check the
+  // state of the feature if the FeatureList is initialized.
+  if (FeatureList::GetInstance()) {
+    g_time_constraints.store(TimeConstraints::ReadFromFeatureParams());
+    g_use_optimized_realtime_threading.store(
+        IsOptimizedRealtimeThreadingMacEnabled());
+  }
+}
+
+// static
+void PlatformThread::SetCurrentThreadRealtimePeriodValue(
+    TimeDelta realtime_period) {
+  if (g_use_optimized_realtime_threading.load()) {
+    [[NSThread currentThread] threadDictionary][kRealtimePeriodNsKey] =
+        @(realtime_period.InNanoseconds());
+  }
+}
+
+namespace {
+
+TimeDelta GetCurrentThreadRealtimePeriod() {
+  NSNumber* period = mac::ObjCCast<NSNumber>(
+      [[NSThread currentThread] threadDictionary][kRealtimePeriodNsKey]);
+
+  return period ? Nanoseconds(period.longLongValue) : TimeDelta();
+}
+
+// Calculates time constrints for THREAD_TIME_CONSTRAINT_POLICY.
+// |realtime_period| is used as a base if it's non-zero.
+// Otherwise we fall back to empirical values.
+thread_time_constraint_policy_data_t GetTimeConstraints(
+    TimeDelta realtime_period) {
+  thread_time_constraint_policy_data_t time_constraints;
+  mach_timebase_info_data_t tb_info;
+  mach_timebase_info(&tb_info);
+
+  if (!realtime_period.is_zero()) {
+    // Limit the lowest value to 2.9 ms we used to have historically. The lower
+    // the period, the more CPU frequency may go up, and we don't want to risk
+    // worsening the thermal situation.
+    uint32_t abs_realtime_period = saturated_cast<uint32_t>(
+        std::max(realtime_period.InNanoseconds(), 2900000LL) *
+        (double(tb_info.denom) / tb_info.numer));
+    TimeConstraints config = g_time_constraints.load();
+    time_constraints.period = abs_realtime_period;
+    time_constraints.constraint = std::min(
+        abs_realtime_period, uint32_t(abs_realtime_period * config.busy_limit));
+    time_constraints.computation =
+        std::min(time_constraints.constraint,
+                 uint32_t(abs_realtime_period * config.busy));
+    time_constraints.preemptible = config.preemptible ? YES : NO;
+    return time_constraints;
   }
 
-  // Set to relatively high priority.
-  thread_precedence_policy_data_t precedence;
-  precedence.importance = 63;
-  result = thread_policy_set(mach_thread_id,
-                             THREAD_PRECEDENCE_POLICY,
-                             reinterpret_cast<thread_policy_t>(&precedence),
-                             THREAD_PRECEDENCE_POLICY_COUNT);
-  if (result != KERN_SUCCESS) {
-    MACH_DVLOG(1, result) << "thread_policy_set";
-    return;
-  }
-
-  // Most important, set real-time constraints.
+  // Empirical configuration.
 
   // Define the guaranteed and max fraction of time for the audio thread.
   // These "duty cycle" values can range from 0 to 1.  A value of 0.5
@@ -124,84 +226,150 @@
 
   // Get the conversion factor from milliseconds to absolute time
   // which is what the time-constraints call needs.
-  mach_timebase_info_data_t tb_info;
-  mach_timebase_info(&tb_info);
-  double ms_to_abs_time =
-      (static_cast<double>(tb_info.denom) / tb_info.numer) * 1000000;
+  double ms_to_abs_time = double(tb_info.denom) / tb_info.numer * 1000000;
 
-  thread_time_constraint_policy_data_t time_constraints;
   time_constraints.period = kTimeQuantum * ms_to_abs_time;
   time_constraints.computation = kAudioTimeNeeded * ms_to_abs_time;
   time_constraints.constraint = kMaxTimeAllowed * ms_to_abs_time;
   time_constraints.preemptible = 0;
+  return time_constraints;
+}
+
+// Enables time-contraint policy and priority suitable for low-latency,
+// glitch-resistant audio.
+void SetPriorityRealtimeAudio(TimeDelta realtime_period) {
+  // Increase thread priority to real-time.
+
+  // Please note that the thread_policy_set() calls may fail in
+  // rare cases if the kernel decides the system is under heavy load
+  // and is unable to handle boosting the thread priority.
+  // In these cases we just return early and go on with life.
+
+  mach_port_t mach_thread_id =
+      pthread_mach_thread_np(PlatformThread::CurrentHandle().platform_handle());
+
+  // Make thread fixed priority.
+  thread_extended_policy_data_t policy;
+  policy.timeshare = 0;  // Set to 1 for a non-fixed thread.
+  kern_return_t result = thread_policy_set(
+      mach_thread_id, THREAD_EXTENDED_POLICY,
+      reinterpret_cast<thread_policy_t>(&policy), THREAD_EXTENDED_POLICY_COUNT);
+  if (result != KERN_SUCCESS) {
+    MACH_DVLOG(1, result) << "thread_policy_set";
+    return;
+  }
+
+  // Set to relatively high priority.
+  thread_precedence_policy_data_t precedence;
+  precedence.importance = 63;
+  result = thread_policy_set(mach_thread_id, THREAD_PRECEDENCE_POLICY,
+                             reinterpret_cast<thread_policy_t>(&precedence),
+                             THREAD_PRECEDENCE_POLICY_COUNT);
+  if (result != KERN_SUCCESS) {
+    MACH_DVLOG(1, result) << "thread_policy_set";
+    return;
+  }
+
+  // Most important, set real-time constraints.
+
+  thread_time_constraint_policy_data_t time_constraints =
+      GetTimeConstraints(realtime_period);
 
   result =
-      thread_policy_set(mach_thread_id,
-                        THREAD_TIME_CONSTRAINT_POLICY,
+      thread_policy_set(mach_thread_id, THREAD_TIME_CONSTRAINT_POLICY,
                         reinterpret_cast<thread_policy_t>(&time_constraints),
                         THREAD_TIME_CONSTRAINT_POLICY_COUNT);
   MACH_DVLOG_IF(1, result != KERN_SUCCESS, result) << "thread_policy_set";
-
   return;
 }
 
 }  // anonymous namespace
 
 // static
-bool PlatformThread::CanIncreaseThreadPriority(ThreadPriority priority) {
+bool PlatformThread::CanChangeThreadType(ThreadType from, ThreadType to) {
   return true;
 }
 
-// static
-void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
-  // Changing the priority of the main thread causes performance regressions.
-  // https://crbug.com/601270
-  DCHECK(![[NSThread currentThread] isMainThread]);
+namespace internal {
 
-  switch (priority) {
-    case ThreadPriority::BACKGROUND:
-      [[NSThread currentThread] setThreadPriority:0];
+void SetCurrentThreadTypeImpl(ThreadType thread_type,
+                              MessagePumpType pump_type_hint) {
+  // Changing the priority of the main thread causes performance
+  // regressions. https://crbug.com/601270
+  // TODO(1280764): Remove this check. kCompositing is the default on Mac, so
+  // this check is counter intuitive.
+  if ([[NSThread currentThread] isMainThread] &&
+      thread_type >= ThreadType::kCompositing) {
+    DCHECK(thread_type == ThreadType::kDefault ||
+           thread_type == ThreadType::kCompositing);
+    return;
+  }
+
+  ThreadPriorityForTest priority = ThreadPriorityForTest::kNormal;
+  switch (thread_type) {
+    case ThreadType::kBackground:
+      priority = ThreadPriorityForTest::kBackground;
+      pthread_set_qos_class_self_np(QOS_CLASS_BACKGROUND, 0);
       break;
-    case ThreadPriority::NORMAL:
-    case ThreadPriority::DISPLAY:
-      [[NSThread currentThread] setThreadPriority:0.5];
+    case ThreadType::kUtility:
+      priority = ThreadPriorityForTest::kUtility;
+      pthread_set_qos_class_self_np(QOS_CLASS_UTILITY, 0);
       break;
-    case ThreadPriority::REALTIME_AUDIO:
-      SetPriorityRealtimeAudio();
+    case ThreadType::kResourceEfficient:
+      priority = ThreadPriorityForTest::kUtility;
+      pthread_set_qos_class_self_np(QOS_CLASS_UTILITY, 0);
+      break;
+    case ThreadType::kDefault:
+      // TODO(1329208): Experiment with prioritizing kCompositing on Mac like on
+      // other platforms.
+      [[fallthrough]];
+    case ThreadType::kCompositing:
+      priority = ThreadPriorityForTest::kNormal;
+      pthread_set_qos_class_self_np(QOS_CLASS_USER_INITIATED, 0);
+      break;
+    case ThreadType::kDisplayCritical: {
+      priority = ThreadPriorityForTest::kDisplay;
+      pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
+      break;
+    }
+    case ThreadType::kRealtimeAudio:
+      priority = ThreadPriorityForTest::kRealtimeAudio;
+      SetPriorityRealtimeAudio(GetCurrentThreadRealtimePeriod());
       DCHECK_EQ([[NSThread currentThread] threadPriority], 1.0);
       break;
   }
 
-  [[[NSThread currentThread] threadDictionary]
-      setObject:@(static_cast<int>(priority))
-         forKey:kThreadPriorityKey];
+  [[NSThread currentThread] threadDictionary][kThreadPriorityForTestKey] =
+      @(static_cast<int>(priority));
 }
 
+}  // namespace internal
+
 // static
-ThreadPriority PlatformThread::GetCurrentThreadPriority() {
-  NSNumber* priority = base::mac::ObjCCast<NSNumber>([[[NSThread currentThread]
-      threadDictionary] objectForKey:kThreadPriorityKey]);
+ThreadPriorityForTest PlatformThread::GetCurrentThreadPriorityForTest() {
+  NSNumber* priority = base::mac::ObjCCast<NSNumber>(
+      [[NSThread currentThread] threadDictionary][kThreadPriorityForTestKey]);
 
   if (!priority)
-    return ThreadPriority::NORMAL;
+    return ThreadPriorityForTest::kNormal;
 
-  ThreadPriority thread_priority =
-      static_cast<ThreadPriority>(priority.intValue);
-  switch (thread_priority) {
-    case ThreadPriority::BACKGROUND:
-    case ThreadPriority::NORMAL:
-    case ThreadPriority::DISPLAY:
-    case ThreadPriority::REALTIME_AUDIO:
-      return thread_priority;
-    default:
-      NOTREACHED() << "Unknown priority.";
-      return ThreadPriority::NORMAL;
-  }
+  ThreadPriorityForTest thread_priority =
+      static_cast<ThreadPriorityForTest>(priority.intValue);
+  DCHECK_GE(thread_priority, ThreadPriorityForTest::kBackground);
+  DCHECK_LE(thread_priority, ThreadPriorityForTest::kMaxValue);
+  return thread_priority;
 }
 
 size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
+#if BUILDFLAG(USE_BLINK)
+  // For iOS 512kB (the default) isn't sufficient, but using the code
+  // for Mac OS X below will return 8MB. So just be a little more conservative
+  // and return 1MB for now.
+  return 1024 * 1024;
+#else
   return 0;
+#endif
 #else
   // The Mac OS X default for a pthread stack size is 512kB.
   // Libc-594.1.4/pthreads/pthread.c's pthread_attr_init uses
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
index 829d0db..6743b44 100644
--- a/base/threading/platform_thread_posix.cc
+++ b/base/threading/platform_thread_posix.cc
@@ -1,42 +1,53 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/notreached.h"
 #include "base/threading/platform_thread.h"
 
 #include <errno.h>
 #include <pthread.h>
 #include <sched.h>
+#include <stddef.h>
+#include <stdint.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include <memory>
+#include <tuple>
 
-#include "starboard/types.h"
-
-#include "base/debug/activity_tracker.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
+#include "base/compiler_specific.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
+#include "base/memory/raw_ptr.h"
 #include "base/threading/platform_thread_internal_posix.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "base/threading/thread_id_name_manager.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 
-#if !defined(OS_MACOSX) && !defined(OS_FUCHSIA) && !defined(OS_NACL)
+#if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_FUCHSIA) && !BUILDFLAG(IS_NACL)
 #include "base/posix/can_lower_nice_to.h"
 #endif
 
-#if defined(OS_LINUX)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 #include <sys/syscall.h>
+#include <atomic>
 #endif
 
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
 #include <zircon/process.h>
 #else
 #include <sys/resource.h>
 #endif
 
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN)
+#include "base/allocator/partition_allocator/starscan/pcscan.h"
+#include "base/allocator/partition_allocator/starscan/stack/stack.h"
+#endif
+
 namespace base {
 
 void InitThreading();
@@ -46,12 +57,12 @@
 namespace {
 
 struct ThreadParams {
-  ThreadParams()
-      : delegate(nullptr), joinable(false), priority(ThreadPriority::NORMAL) {}
+  ThreadParams() = default;
 
-  PlatformThread::Delegate* delegate;
-  bool joinable;
-  ThreadPriority priority;
+  raw_ptr<PlatformThread::Delegate> delegate = nullptr;
+  bool joinable = false;
+  ThreadType thread_type = ThreadType::kDefault;
+  MessagePumpType message_pump_type = MessagePumpType::DEFAULT;
 };
 
 void* ThreadFunc(void* params) {
@@ -63,14 +74,24 @@
 
     delegate = thread_params->delegate;
     if (!thread_params->joinable)
-      base::ThreadRestrictions::SetSingletonAllowed(false);
+      base::DisallowSingleton();
 
-#if !defined(OS_NACL)
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN)
+    partition_alloc::internal::PCScan::NotifyThreadCreated(
+        partition_alloc::internal::GetStackPointer());
+#endif
+
+#if !BUILDFLAG(IS_NACL)
+#if BUILDFLAG(IS_APPLE)
+    PlatformThread::SetCurrentThreadRealtimePeriodValue(
+        delegate->GetRealtimePeriod());
+#endif
+
     // Threads on linux/android may inherit their priority from the thread
     // where they were created. This explicitly sets the priority of all new
     // threads.
-    PlatformThread::SetCurrentThreadPriority(thread_params->priority);
-#endif
+    PlatformThread::SetCurrentThreadType(thread_params->thread_type);
+#endif  //  !BUILDFLAG(IS_NACL)
   }
 
   ThreadIdNameManager::GetInstance()->RegisterThread(
@@ -83,6 +104,10 @@
       PlatformThread::CurrentHandle().platform_handle(),
       PlatformThread::CurrentId());
 
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN)
+  partition_alloc::internal::PCScan::NotifyThreadDestroyed();
+#endif
+
   base::TerminateOnThread();
   return nullptr;
 }
@@ -91,7 +116,8 @@
                   bool joinable,
                   PlatformThread::Delegate* delegate,
                   PlatformThreadHandle* thread_handle,
-                  ThreadPriority priority) {
+                  ThreadType thread_type,
+                  MessagePumpType message_pump_type) {
   DCHECK(thread_handle);
   base::InitThreading();
 
@@ -113,14 +139,15 @@
   std::unique_ptr<ThreadParams> params(new ThreadParams);
   params->delegate = delegate;
   params->joinable = joinable;
-  params->priority = priority;
+  params->thread_type = thread_type;
+  params->message_pump_type = message_pump_type;
 
   pthread_t handle;
   int err = pthread_create(&handle, &attributes, ThreadFunc, params.get());
   bool success = !err;
   if (success) {
     // ThreadParams should be deleted on the created thread after used.
-    ignore_result(params.release());
+    std::ignore = params.release();
   } else {
     // Value of |handle| is undefined if pthread_create fails.
     handle = 0;
@@ -134,30 +161,109 @@
   return success;
 }
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
+// Store the thread ids in local storage since calling the SWI can be
+// expensive and PlatformThread::CurrentId is used liberally.
+thread_local pid_t g_thread_id = -1;
+
+// A boolean value that indicates that the value stored in |g_thread_id| on the
+// main thread is invalid, because it hasn't been updated since the process
+// forked.
+//
+// This used to work by setting |g_thread_id| to -1 in a pthread_atfork handler.
+// However, when a multithreaded process forks, it is only allowed to call
+// async-signal-safe functions until it calls an exec() syscall. However,
+// accessing TLS may allocate (see crbug.com/1275748), which is not
+// async-signal-safe and therefore causes deadlocks, corruption, and crashes.
+//
+// It's Atomic to placate TSAN.
+std::atomic<bool> g_main_thread_tid_cache_valid = false;
+
+// Tracks whether the current thread is the main thread, and therefore whether
+// |g_main_thread_tid_cache_valid| is relevant for the current thread. This is
+// also updated by PlatformThread::CurrentId().
+thread_local bool g_is_main_thread = true;
+
+class InitAtFork {
+ public:
+  InitAtFork() {
+    pthread_atfork(nullptr, nullptr, internal::InvalidateTidCache);
+  }
+};
+
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
 }  // namespace
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
+namespace internal {
+
+void InvalidateTidCache() {
+  g_main_thread_tid_cache_valid.store(false, std::memory_order_relaxed);
+}
+
+}  // namespace internal
+
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
 // static
 PlatformThreadId PlatformThread::CurrentId() {
   // Pthreads doesn't have the concept of a thread ID, so we have to reach down
   // into the kernel.
-#if defined(OS_MACOSX)
+#if BUILDFLAG(IS_APPLE)
   return pthread_mach_thread_np(pthread_self());
-#elif defined(OS_LINUX)
-  return syscall(__NR_gettid);
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+  // Workaround false-positive MSAN use-of-uninitialized-value on
+  // thread_local storage for loaded libraries:
+  // https://github.com/google/sanitizers/issues/1265
+  MSAN_UNPOISON(&g_thread_id, sizeof(pid_t));
+  MSAN_UNPOISON(&g_is_main_thread, sizeof(bool));
+  static InitAtFork init_at_fork;
+  if (g_thread_id == -1 ||
+      (g_is_main_thread &&
+       !g_main_thread_tid_cache_valid.load(std::memory_order_relaxed))) {
+    // Update the cached tid.
+    g_thread_id = static_cast<pid_t>(syscall(__NR_gettid));
+    // If this is the main thread, we can mark the tid_cache as valid.
+    // Otherwise, stop the current thread from always entering this slow path.
+    if (g_thread_id == getpid()) {
+      g_main_thread_tid_cache_valid.store(true, std::memory_order_relaxed);
+    } else {
+      g_is_main_thread = false;
+    }
+  } else {
+#if DCHECK_IS_ON()
+    if (g_thread_id != syscall(__NR_gettid)) {
+      RAW_LOG(
+          FATAL,
+          "Thread id stored in TLS is different from thread id returned by "
+          "the system. It is likely that the process was forked without going "
+          "through fork().");
+    }
+#endif
+  }
+  return g_thread_id;
+#elif BUILDFLAG(IS_ANDROID)
+  // Note: do not cache the return value inside a thread_local variable on
+  // Android (as above). The reasons are:
+  // - thread_local is slow on Android (goes through emutls)
+  // - gettid() is fast, since its return value is cached in pthread (in the
+  //   thread control block of pthread). See gettid.c in bionic.
   return gettid();
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
   return zx_thread_self();
-#elif defined(OS_SOLARIS) || defined(OS_QNX)
+#elif BUILDFLAG(IS_SOLARIS) || BUILDFLAG(IS_QNX)
   return pthread_self();
-#elif defined(OS_NACL) && defined(__GLIBC__)
+#elif BUILDFLAG(IS_NACL) && defined(__GLIBC__)
   return pthread_self();
-#elif defined(OS_NACL) && !defined(__GLIBC__)
+#elif BUILDFLAG(IS_NACL) && !defined(__GLIBC__)
   // Pointers are 32-bits in NaCl.
   return reinterpret_cast<int32_t>(pthread_self());
-#elif defined(OS_POSIX) && defined(OS_AIX)
+#elif BUILDFLAG(IS_POSIX) && BUILDFLAG(IS_AIX)
   return pthread_self();
-#elif defined(OS_POSIX) && !defined(OS_AIX)
+#elif BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_AIX)
   return reinterpret_cast<int64_t>(pthread_self());
 #endif
 }
@@ -172,10 +278,12 @@
   return PlatformThreadHandle(pthread_self());
 }
 
+#if !BUILDFLAG(IS_APPLE)
 // static
 void PlatformThread::YieldCurrentThread() {
   sched_yield();
 }
+#endif  // !BUILDFLAG(IS_APPLE)
 
 // static
 void PlatformThread::Sleep(TimeDelta duration) {
@@ -184,9 +292,9 @@
   // Break the duration into seconds and nanoseconds.
   // NOTE: TimeDelta's microseconds are int64s while timespec's
   // nanoseconds are longs, so this unpacking must prevent overflow.
-  sleep_time.tv_sec = duration.InSeconds();
-  duration -= TimeDelta::FromSeconds(sleep_time.tv_sec);
-  sleep_time.tv_nsec = duration.InMicroseconds() * 1000;  // nanoseconds
+  sleep_time.tv_sec = static_cast<time_t>(duration.InSeconds());
+  duration -= Seconds(sleep_time.tv_sec);
+  sleep_time.tv_nsec = static_cast<long>(duration.InMicroseconds() * 1000);
 
   while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
     sleep_time = remaining;
@@ -198,39 +306,39 @@
 }
 
 // static
-bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
-                                        PlatformThreadHandle* thread_handle,
-                                        ThreadPriority priority) {
+bool PlatformThread::CreateWithType(size_t stack_size,
+                                    Delegate* delegate,
+                                    PlatformThreadHandle* thread_handle,
+                                    ThreadType thread_type,
+                                    MessagePumpType pump_type_hint) {
   return CreateThread(stack_size, true /* joinable thread */, delegate,
-                      thread_handle, priority);
+                      thread_handle, thread_type, pump_type_hint);
 }
 
 // static
 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
-  return CreateNonJoinableWithPriority(stack_size, delegate,
-                                       ThreadPriority::NORMAL);
+  return CreateNonJoinableWithType(stack_size, delegate, ThreadType::kDefault);
 }
 
 // static
-bool PlatformThread::CreateNonJoinableWithPriority(size_t stack_size,
-                                                   Delegate* delegate,
-                                                   ThreadPriority priority) {
+bool PlatformThread::CreateNonJoinableWithType(size_t stack_size,
+                                               Delegate* delegate,
+                                               ThreadType thread_type,
+                                               MessagePumpType pump_type_hint) {
   PlatformThreadHandle unused;
 
   bool result = CreateThread(stack_size, false /* non-joinable thread */,
-                             delegate, &unused, priority);
+                             delegate, &unused, thread_type, pump_type_hint);
   return result;
 }
 
 // static
 void PlatformThread::Join(PlatformThreadHandle thread_handle) {
-  // Record the event that this thread is blocking upon (for hang diagnosis).
-  base::debug::ScopedThreadJoinActivity thread_activity(&thread_handle);
-
   // Joining another thread may block the current thread for a long time, since
   // the thread referred to by |thread_handle| may still be running long-lived /
   // blocking tasks.
-  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
+  base::internal::ScopedBlockingCallWithBaseSyncPrimitives scoped_blocking_call(
+      FROM_HERE, base::BlockingType::MAY_BLOCK);
   CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), nullptr));
 }
 
@@ -239,26 +347,35 @@
   CHECK_EQ(0, pthread_detach(thread_handle.platform_handle()));
 }
 
-// Mac and Fuchsia have their own Set/GetCurrentThreadPriority()
-// implementations.
-#if !defined(OS_MACOSX) && !defined(OS_FUCHSIA)
+// Mac and Fuchsia have their own SetCurrentThreadType() and
+// GetCurrentThreadPriorityForTest() implementations.
+#if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_FUCHSIA)
 
 // static
-bool PlatformThread::CanIncreaseThreadPriority(ThreadPriority priority) {
-#if defined(OS_NACL)
+bool PlatformThread::CanChangeThreadType(ThreadType from, ThreadType to) {
+#if BUILDFLAG(IS_NACL)
   return false;
 #else
-  return internal::CanLowerNiceTo(
-      internal::ThreadPriorityToNiceValue(priority));
-#endif  // defined(OS_NACL)
+  if (from >= to) {
+    // Decreasing thread priority on POSIX is always allowed.
+    return true;
+  }
+  if (to == ThreadType::kRealtimeAudio) {
+    return internal::CanSetThreadTypeToRealtimeAudio();
+  }
+
+  return internal::CanLowerNiceTo(internal::ThreadTypeToNiceValue(to));
+#endif  // BUILDFLAG(IS_NACL)
 }
 
-// static
-void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
-#if defined(OS_NACL)
+namespace internal {
+
+void SetCurrentThreadTypeImpl(ThreadType thread_type,
+                              MessagePumpType pump_type_hint) {
+#if BUILDFLAG(IS_NACL)
   NOTIMPLEMENTED();
 #else
-  if (internal::SetCurrentThreadPriorityForPlatform(priority))
+  if (internal::SetCurrentThreadTypeForPlatform(thread_type, pump_type_hint))
     return;
 
   // setpriority(2) should change the whole thread group's (i.e. process)
@@ -267,41 +384,41 @@
   // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread
   // attribute". Also, 0 is prefered to the current thread id since it is
   // equivalent but makes sandboxing easier (https://crbug.com/399473).
-  const int nice_setting = internal::ThreadPriorityToNiceValue(priority);
+  const int nice_setting = internal::ThreadTypeToNiceValue(thread_type);
   if (setpriority(PRIO_PROCESS, 0, nice_setting)) {
     DVPLOG(1) << "Failed to set nice value of thread ("
               << PlatformThread::CurrentId() << ") to " << nice_setting;
   }
-#endif  // defined(OS_NACL)
+#endif  // BUILDFLAG(IS_NACL)
 }
 
+}  // namespace internal
+
 // static
-ThreadPriority PlatformThread::GetCurrentThreadPriority() {
-#if defined(OS_NACL)
+ThreadPriorityForTest PlatformThread::GetCurrentThreadPriorityForTest() {
+#if BUILDFLAG(IS_NACL)
   NOTIMPLEMENTED();
-  return ThreadPriority::NORMAL;
+  return ThreadPriorityForTest::kNormal;
 #else
   // Mirrors SetCurrentThreadPriority()'s implementation.
-  ThreadPriority platform_specific_priority;
-  if (internal::GetCurrentThreadPriorityForPlatform(
-          &platform_specific_priority)) {
-    return platform_specific_priority;
-  }
+  auto platform_specific_priority =
+      internal::GetCurrentThreadPriorityForPlatformForTest();  // IN-TEST
+  if (platform_specific_priority)
+    return platform_specific_priority.value();
 
-  // Need to clear errno before calling getpriority():
-  // http://man7.org/linux/man-pages/man2/getpriority.2.html
-  errno = 0;
-  int nice_value = getpriority(PRIO_PROCESS, 0);
-  if (errno != 0) {
-    DVPLOG(1) << "Failed to get nice value of thread ("
-              << PlatformThread::CurrentId() << ")";
-    return ThreadPriority::NORMAL;
-  }
+  int nice_value = internal::GetCurrentThreadNiceValue();
 
-  return internal::NiceValueToThreadPriority(nice_value);
-#endif  // !defined(OS_NACL)
+  return internal::NiceValueToThreadPriorityForTest(nice_value);  // IN-TEST
+#endif  // !BUILDFLAG(IS_NACL)
 }
 
-#endif  // !defined(OS_MACOSX) && !defined(OS_FUCHSIA)
+#endif  // !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_FUCHSIA)
+
+// static
+size_t PlatformThread::GetDefaultThreadStackSize() {
+  pthread_attr_t attributes;
+  pthread_attr_init(&attributes);
+  return base::GetDefaultThreadStackSize(attributes);
+}
 
 }  // namespace base
diff --git a/base/threading/platform_thread_ref.cc b/base/threading/platform_thread_ref.cc
new file mode 100644
index 0000000..2771d59
--- /dev/null
+++ b/base/threading/platform_thread_ref.cc
@@ -0,0 +1,16 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread_ref.h"
+
+#include <ostream>
+
+namespace base {
+
+std::ostream& operator<<(std::ostream& os, const PlatformThreadRef& ref) {
+  os << ref.id_;
+  return os;
+}
+
+}  // namespace base
diff --git a/base/threading/platform_thread_ref.h b/base/threading/platform_thread_ref.h
new file mode 100644
index 0000000..04142c4
--- /dev/null
+++ b/base/threading/platform_thread_ref.h
@@ -0,0 +1,71 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: *DO NOT* use this class directly. base::PlatformThreadRef is a
+// low-level platform-specific abstraction to the OS's threading interface.
+// Instead, consider using a message-loop driven base::Thread, see
+// base/threading/thread.h.
+
+#ifndef BASE_THREADING_PLATFORM_THREAD_REF_H_
+#define BASE_THREADING_PLATFORM_THREAD_REF_H_
+
+#include <iosfwd>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+#if defined(STARBOARD)
+#include <pthread.h>
+#include "starboard/thread.h"
+#elif BUILDFLAG(IS_WIN)
+#include "base/win/windows_types.h"
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
+#include <pthread.h>
+#endif
+
+namespace base {
+
+// Used for thread checking and debugging.
+// Meant to be as fast as possible.
+// These are produced by PlatformThread::CurrentRef(), and used to later
+// check if we are on the same thread or not by using ==. These are safe
+// to copy between threads, but can't be copied to another process as they
+// have no meaning there. Also, the internal identifier can be re-used
+// after a thread dies, so a PlatformThreadRef cannot be reliably used
+// to distinguish a new thread from an old, dead thread.
+class PlatformThreadRef {
+ public:
+#if defined(STARBOARD)
+#if SB_API_VERSION < 16
+  typedef SbThread RefType;
+#else
+  using RefType = pthread_t;
+#endif
+#elif BUILDFLAG(IS_WIN)
+  using RefType = DWORD;
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
+  using RefType = pthread_t;
+#endif
+
+  constexpr PlatformThreadRef() = default;
+  explicit constexpr PlatformThreadRef(RefType id) : id_(id) {}
+
+  bool operator==(PlatformThreadRef other) const { return id_ == other.id_; }
+  bool operator!=(PlatformThreadRef other) const { return id_ != other.id_; }
+
+  bool is_null() const { return id_ == 0; }
+
+ private:
+  friend BASE_EXPORT std::ostream& operator<<(std::ostream& os,
+                                              const PlatformThreadRef& ref);
+
+  RefType id_ = 0;
+};
+
+BASE_EXPORT std::ostream& operator<<(std::ostream& os,
+                                     const PlatformThreadRef& ref);
+
+}  // namespace base
+
+#endif  // BASE_THREADING_PLATFORM_THREAD_REF_H_
diff --git a/base/threading/platform_thread_starboard.cc b/base/threading/platform_thread_starboard.cc
index 4f26ede..594ede6 100644
--- a/base/threading/platform_thread_starboard.cc
+++ b/base/threading/platform_thread_starboard.cc
@@ -14,9 +14,14 @@
 
 #include "base/threading/platform_thread.h"
 
+#include <pthread.h>
+#include <sched.h>
+#include <unistd.h>
+
 #include "base/logging.h"
 #include "base/threading/thread_id_name_manager.h"
 #include "base/threading/thread_restrictions.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/thread.h"
 
 namespace base {
@@ -26,13 +31,24 @@
 struct ThreadParams {
   PlatformThread::Delegate* delegate;
   bool joinable;
+  SbThreadPriority thread_priority;
+  std::string thread_name;
 };
 
 void* ThreadFunc(void* params) {
   ThreadParams* thread_params = static_cast<ThreadParams*>(params);
   PlatformThread::Delegate* delegate = thread_params->delegate;
+
+#if SB_API_VERSION >= 16
+  if (kSbHasThreadPrioritySupport) {
+    SbThreadSetPriority(thread_params->thread_priority);
+  }
+#endif  // SB_API_VERSION >= 16
+  pthread_setname_np(pthread_self(), thread_params->thread_name.c_str());
+
+  absl::optional<ScopedDisallowSingleton> disallow_singleton;
   if (!thread_params->joinable) {
-    base::ThreadRestrictions::SetSingletonAllowed(false);
+    disallow_singleton.emplace();
   }
 
   delete thread_params;
@@ -50,9 +66,49 @@
   return NULL;
 }
 
+#if SB_API_VERSION >= 16
 bool CreateThread(size_t stack_size,
                   SbThreadPriority priority,
-                  SbThreadAffinity affinity,
+                  bool joinable,
+                  const char* name,
+                  PlatformThread::Delegate* delegate,
+                  PlatformThreadHandle* thread_handle) {
+  ThreadParams* params = new ThreadParams;
+  params->delegate = delegate;
+  params->joinable = joinable;
+  params->thread_priority = priority;
+  if (name != nullptr) {
+    params->thread_name = name;
+  }
+
+  pthread_attr_t attr;
+  if (pthread_attr_init(&attr) != 0) {
+    return false;
+  }
+
+  pthread_attr_setstacksize(&attr, stack_size);
+
+  if (!joinable) {
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+  }
+
+  pthread_t thread = 0;
+  pthread_create(&thread, &attr, ThreadFunc, params);
+  pthread_attr_destroy(&attr);
+
+  if (thread != 0) {
+    if (thread_handle) {
+      *thread_handle = PlatformThreadHandle(thread);
+    }
+
+    return true;
+  }
+
+  return false;
+}
+#else
+bool CreateThread(size_t stack_size,
+                  SbThreadPriority priority,
                   bool joinable,
                   const char* name,
                   PlatformThread::Delegate* delegate,
@@ -61,7 +117,7 @@
   params->delegate = delegate;
   params->joinable = joinable;
 
-  SbThread thread = SbThreadCreate(stack_size, priority, affinity, joinable,
+  SbThread thread = SbThreadCreate(stack_size, priority, kSbThreadNoAffinity, joinable,
                                    name, ThreadFunc, params);
   if (SbThreadIsValid(thread)) {
     if (thread_handle) {
@@ -73,9 +129,26 @@
 
   return false;
 }
+#endif  // SB_API_VERSION >= 16
 
-inline SbThreadPriority toSbPriority(ThreadPriority priority) {
-  return static_cast<SbThreadPriority>(priority);
+inline SbThreadPriority toSbPriority(ThreadType priority) {
+  switch (priority) {
+    case ThreadType::kBackground:
+      return kSbThreadPriorityLowest;
+    case ThreadType::kUtility:
+      return kSbThreadPriorityLow;
+    case ThreadType::kResourceEfficient:
+      return kSbThreadPriorityNormal;
+    case ThreadType::kDefault:
+      return kSbThreadNoPriority;
+    case ThreadType::kCompositing:
+      return kSbThreadPriorityHigh;
+    case ThreadType::kDisplayCritical:
+      return kSbThreadPriorityHighest;
+    case ThreadType::kRealtimeAudio:
+      return kSbThreadPriorityRealTime;
+  };
+  NOTREACHED();
 }
 }  // namespace
 
@@ -86,28 +159,39 @@
 
 // static
 PlatformThreadRef PlatformThread::CurrentRef() {
+#if SB_API_VERSION < 16
   return PlatformThreadRef(SbThreadGetCurrent());
+#else
+  return PlatformThreadRef(pthread_self());
+#endif  // SB_API_VERSION < 16
+
 }
 
 // static
 PlatformThreadHandle PlatformThread::CurrentHandle() {
+#if SB_API_VERSION < 16
   return PlatformThreadHandle(SbThreadGetCurrent());
+#else
+  return PlatformThreadHandle(pthread_self());
+#endif  // SB_API_VERSION < 16
 }
 
 // static
 void PlatformThread::YieldCurrentThread() {
-  SbThreadYield();
+  sched_yield();
 }
 
 // static
 void PlatformThread::Sleep(TimeDelta duration) {
-  SbThreadSleep(duration.InMicroseconds());
+  usleep(duration.InMicroseconds());
 }
 
 // static
 void PlatformThread::SetName(const std::string& name) {
   ThreadIdNameManager::GetInstance()->SetName(name);
-  SbThreadSetName(name.c_str());
+
+  std::string buffer(name, 0, kSbMaxThreadNameLength - 1);
+  pthread_setname_np(pthread_self(), buffer.c_str());
 }
 
 // static
@@ -116,20 +200,22 @@
 }
 
 // static
-bool PlatformThread::CreateWithPriority(size_t stack_size,
+bool PlatformThread::CreateWithType(size_t stack_size,
                                         Delegate* delegate,
                                         PlatformThreadHandle* thread_handle,
-                                        ThreadPriority priority) {
-  return CreateThread(stack_size, toSbPriority(priority), kSbThreadNoAffinity,
+                                        ThreadType priority,
+                                        MessagePumpType /* pump_type_hint */) {
+  return CreateThread(stack_size, toSbPriority(priority),
                       true /* joinable thread */, NULL, delegate,
                       thread_handle);
 }
 
 // static
-bool PlatformThread::CreateNonJoinableWithPriority(size_t stack_size,
+bool PlatformThread::CreateNonJoinableWithType(size_t stack_size,
                                                    Delegate* delegate,
-                                                   ThreadPriority priority) {
-  return CreateThread(stack_size, toSbPriority(priority), kSbThreadNoAffinity,
+                                                   ThreadType priority,
+                                                   MessagePumpType /* pump_type_hint */) {
+  return CreateThread(stack_size, toSbPriority(priority),
                       false /* joinable thread */, NULL, delegate, NULL);
 }
 
@@ -138,26 +224,39 @@
   // Joining another thread may block the current thread for a long time, since
   // the thread referred to by |thread_handle| may still be running long-lived /
   // blocking tasks.
-  AssertBlockingAllowed();
+  internal::AssertBlockingAllowed();
+#if SB_API_VERSION < 16
   SbThreadJoin(thread_handle.platform_handle(), NULL);
+#else
+  pthread_join(thread_handle.platform_handle(), NULL);
+#endif  // SB_API_VERSION < 16
 }
 
 void PlatformThread::Detach(PlatformThreadHandle thread_handle) {
+#if SB_API_VERSION < 16
   SbThreadDetach(thread_handle.platform_handle());
+#else
+  pthread_detach(thread_handle.platform_handle());
+#endif  // SB_API_VERSION < 16
 }
 
-void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
+void internal::SetCurrentThreadTypeImpl(ThreadType /* thread_type */, MessagePumpType /*pump_type_hint*/) {
   NOTIMPLEMENTED();
 }
 
-ThreadPriority PlatformThread::GetCurrentThreadPriority() {
-  NOTIMPLEMENTED();
-  return ThreadPriority::NORMAL;
-}
-
 // static
-bool PlatformThread::CanIncreaseThreadPriority(ThreadPriority priority) {
+bool PlatformThread::CanChangeThreadType(ThreadType /* from */, ThreadType /* to */) {
   return false;
 }
 
+size_t PlatformThread::GetDefaultThreadStackSize() {
+  return 0;
+}
+
+// static
+ThreadPriorityForTest PlatformThread::GetCurrentThreadPriorityForTest() {
+  NOTIMPLEMENTED();
+  return ThreadPriorityForTest::kNormal;
+}
+
 }  // namespace base
diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc
index 9e530e4..e504bcf 100644
--- a/base/threading/platform_thread_unittest.cc
+++ b/base/threading/platform_thread_unittest.cc
@@ -1,21 +1,43 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/threading/platform_thread.h"
+
+#include <stddef.h>
+
 #include "base/compiler_specific.h"
-#include "base/macros.h"
+#include "base/process/process.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/scoped_feature_list.h"
-#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "base/threading/threading_features.h"
+#include "build/blink_buildflags.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
 #include "base/threading/platform_thread_internal_posix.h"
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
 #include <windows.h>
 #include "base/threading/platform_thread_win.h"
-#include "starboard/types.h"
+#endif
+
+#if BUILDFLAG(IS_APPLE)
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <mach/thread_policy.h>
+#include "base/mac/mac_util.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/time/time.h"
+#endif
+
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#include <pthread.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
 #endif
 
 namespace base {
@@ -29,14 +51,15 @@
   TrivialThread() : run_event_(WaitableEvent::ResetPolicy::MANUAL,
                                WaitableEvent::InitialState::NOT_SIGNALED) {}
 
+  TrivialThread(const TrivialThread&) = delete;
+  TrivialThread& operator=(const TrivialThread&) = delete;
+
   void ThreadMain() override { run_event_.Signal(); }
 
   WaitableEvent& run_event() { return run_event_; }
 
  private:
   WaitableEvent run_event_;
-
-  DISALLOW_COPY_AND_ASSIGN(TrivialThread);
 };
 
 }  // namespace
@@ -53,16 +76,16 @@
 
 TEST(PlatformThreadTest, TrivialJoinTimesTen) {
   TrivialThread thread[10];
-  PlatformThreadHandle handle[arraysize(thread)];
+  PlatformThreadHandle handle[std::size(thread)];
 
-  for (size_t n = 0; n < arraysize(thread); n++)
-    ASSERT_FALSE(thread[n].run_event().IsSignaled());
-  for (size_t n = 0; n < arraysize(thread); n++)
+  for (auto& n : thread)
+    ASSERT_FALSE(n.run_event().IsSignaled());
+  for (size_t n = 0; n < std::size(thread); n++)
     ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
-  for (size_t n = 0; n < arraysize(thread); n++)
-    PlatformThread::Join(handle[n]);
-  for (size_t n = 0; n < arraysize(thread); n++)
-    ASSERT_TRUE(thread[n].run_event().IsSignaled());
+  for (auto n : handle)
+    PlatformThread::Join(n);
+  for (auto& n : thread)
+    ASSERT_TRUE(n.run_event().IsSignaled());
 }
 
 // The following detach tests are by nature racy. The run_event approximates the
@@ -80,16 +103,16 @@
 
 TEST(PlatformThreadTest, TrivialDetachTimesTen) {
   TrivialThread thread[10];
-  PlatformThreadHandle handle[arraysize(thread)];
+  PlatformThreadHandle handle[std::size(thread)];
 
-  for (size_t n = 0; n < arraysize(thread); n++)
-    ASSERT_FALSE(thread[n].run_event().IsSignaled());
-  for (size_t n = 0; n < arraysize(thread); n++) {
+  for (auto& n : thread)
+    ASSERT_FALSE(n.run_event().IsSignaled());
+  for (size_t n = 0; n < std::size(thread); n++) {
     ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
     PlatformThread::Detach(handle[n]);
   }
-  for (size_t n = 0; n < arraysize(thread); n++)
-    thread[n].run_event().Wait();
+  for (auto& n : thread)
+    n.run_event().Wait();
 }
 
 // Tests of basic thread functions ---------------------------------------------
@@ -105,6 +128,10 @@
         terminate_thread_(WaitableEvent::ResetPolicy::MANUAL,
                           WaitableEvent::InitialState::NOT_SIGNALED),
         done_(false) {}
+
+  FunctionTestThread(const FunctionTestThread&) = delete;
+  FunctionTestThread& operator=(const FunctionTestThread&) = delete;
+
   ~FunctionTestThread() override {
     EXPECT_TRUE(terminate_thread_.IsSignaled())
         << "Need to mark thread for termination and join the underlying thread "
@@ -156,8 +183,6 @@
   mutable WaitableEvent termination_ready_;
   WaitableEvent terminate_thread_;
   bool done_;
-
-  DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
 };
 
 }  // namespace
@@ -186,17 +211,17 @@
   PlatformThreadId main_thread_id = PlatformThread::CurrentId();
 
   FunctionTestThread thread[10];
-  PlatformThreadHandle handle[arraysize(thread)];
+  PlatformThreadHandle handle[std::size(thread)];
 
-  for (size_t n = 0; n < arraysize(thread); n++)
-    ASSERT_FALSE(thread[n].IsRunning());
+  for (const auto& n : thread)
+    ASSERT_FALSE(n.IsRunning());
 
-  for (size_t n = 0; n < arraysize(thread); n++)
+  for (size_t n = 0; n < std::size(thread); n++)
     ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
-  for (size_t n = 0; n < arraysize(thread); n++)
-    thread[n].WaitForTerminationReady();
+  for (auto& n : thread)
+    n.WaitForTerminationReady();
 
-  for (size_t n = 0; n < arraysize(thread); n++) {
+  for (size_t n = 0; n < std::size(thread); n++) {
     ASSERT_TRUE(thread[n].IsRunning());
     EXPECT_NE(thread[n].thread_id(), main_thread_id);
 
@@ -206,158 +231,305 @@
     }
   }
 
-  for (size_t n = 0; n < arraysize(thread); n++)
-    thread[n].MarkForTermination();
-  for (size_t n = 0; n < arraysize(thread); n++)
-    PlatformThread::Join(handle[n]);
-  for (size_t n = 0; n < arraysize(thread); n++)
-    ASSERT_FALSE(thread[n].IsRunning());
+  for (auto& n : thread)
+    n.MarkForTermination();
+  for (auto n : handle)
+    PlatformThread::Join(n);
+  for (const auto& n : thread)
+    ASSERT_FALSE(n.IsRunning());
 
   // Make sure that the thread ID is the same across calls.
   EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
 }
 
-#if !defined(STARBOARD)
 namespace {
 
-class ThreadPriorityTestThread : public FunctionTestThread {
+constexpr ThreadType kAllThreadTypes[] = {
+    ThreadType::kRealtimeAudio,     ThreadType::kDisplayCritical,
+    ThreadType::kCompositing,       ThreadType::kDefault,
+    ThreadType::kResourceEfficient, ThreadType::kUtility,
+    ThreadType::kBackground};
+
+class ThreadTypeTestThread : public FunctionTestThread {
  public:
-  explicit ThreadPriorityTestThread(ThreadPriority from, ThreadPriority to)
+  explicit ThreadTypeTestThread(ThreadType from, ThreadType to)
       : from_(from), to_(to) {}
-  ~ThreadPriorityTestThread() override = default;
+
+  ThreadTypeTestThread(const ThreadTypeTestThread&) = delete;
+  ThreadTypeTestThread& operator=(const ThreadTypeTestThread&) = delete;
+
+  ~ThreadTypeTestThread() override = default;
 
  private:
   void RunTest() override {
-    EXPECT_EQ(PlatformThread::GetCurrentThreadPriority(),
-              ThreadPriority::NORMAL);
-    PlatformThread::SetCurrentThreadPriority(from_);
-    EXPECT_EQ(PlatformThread::GetCurrentThreadPriority(), from_);
-    PlatformThread::SetCurrentThreadPriority(to_);
+    EXPECT_EQ(PlatformThread::GetCurrentThreadType(), ThreadType::kDefault);
+    PlatformThread::SetCurrentThreadType(from_);
+    EXPECT_EQ(PlatformThread::GetCurrentThreadType(), from_);
+    PlatformThread::SetCurrentThreadType(to_);
+    EXPECT_EQ(PlatformThread::GetCurrentThreadType(), to_);
+  }
 
-    if (static_cast<int>(to_) <= static_cast<int>(from_) ||
-        PlatformThread::CanIncreaseThreadPriority(to_)) {
-      EXPECT_EQ(PlatformThread::GetCurrentThreadPriority(), to_);
-    } else {
-      EXPECT_NE(PlatformThread::GetCurrentThreadPriority(), to_);
+  const ThreadType from_;
+  const ThreadType to_;
+};
+
+class ThreadPriorityTestThread : public FunctionTestThread {
+ public:
+  ThreadPriorityTestThread(ThreadType thread_type,
+                           ThreadPriorityForTest priority)
+      : thread_type_(thread_type), priority(priority) {}
+
+ private:
+  void RunTest() override {
+    testing::Message message;
+    message << "thread_type: " << static_cast<int>(thread_type_);
+    SCOPED_TRACE(message);
+
+    EXPECT_EQ(PlatformThread::GetCurrentThreadType(), ThreadType::kDefault);
+    PlatformThread::SetCurrentThreadType(thread_type_);
+    EXPECT_EQ(PlatformThread::GetCurrentThreadType(), thread_type_);
+    if (PlatformThread::CanChangeThreadType(ThreadType::kDefault,
+                                            thread_type_)) {
+      EXPECT_EQ(PlatformThread::GetCurrentThreadPriorityForTest(), priority);
     }
   }
 
-  const ThreadPriority from_;
-  const ThreadPriority to_;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadPriorityTestThread);
+  const ThreadType thread_type_;
+  const ThreadPriorityForTest priority;
 };
 
-void TestSetCurrentThreadPriority() {
-  constexpr ThreadPriority kAllThreadPriorities[] = {
-      ThreadPriority::REALTIME_AUDIO, ThreadPriority::DISPLAY,
-      ThreadPriority::NORMAL, ThreadPriority::BACKGROUND};
-
-  for (auto from : kAllThreadPriorities) {
-    if (static_cast<int>(from) <= static_cast<int>(ThreadPriority::NORMAL) ||
-        PlatformThread::CanIncreaseThreadPriority(from)) {
-      for (auto to : kAllThreadPriorities) {
-        ThreadPriorityTestThread thread(from, to);
-        PlatformThreadHandle handle;
-
-        ASSERT_FALSE(thread.IsRunning());
-        ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
-        thread.WaitForTerminationReady();
-        ASSERT_TRUE(thread.IsRunning());
-
-        thread.MarkForTermination();
-        PlatformThread::Join(handle);
-        ASSERT_FALSE(thread.IsRunning());
-      }
+void TestSetCurrentThreadType() {
+  for (auto from : kAllThreadTypes) {
+    if (!PlatformThread::CanChangeThreadType(ThreadType::kDefault, from)) {
+      continue;
     }
+    for (auto to : kAllThreadTypes) {
+      ThreadTypeTestThread thread(from, to);
+      PlatformThreadHandle handle;
+
+      ASSERT_FALSE(thread.IsRunning());
+      ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+      thread.WaitForTerminationReady();
+      ASSERT_TRUE(thread.IsRunning());
+
+      thread.MarkForTermination();
+      PlatformThread::Join(handle);
+      ASSERT_FALSE(thread.IsRunning());
+    }
+  }
+}
+
+void TestPriorityResultingFromThreadType(ThreadType thread_type,
+                                         ThreadPriorityForTest priority) {
+  ThreadPriorityTestThread thread(thread_type, priority);
+  PlatformThreadHandle handle;
+
+  ASSERT_FALSE(thread.IsRunning());
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+  thread.WaitForTerminationReady();
+  ASSERT_TRUE(thread.IsRunning());
+
+  thread.MarkForTermination();
+  PlatformThread::Join(handle);
+  ASSERT_FALSE(thread.IsRunning());
+}
+
+ThreadPriorityForTest GetCurrentThreadPriorityIfStartWithThreadType(
+    ThreadType thread_type,
+    MessagePumpType message_pump_type) {
+  Thread::Options options;
+  options.thread_type = thread_type;
+  options.message_pump_type = message_pump_type;
+
+  Thread thread("GetCurrentThreadPriorityIfStartWithThreadType");
+  thread.StartWithOptions(std::move(options));
+  thread.WaitUntilThreadStarted();
+
+  ThreadPriorityForTest priority;
+  thread.task_runner()->PostTask(
+      FROM_HERE, BindOnce(
+                     [](ThreadPriorityForTest* priority) {
+                       *priority =
+                           PlatformThread::GetCurrentThreadPriorityForTest();
+                     },
+                     &priority));
+  thread.Stop();
+
+  return priority;
+}
+
+ThreadPriorityForTest GetCurrentThreadPriorityIfSetThreadTypeLater(
+    ThreadType thread_type,
+    MessagePumpType message_pump_type) {
+  Thread::Options options;
+  options.message_pump_type = message_pump_type;
+
+  Thread thread("GetCurrentThreadPriorityIfSetThreadTypeLater");
+  thread.StartWithOptions(std::move(options));
+  thread.WaitUntilThreadStarted();
+
+  ThreadPriorityForTest priority;
+  thread.task_runner()->PostTask(
+      FROM_HERE,
+      BindOnce(
+          [](ThreadType thread_type, ThreadPriorityForTest* priority) {
+            PlatformThread::SetCurrentThreadType(thread_type);
+            *priority = PlatformThread::GetCurrentThreadPriorityForTest();
+          },
+          thread_type, &priority));
+  thread.Stop();
+
+  return priority;
+}
+
+void TestPriorityResultingFromThreadType(ThreadType thread_type,
+                                         MessagePumpType message_pump_type,
+                                         ThreadPriorityForTest priority) {
+  testing::Message message;
+  message << "thread_type: " << static_cast<int>(thread_type)
+          << ", message_pump_type: " << static_cast<int>(message_pump_type);
+  SCOPED_TRACE(message);
+
+  if (PlatformThread::CanChangeThreadType(ThreadType::kDefault, thread_type)) {
+    EXPECT_EQ(GetCurrentThreadPriorityIfStartWithThreadType(thread_type,
+                                                            message_pump_type),
+              priority);
+    EXPECT_EQ(GetCurrentThreadPriorityIfSetThreadTypeLater(thread_type,
+                                                           message_pump_type),
+              priority);
   }
 }
 
 }  // namespace
 
-// Test changing a created thread's priority.
-#if defined(OS_FUCHSIA)
-// TODO(crbug.com/851759): Thread priorities are not implemented in Fuchsia.
-#define MAYBE_SetCurrentThreadPriority DISABLED_SetCurrentThreadPriority
+// Test changing a created thread's type.
+TEST(PlatformThreadTest, SetCurrentThreadType) {
+  TestSetCurrentThreadType();
+}
+
+#if BUILDFLAG(IS_WIN)
+// Test changing a created thread's priority in an IDLE_PRIORITY_CLASS process
+// (regression test for https://crbug.com/901483).
+TEST(PlatformThreadTest,
+     SetCurrentThreadTypeWithThreadModeBackgroundIdleProcess) {
+  ::SetPriorityClass(Process::Current().Handle(), IDLE_PRIORITY_CLASS);
+  TestSetCurrentThreadType();
+  ::SetPriorityClass(Process::Current().Handle(), NORMAL_PRIORITY_CLASS);
+}
+#endif  // BUILDFLAG(IS_WIN)
+
+#if !defined(STARBOARD)
+// Ideally PlatformThread::CanChangeThreadType() would be true on all
+// platforms for all priorities. This not being the case. This test documents
+// and hardcodes what we know. Please inform scheduler-dev@chromium.org if this
+// proprerty changes for a given platform.
+TEST(PlatformThreadTest, CanChangeThreadType) {
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+  // On Ubuntu, RLIMIT_NICE and RLIMIT_RTPRIO are 0 by default, so we won't be
+  // able to increase priority to any level.
+  constexpr bool kCanIncreasePriority = false;
 #else
-#define MAYBE_SetCurrentThreadPriority SetCurrentThreadPriority
+  constexpr bool kCanIncreasePriority = true;
 #endif
-TEST(PlatformThreadTest, MAYBE_SetCurrentThreadPriority) {
-  TestSetCurrentThreadPriority();
+
+  for (auto type : kAllThreadTypes) {
+    EXPECT_TRUE(PlatformThread::CanChangeThreadType(type, type));
+  }
+#if BUILDFLAG(IS_FUCHSIA)
+  EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
+                                                   ThreadType::kUtility));
+  EXPECT_FALSE(PlatformThread::CanChangeThreadType(
+      ThreadType::kBackground, ThreadType::kResourceEfficient));
+  EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
+                                                   ThreadType::kDefault));
+  EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
+                                                   ThreadType::kCompositing));
+  EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kDefault,
+                                                   ThreadType::kBackground));
+  EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kCompositing,
+                                                   ThreadType::kBackground));
+#else
+  EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
+                                                ThreadType::kUtility),
+            kCanIncreasePriority);
+  EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
+                                                ThreadType::kResourceEfficient),
+            kCanIncreasePriority);
+  EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
+                                                ThreadType::kDefault),
+            kCanIncreasePriority);
+  EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
+                                                ThreadType::kCompositing),
+            kCanIncreasePriority);
+  EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kDefault,
+                                                  ThreadType::kBackground));
+  EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kCompositing,
+                                                  ThreadType::kBackground));
+#endif
+  EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
+                                                ThreadType::kDisplayCritical),
+            kCanIncreasePriority);
+  EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
+                                                ThreadType::kRealtimeAudio),
+            kCanIncreasePriority);
+#if BUILDFLAG(IS_FUCHSIA)
+  EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kDisplayCritical,
+                                                   ThreadType::kBackground));
+  EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kRealtimeAudio,
+                                                   ThreadType::kBackground));
+#else
+  EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kDisplayCritical,
+                                                  ThreadType::kBackground));
+  EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kRealtimeAudio,
+                                                  ThreadType::kBackground));
+#endif
 }
+#endif // !defined(STARBOARD)
 
-#if defined(OS_WIN)
-// Test changing a created thread's priority, with the
-// kWindowsThreadModeBackground feature enabled.
-TEST(PlatformThreadTest, SetCurrentThreadPriorityWithThreadModeBackground) {
-  test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      features::kWindowsThreadModeBackground);
-  TestSetCurrentThreadPriority();
+TEST(PlatformThreadTest, SetCurrentThreadTypeTest) {
+  TestPriorityResultingFromThreadType(ThreadType::kBackground,
+                                      ThreadPriorityForTest::kBackground);
+  TestPriorityResultingFromThreadType(ThreadType::kUtility,
+                                      ThreadPriorityForTest::kUtility);
+#if BUILDFLAG(IS_APPLE)
+  TestPriorityResultingFromThreadType(ThreadType::kResourceEfficient,
+                                      ThreadPriorityForTest::kUtility);
+#else
+  TestPriorityResultingFromThreadType(ThreadType::kResourceEfficient,
+                                      ThreadPriorityForTest::kNormal);
+#endif  // BUILDFLAG(IS_APPLE)
+  TestPriorityResultingFromThreadType(ThreadType::kDefault,
+                                      ThreadPriorityForTest::kNormal);
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
+  TestPriorityResultingFromThreadType(ThreadType::kCompositing,
+                                      ThreadPriorityForTest::kDisplay);
+#if BUILDFLAG(IS_WIN)
+  TestPriorityResultingFromThreadType(ThreadType::kCompositing,
+                                      MessagePumpType::UI,
+                                      ThreadPriorityForTest::kNormal);
+#else
+  TestPriorityResultingFromThreadType(ThreadType::kCompositing,
+                                      MessagePumpType::UI,
+                                      ThreadPriorityForTest::kDisplay);
+#endif  // BUILDFLAG(IS_WIN)
+  TestPriorityResultingFromThreadType(ThreadType::kCompositing,
+                                      MessagePumpType::IO,
+                                      ThreadPriorityForTest::kDisplay);
+#else  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_FUCHSIA)
+  TestPriorityResultingFromThreadType(ThreadType::kCompositing,
+                                      ThreadPriorityForTest::kNormal);
+  TestPriorityResultingFromThreadType(ThreadType::kCompositing,
+                                      MessagePumpType::UI,
+                                      ThreadPriorityForTest::kNormal);
+  TestPriorityResultingFromThreadType(ThreadType::kCompositing,
+                                      MessagePumpType::IO,
+                                      ThreadPriorityForTest::kNormal);
+#endif
+  TestPriorityResultingFromThreadType(ThreadType::kDisplayCritical,
+                                      ThreadPriorityForTest::kDisplay);
+  TestPriorityResultingFromThreadType(ThreadType::kRealtimeAudio,
+                                      ThreadPriorityForTest::kRealtimeAudio);
 }
-#endif  // defined(OS_WIN)
-#endif  // !defined(STARBOARD)
-
-// This tests internal PlatformThread APIs used under some POSIX platforms,
-// with the exception of Mac OS X, iOS and Fuchsia.
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS) && \
-    !defined(OS_FUCHSIA)
-TEST(PlatformThreadTest, GetNiceValueToThreadPriority) {
-  using internal::NiceValueToThreadPriority;
-  using internal::kThreadPriorityToNiceValueMap;
-
-  EXPECT_EQ(ThreadPriority::BACKGROUND,
-            kThreadPriorityToNiceValueMap[0].priority);
-  EXPECT_EQ(ThreadPriority::NORMAL,
-            kThreadPriorityToNiceValueMap[1].priority);
-  EXPECT_EQ(ThreadPriority::DISPLAY,
-            kThreadPriorityToNiceValueMap[2].priority);
-  EXPECT_EQ(ThreadPriority::REALTIME_AUDIO,
-            kThreadPriorityToNiceValueMap[3].priority);
-
-  static const int kBackgroundNiceValue =
-      kThreadPriorityToNiceValueMap[0].nice_value;
-  static const int kNormalNiceValue =
-      kThreadPriorityToNiceValueMap[1].nice_value;
-  static const int kDisplayNiceValue =
-      kThreadPriorityToNiceValueMap[2].nice_value;
-  static const int kRealtimeAudioNiceValue =
-      kThreadPriorityToNiceValueMap[3].nice_value;
-
-  // The tests below assume the nice values specified in the map are within
-  // the range below (both ends exclusive).
-  static const int kHighestNiceValue = 19;
-  static const int kLowestNiceValue = -20;
-
-  EXPECT_GT(kHighestNiceValue, kBackgroundNiceValue);
-  EXPECT_GT(kBackgroundNiceValue, kNormalNiceValue);
-  EXPECT_GT(kNormalNiceValue, kDisplayNiceValue);
-  EXPECT_GT(kDisplayNiceValue, kRealtimeAudioNiceValue);
-  EXPECT_GT(kRealtimeAudioNiceValue, kLowestNiceValue);
-
-  EXPECT_EQ(ThreadPriority::BACKGROUND,
-            NiceValueToThreadPriority(kHighestNiceValue));
-  EXPECT_EQ(ThreadPriority::BACKGROUND,
-            NiceValueToThreadPriority(kBackgroundNiceValue + 1));
-  EXPECT_EQ(ThreadPriority::BACKGROUND,
-            NiceValueToThreadPriority(kBackgroundNiceValue));
-  EXPECT_EQ(ThreadPriority::BACKGROUND,
-            NiceValueToThreadPriority(kNormalNiceValue + 1));
-  EXPECT_EQ(ThreadPriority::NORMAL,
-            NiceValueToThreadPriority(kNormalNiceValue));
-  EXPECT_EQ(ThreadPriority::NORMAL,
-            NiceValueToThreadPriority(kDisplayNiceValue + 1));
-  EXPECT_EQ(ThreadPriority::DISPLAY,
-            NiceValueToThreadPriority(kDisplayNiceValue));
-  EXPECT_EQ(ThreadPriority::DISPLAY,
-            NiceValueToThreadPriority(kRealtimeAudioNiceValue + 1));
-  EXPECT_EQ(ThreadPriority::REALTIME_AUDIO,
-            NiceValueToThreadPriority(kRealtimeAudioNiceValue));
-  EXPECT_EQ(ThreadPriority::REALTIME_AUDIO,
-            NiceValueToThreadPriority(kLowestNiceValue));
-}
-#endif  // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS) &&
-        // !defined(OS_FUCHSIA)
 
 TEST(PlatformThreadTest, SetHugeThreadName) {
   // Construct an excessively long thread name.
@@ -368,4 +540,245 @@
   PlatformThread::SetName(long_name);
 }
 
+// TODO: b/327008491 - Not used by Cobalt, but should be tested to get
+// closer to Chrome.
+#if !defined(STARBOARD)
+TEST(PlatformThreadTest, GetDefaultThreadStackSize) {
+  size_t stack_size = PlatformThread::GetDefaultThreadStackSize();
+#if BUILDFLAG(IS_IOS) && BUILDFLAG(USE_BLINK)
+  EXPECT_EQ(1024u * 1024u, stack_size);
+#elif BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS) || BUILDFLAG(IS_FUCHSIA) ||      \
+    ((BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && defined(__GLIBC__) && \
+     !defined(THREAD_SANITIZER)) ||                                           \
+    (BUILDFLAG(IS_ANDROID) && !defined(ADDRESS_SANITIZER))
+  EXPECT_EQ(0u, stack_size);
+#else
+  EXPECT_GT(stack_size, 0u);
+  EXPECT_LT(stack_size, 20u * (1 << 20));
+#endif
+}
+#endif
+
+#if BUILDFLAG(IS_APPLE)
+
+namespace {
+
+class RealtimeTestThread : public FunctionTestThread {
+ public:
+  explicit RealtimeTestThread(TimeDelta realtime_period)
+      : realtime_period_(realtime_period) {}
+  ~RealtimeTestThread() override = default;
+
+ private:
+  RealtimeTestThread(const RealtimeTestThread&) = delete;
+  RealtimeTestThread& operator=(const RealtimeTestThread&) = delete;
+
+  TimeDelta GetRealtimePeriod() final { return realtime_period_; }
+
+  // Verifies the realtime thead configuration.
+  void RunTest() override {
+    EXPECT_EQ(PlatformThread::GetCurrentThreadType(),
+              ThreadType::kRealtimeAudio);
+
+    mach_port_t mach_thread_id = pthread_mach_thread_np(
+        PlatformThread::CurrentHandle().platform_handle());
+
+    // |count| and |get_default| chosen impirically so that
+    // time_constraints_buffer[0] would store the last constraints that were
+    // applied.
+    const int kPolicyCount = 32;
+    thread_time_constraint_policy_data_t time_constraints_buffer[kPolicyCount];
+    mach_msg_type_number_t count = kPolicyCount;
+    boolean_t get_default = 0;
+
+    kern_return_t result = thread_policy_get(
+        mach_thread_id, THREAD_TIME_CONSTRAINT_POLICY,
+        reinterpret_cast<thread_policy_t>(time_constraints_buffer), &count,
+        &get_default);
+
+    EXPECT_EQ(result, KERN_SUCCESS);
+
+    const thread_time_constraint_policy_data_t& time_constraints =
+        time_constraints_buffer[0];
+
+    mach_timebase_info_data_t tb_info;
+    mach_timebase_info(&tb_info);
+
+    if (FeatureList::IsEnabled(kOptimizedRealtimeThreadingMac) &&
+#if BUILDFLAG(IS_MAC)
+        !mac::IsOS10_14() &&  // Should not be applied on 10.14.
+#endif
+        !realtime_period_.is_zero()) {
+      uint32_t abs_realtime_period = saturated_cast<uint32_t>(
+          realtime_period_.InNanoseconds() *
+          (static_cast<double>(tb_info.denom) / tb_info.numer));
+
+      EXPECT_EQ(time_constraints.period, abs_realtime_period);
+      EXPECT_EQ(
+          time_constraints.computation,
+          static_cast<uint32_t>(abs_realtime_period *
+                                kOptimizedRealtimeThreadingMacBusy.Get()));
+      EXPECT_EQ(
+          time_constraints.constraint,
+          static_cast<uint32_t>(abs_realtime_period *
+                                kOptimizedRealtimeThreadingMacBusyLimit.Get()));
+      EXPECT_EQ(time_constraints.preemptible,
+                kOptimizedRealtimeThreadingMacPreemptible.Get());
+    } else {
+      // Old-style empirical values.
+      const double kTimeQuantum = 2.9;
+      const double kAudioTimeNeeded = 0.75 * kTimeQuantum;
+      const double kMaxTimeAllowed = 0.85 * kTimeQuantum;
+
+      // Get the conversion factor from milliseconds to absolute time
+      // which is what the time-constraints returns.
+      double ms_to_abs_time = double(tb_info.denom) / tb_info.numer * 1000000;
+
+      EXPECT_EQ(time_constraints.period,
+                saturated_cast<uint32_t>(kTimeQuantum * ms_to_abs_time));
+      EXPECT_EQ(time_constraints.computation,
+                saturated_cast<uint32_t>(kAudioTimeNeeded * ms_to_abs_time));
+      EXPECT_EQ(time_constraints.constraint,
+                saturated_cast<uint32_t>(kMaxTimeAllowed * ms_to_abs_time));
+      EXPECT_FALSE(time_constraints.preemptible);
+    }
+  }
+
+  const TimeDelta realtime_period_;
+};
+
+class RealtimePlatformThreadTest
+    : public testing::TestWithParam<
+          std::tuple<bool, FieldTrialParams, TimeDelta>> {
+ protected:
+  void VerifyRealtimeConfig(TimeDelta period) {
+    RealtimeTestThread thread(period);
+    PlatformThreadHandle handle;
+
+    ASSERT_FALSE(thread.IsRunning());
+    ASSERT_TRUE(PlatformThread::CreateWithType(0, &thread, &handle,
+                                               ThreadType::kRealtimeAudio));
+    thread.WaitForTerminationReady();
+    ASSERT_TRUE(thread.IsRunning());
+
+    thread.MarkForTermination();
+    PlatformThread::Join(handle);
+    ASSERT_FALSE(thread.IsRunning());
+  }
+};
+
+TEST_P(RealtimePlatformThreadTest, RealtimeAudioConfigMac) {
+  test::ScopedFeatureList feature_list;
+  if (std::get<0>(GetParam())) {
+    feature_list.InitAndEnableFeatureWithParameters(
+        kOptimizedRealtimeThreadingMac, std::get<1>(GetParam()));
+  } else {
+    feature_list.InitAndDisableFeature(kOptimizedRealtimeThreadingMac);
+  }
+
+  PlatformThread::InitFeaturesPostFieldTrial();
+  VerifyRealtimeConfig(std::get<2>(GetParam()));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    RealtimePlatformThreadTest,
+    RealtimePlatformThreadTest,
+    testing::Combine(
+        testing::Bool(),
+        testing::Values(
+            FieldTrialParams{
+                {kOptimizedRealtimeThreadingMacPreemptible.name, "true"}},
+            FieldTrialParams{
+                {kOptimizedRealtimeThreadingMacPreemptible.name, "false"}},
+            FieldTrialParams{
+                {kOptimizedRealtimeThreadingMacBusy.name, "0.5"},
+                {kOptimizedRealtimeThreadingMacBusyLimit.name, "0.75"}},
+            FieldTrialParams{
+                {kOptimizedRealtimeThreadingMacBusy.name, "0.7"},
+                {kOptimizedRealtimeThreadingMacBusyLimit.name, "0.7"}},
+            FieldTrialParams{
+                {kOptimizedRealtimeThreadingMacBusy.name, "0.5"},
+                {kOptimizedRealtimeThreadingMacBusyLimit.name, "1.0"}}),
+        testing::Values(TimeDelta(),
+                        Seconds(256.0 / 48000),
+                        Milliseconds(5),
+                        Milliseconds(10),
+                        Seconds(1024.0 / 44100),
+                        Seconds(1024.0 / 16000))));
+
+}  // namespace
+
+#endif  // BUILDFLAG(IS_APPLE)
+
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
+namespace {
+
+bool IsTidCacheCorrect() {
+  return PlatformThread::CurrentId() == syscall(__NR_gettid);
+}
+
+void* CheckTidCacheCorrectWrapper(void*) {
+  CHECK(IsTidCacheCorrect());
+  return nullptr;
+}
+
+void CreatePthreadToCheckCache() {
+  pthread_t thread_id;
+  pthread_create(&thread_id, nullptr, CheckTidCacheCorrectWrapper, nullptr);
+  pthread_join(thread_id, nullptr);
+}
+
+// This test must use raw pthreads and fork() to avoid calls from //base to
+// PlatformThread::CurrentId(), as the ordering of calls is important to the
+// test.
+void TestTidCacheCorrect(bool main_thread_accesses_cache_first) {
+  EXPECT_TRUE(IsTidCacheCorrect());
+
+  CreatePthreadToCheckCache();
+
+  // Now fork a process and make sure the TID cache gets correctly updated on
+  // both its main thread and a child thread.
+  pid_t child_pid = fork();
+  ASSERT_GE(child_pid, 0);
+
+  if (child_pid == 0) {
+    // In the child.
+    if (main_thread_accesses_cache_first) {
+      if (!IsTidCacheCorrect())
+        _exit(1);
+    }
+
+    // Access the TID cache on another thread and make sure the cached value is
+    // correct.
+    CreatePthreadToCheckCache();
+
+    if (!main_thread_accesses_cache_first) {
+      // Make sure the main thread's cache is correct even though another thread
+      // accessed the cache first.
+      if (!IsTidCacheCorrect())
+        _exit(1);
+    }
+
+    _exit(0);
+  }
+
+  int status;
+  ASSERT_EQ(waitpid(child_pid, &status, 0), child_pid);
+  ASSERT_TRUE(WIFEXITED(status));
+  ASSERT_EQ(WEXITSTATUS(status), 0);
+}
+
+TEST(PlatformThreadTidCacheTest, MainThreadFirst) {
+  TestTidCacheCorrect(true);
+}
+
+TEST(PlatformThreadTidCacheTest, MainThreadSecond) {
+  TestTidCacheCorrect(false);
+}
+
+}  // namespace
+
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
 }  // namespace base
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc
index d97c1bf..e41758d 100644
--- a/base/threading/platform_thread_win.cc
+++ b/base/threading/platform_thread_win.cc
@@ -1,35 +1,62 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/platform_thread_win.h"
 
-#include "base/debug/activity_tracker.h"
+#include <stddef.h>
+
+#include <string>
+
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/debug/alias.h"
+#include "base/debug/crash_logging.h"
 #include "base/debug/profiler.h"
+#include "base/feature_list.h"
 #include "base/logging.h"
+#include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/process/memory.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/scoped_blocking_call.h"
+#include "base/threading/scoped_thread_priority.h"
 #include "base/threading/thread_id_name_manager.h"
 #include "base/threading/thread_restrictions.h"
+#include "base/threading/threading_features.h"
+#include "base/time/time_override.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/windows_version.h"
+#include "build/build_config.h"
 
 #include <windows.h>
 
-#include "starboard/types.h"
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN)
+#include "base/allocator/partition_allocator/starscan/pcscan.h"
+#include "base/allocator/partition_allocator/starscan/stack/stack.h"
+#endif
 
 namespace base {
 
+BASE_FEATURE(kUseThreadPriorityLowest,
+             "UseThreadPriorityLowest",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kAboveNormalCompositingBrowserWin,
+             "AboveNormalCompositingBrowserWin",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 namespace {
 
-// The value returned by ::GetThreadPriority() after background thread mode is
-// enabled on Windows 7.
-constexpr int kWin7BackgroundThreadModePriority = 4;
+// Flag used to set thread priority to |THREAD_PRIORITY_LOWEST| for
+// |kUseThreadPriorityLowest| Feature.
+std::atomic<bool> g_use_thread_priority_lowest{false};
+// Flag used to map Compositing ThreadType |THREAD_PRIORITY_ABOVE_NORMAL| on the
+// UI thread for |kAboveNormalCompositingBrowserWin| Feature.
+std::atomic<bool> g_above_normal_compositing_browser{false};
 
-// The value returned by ::GetThreadPriority() after background thread mode is
-// enabled on Windows 8+.
-constexpr int kWin8AboveBackgroundThreadModePriority = -4;
+// These values are sometimes returned by ::GetThreadPriority().
+constexpr int kWinDisplayPriority1 = 5;
+constexpr int kWinDisplayPriority2 = 6;
 
 // The information on how to set the thread name comes from
 // a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx
@@ -55,26 +82,28 @@
   info.dwFlags = 0;
 
   __try {
-    RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
-                   reinterpret_cast<DWORD_PTR*>(&info));
-  } __except(EXCEPTION_CONTINUE_EXECUTION) {
+    RaiseException(kVCThreadNameException, 0, sizeof(info) / sizeof(ULONG_PTR),
+                   reinterpret_cast<ULONG_PTR*>(&info));
+  } __except (EXCEPTION_EXECUTE_HANDLER) {
   }
 }
 
 struct ThreadParams {
-  PlatformThread::Delegate* delegate;
+  raw_ptr<PlatformThread::Delegate> delegate;
   bool joinable;
-  ThreadPriority priority;
+  ThreadType thread_type;
+  MessagePumpType message_pump_type;
 };
 
 DWORD __stdcall ThreadFunc(void* params) {
   ThreadParams* thread_params = static_cast<ThreadParams*>(params);
   PlatformThread::Delegate* delegate = thread_params->delegate;
   if (!thread_params->joinable)
-    base::ThreadRestrictions::SetSingletonAllowed(false);
+    base::DisallowSingleton();
 
-  if (thread_params->priority != ThreadPriority::NORMAL)
-    PlatformThread::SetCurrentThreadPriority(thread_params->priority);
+  if (thread_params->thread_type != ThreadType::kDefault)
+    internal::SetCurrentThreadType(thread_params->thread_type,
+                                   thread_params->message_pump_type);
 
   // Retrieve a copy of the thread handle to use as the key in the
   // thread name mapping.
@@ -87,59 +116,105 @@
                                 FALSE,
                                 DUPLICATE_SAME_ACCESS);
 
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN)
+  partition_alloc::internal::PCScan::NotifyThreadCreated(
+      partition_alloc::internal::GetStackPointer());
+#endif
+
   win::ScopedHandle scoped_platform_handle;
 
   if (did_dup) {
     scoped_platform_handle.Set(platform_handle);
     ThreadIdNameManager::GetInstance()->RegisterThread(
-        scoped_platform_handle.Get(),
-        PlatformThread::CurrentId());
+        scoped_platform_handle.get(), PlatformThread::CurrentId());
   }
 
   delete thread_params;
   delegate->ThreadMain();
 
   if (did_dup) {
-    ThreadIdNameManager::GetInstance()->RemoveName(
-        scoped_platform_handle.Get(),
-        PlatformThread::CurrentId());
+    ThreadIdNameManager::GetInstance()->RemoveName(scoped_platform_handle.get(),
+                                                   PlatformThread::CurrentId());
   }
 
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN)
+  partition_alloc::internal::PCScan::NotifyThreadDestroyed();
+#endif
+
+  // Ensure thread priority is at least NORMAL before initiating thread
+  // destruction. Thread destruction on Windows holds the LdrLock while
+  // performing TLS destruction which causes hangs if performed at background
+  // priority (priority inversion) (see: http://crbug.com/1096203).
+  if (::GetThreadPriority(::GetCurrentThread()) < THREAD_PRIORITY_NORMAL)
+    PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
+
   return 0;
 }
 
-// CreateThreadInternal() matches PlatformThread::CreateWithPriority(), except
+// CreateThreadInternal() matches PlatformThread::CreateWithType(), except
 // that |out_thread_handle| may be nullptr, in which case a non-joinable thread
 // is created.
 bool CreateThreadInternal(size_t stack_size,
                           PlatformThread::Delegate* delegate,
                           PlatformThreadHandle* out_thread_handle,
-                          ThreadPriority priority) {
+                          ThreadType thread_type,
+                          MessagePumpType message_pump_type) {
   unsigned int flags = 0;
   if (stack_size > 0) {
     flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
+#if defined(ARCH_CPU_32_BITS)
+  } else {
+    // The process stack size is increased to give spaces to |RendererMain| in
+    // |chrome/BUILD.gn|, but keep the default stack size of other threads to
+    // 1MB for the address space pressure.
+    flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
+    static BOOL is_wow64 = -1;
+    if (is_wow64 == -1 && !IsWow64Process(GetCurrentProcess(), &is_wow64))
+      is_wow64 = FALSE;
+    // When is_wow64 is set that means we are running on 64-bit Windows and we
+    // get 4 GiB of address space. In that situation we can afford to use 1 MiB
+    // of address space for stacks. When running on 32-bit Windows we only get
+    // 2 GiB of address space so we need to conserve. Typically stack usage on
+    // these threads is only about 100 KiB.
+    if (is_wow64)
+      stack_size = 1024 * 1024;
+    else
+      stack_size = 512 * 1024;
+#endif
   }
 
   ThreadParams* params = new ThreadParams;
   params->delegate = delegate;
   params->joinable = out_thread_handle != nullptr;
-  params->priority = priority;
+  params->thread_type = thread_type;
+  params->message_pump_type = message_pump_type;
 
-  void* thread_handle;
-  {
-    SCOPED_UMA_HISTOGRAM_TIMER("Windows.CreateThreadTime");
-
-    // Using CreateThread here vs _beginthreadex makes thread creation a bit
-    // faster and doesn't require the loader lock to be available.  Our code
-    // will  have to work running on CreateThread() threads anyway, since we run
-    // code on the Windows thread pool, etc.  For some background on the
-    // difference:
-    //   http://www.microsoft.com/msj/1099/win32/win321099.aspx
-    thread_handle =
-        ::CreateThread(nullptr, stack_size, ThreadFunc, params, flags, nullptr);
-  }
+  // Using CreateThread here vs _beginthreadex makes thread creation a bit
+  // faster and doesn't require the loader lock to be available.  Our code will
+  // have to work running on CreateThread() threads anyway, since we run code on
+  // the Windows thread pool, etc.  For some background on the difference:
+  // http://www.microsoft.com/msj/1099/win32/win321099.aspx
+  void* thread_handle =
+      ::CreateThread(nullptr, stack_size, ThreadFunc, params, flags, nullptr);
 
   if (!thread_handle) {
+    DWORD last_error = ::GetLastError();
+
+    switch (last_error) {
+      case ERROR_NOT_ENOUGH_MEMORY:
+      case ERROR_OUTOFMEMORY:
+      case ERROR_COMMITMENT_LIMIT:
+        TerminateBecauseOutOfMemory(stack_size);
+        break;
+
+      default:
+        static auto* last_error_crash_key = debug::AllocateCrashKeyString(
+            "create_thread_last_error", debug::CrashKeySize::Size32);
+        debug::SetCrashKeyString(last_error_crash_key,
+                                 base::NumberToString(last_error));
+        break;
+    }
+
     delete params;
     return false;
   }
@@ -153,10 +228,27 @@
 
 }  // namespace
 
-namespace features {
-const Feature kWindowsThreadModeBackground{"WindowsThreadModeBackground",
-                                           FEATURE_DISABLED_BY_DEFAULT};
-}  // namespace features
+namespace internal {
+
+void AssertMemoryPriority(HANDLE thread, int memory_priority) {
+#if DCHECK_IS_ON()
+  static const auto get_thread_information_fn =
+      reinterpret_cast<decltype(&::GetThreadInformation)>(::GetProcAddress(
+          ::GetModuleHandle(L"Kernel32.dll"), "GetThreadInformation"));
+
+  DCHECK(get_thread_information_fn);
+
+  MEMORY_PRIORITY_INFORMATION memory_priority_information = {};
+  DCHECK(get_thread_information_fn(thread, ::ThreadMemoryPriority,
+                                   &memory_priority_information,
+                                   sizeof(memory_priority_information)));
+
+  DCHECK_EQ(memory_priority,
+            static_cast<int>(memory_priority_information.MemoryPriority));
+#endif
+}
+
+}  // namespace internal
 
 // static
 PlatformThreadId PlatformThread::CurrentId() {
@@ -182,9 +274,13 @@
 void PlatformThread::Sleep(TimeDelta duration) {
   // When measured with a high resolution clock, Sleep() sometimes returns much
   // too early. We may need to call it repeatedly to get the desired duration.
-  TimeTicks end = TimeTicks::Now() + duration;
-  for (TimeTicks now = TimeTicks::Now(); now < end; now = TimeTicks::Now())
+  // PlatformThread::Sleep doesn't support mock-time, so this always uses
+  // real-time.
+  const TimeTicks end = subtle::TimeTicksNowIgnoringOverride() + duration;
+  for (TimeTicks now = subtle::TimeTicksNowIgnoringOverride(); now < end;
+       now = subtle::TimeTicksNowIgnoringOverride()) {
     ::Sleep(static_cast<DWORD>((end - now).InMillisecondsRoundedUp()));
+  }
 }
 
 // static
@@ -192,7 +288,7 @@
   ThreadIdNameManager::GetInstance()->SetName(name);
 
   // The SetThreadDescription API works even if no debugger is attached.
-  auto set_thread_description_func =
+  static auto set_thread_description_func =
       reinterpret_cast<SetThreadDescription>(::GetProcAddress(
           ::GetModuleHandle(L"Kernel32.dll"), "SetThreadDescription"));
   if (set_thread_description_func) {
@@ -214,36 +310,33 @@
 }
 
 // static
-bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
-                                        PlatformThreadHandle* thread_handle,
-                                        ThreadPriority priority) {
+bool PlatformThread::CreateWithType(size_t stack_size,
+                                    Delegate* delegate,
+                                    PlatformThreadHandle* thread_handle,
+                                    ThreadType thread_type,
+                                    MessagePumpType pump_type_hint) {
   DCHECK(thread_handle);
-  return CreateThreadInternal(stack_size, delegate, thread_handle, priority);
+  return CreateThreadInternal(stack_size, delegate, thread_handle, thread_type,
+                              pump_type_hint);
 }
 
 // static
 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
-  return CreateNonJoinableWithPriority(stack_size, delegate,
-                                       ThreadPriority::NORMAL);
+  return CreateNonJoinableWithType(stack_size, delegate, ThreadType::kDefault);
 }
 
 // static
-bool PlatformThread::CreateNonJoinableWithPriority(size_t stack_size,
-                                                   Delegate* delegate,
-                                                   ThreadPriority priority) {
+bool PlatformThread::CreateNonJoinableWithType(size_t stack_size,
+                                               Delegate* delegate,
+                                               ThreadType thread_type,
+                                               MessagePumpType pump_type_hint) {
   return CreateThreadInternal(stack_size, delegate, nullptr /* non-joinable */,
-                              priority);
+                              thread_type, pump_type_hint);
 }
 
 // static
 void PlatformThread::Join(PlatformThreadHandle thread_handle) {
   DCHECK(thread_handle.platform_handle());
-  // TODO(willchan): Enable this check once I can get it to work for Windows
-  // shutdown.
-  // Joining another thread may block the current thread for a long time, since
-  // the thread referred to by |thread_handle| may still be running long-lived /
-  // blocking tasks.
-  // AssertBlockingAllowed();
 
   DWORD thread_id = 0;
   thread_id = ::GetThreadId(thread_handle.platform_handle());
@@ -255,8 +348,8 @@
   base::debug::Alias(&thread_id);
   base::debug::Alias(&last_error);
 
-  // Record the event that this thread is blocking upon (for hang diagnosis).
-  base::debug::ScopedThreadJoinActivity thread_activity(&thread_handle);
+  base::internal::ScopedBlockingCallWithBaseSyncPrimitives scoped_blocking_call(
+      FROM_HERE, base::BlockingType::MAY_BLOCK);
 
   // Wait for the thread to exit.  It should already have terminated but make
   // sure this assumption is valid.
@@ -271,92 +364,211 @@
 }
 
 // static
-bool PlatformThread::CanIncreaseThreadPriority(ThreadPriority priority) {
+bool PlatformThread::CanChangeThreadType(ThreadType from, ThreadType to) {
   return true;
 }
 
-// static
-void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
-  // A DCHECK is triggered on FeatureList initialization if the state of a
-  // feature has been checked before. We only want to trigger that DCHECK if the
-  // priority has been set to BACKGROUND before, so we are careful not to access
-  // the state of the feature needlessly. We don't DCHECK here because it is ok
-  // if the FeatureList is never initialized in the process (e.g. in tests).
-  //
-  // TODO(fdoray): Remove experiment code. https://crbug.com/872820
-  const bool use_thread_mode_background =
-      (priority == ThreadPriority::BACKGROUND
-           ? FeatureList::IsEnabled(features::kWindowsThreadModeBackground)
-           : (FeatureList::GetInstance() &&
-              FeatureList::IsEnabled(features::kWindowsThreadModeBackground)));
+namespace {
 
-  if (use_thread_mode_background && priority != ThreadPriority::BACKGROUND) {
+void SetCurrentThreadPriority(ThreadType thread_type,
+                              MessagePumpType pump_type_hint) {
+  if (thread_type == ThreadType::kCompositing &&
+      pump_type_hint == MessagePumpType::UI &&
+      !g_above_normal_compositing_browser) {
+    // Ignore kCompositing thread type for UI thread as Windows has a
+    // priority boost mechanism. See
+    // https://docs.microsoft.com/en-us/windows/win32/procthread/priority-boosts
+    return;
+  }
+
+  PlatformThreadHandle::Handle thread_handle =
+      PlatformThread::CurrentHandle().platform_handle();
+
+  if (!g_use_thread_priority_lowest && thread_type != ThreadType::kBackground) {
     // Exit background mode if the new priority is not BACKGROUND. This is a
     // no-op if not in background mode.
-    ::SetThreadPriority(PlatformThread::CurrentHandle().platform_handle(),
-                        THREAD_MODE_BACKGROUND_END);
+    ::SetThreadPriority(thread_handle, THREAD_MODE_BACKGROUND_END);
+    // We used to DCHECK that memory priority is MEMORY_PRIORITY_NORMAL here,
+    // but found that it is not always the case (e.g. in the installer).
+    // crbug.com/1340578#c2
   }
 
   int desired_priority = THREAD_PRIORITY_ERROR_RETURN;
-  switch (priority) {
-    case ThreadPriority::BACKGROUND:
-      desired_priority = use_thread_mode_background
-                             ? THREAD_MODE_BACKGROUND_BEGIN
-                             : THREAD_PRIORITY_LOWEST;
+  switch (thread_type) {
+    case ThreadType::kBackground:
+      // Using THREAD_MODE_BACKGROUND_BEGIN instead of THREAD_PRIORITY_LOWEST
+      // improves input latency and navigation time. See
+      // https://docs.google.com/document/d/16XrOwuwTwKWdgPbcKKajTmNqtB4Am8TgS9GjbzBYLc0
+      //
+      // MSDN recommends THREAD_MODE_BACKGROUND_BEGIN for threads that perform
+      // background work, as it reduces disk and memory priority in addition to
+      // CPU priority.
+      desired_priority =
+          g_use_thread_priority_lowest.load(std::memory_order_relaxed)
+              ? THREAD_PRIORITY_LOWEST
+              : THREAD_MODE_BACKGROUND_BEGIN;
       break;
-    case ThreadPriority::NORMAL:
+    case ThreadType::kUtility:
+      desired_priority = THREAD_PRIORITY_BELOW_NORMAL;
+      break;
+    case ThreadType::kResourceEfficient:
+    case ThreadType::kDefault:
       desired_priority = THREAD_PRIORITY_NORMAL;
       break;
-    case ThreadPriority::DISPLAY:
+    case ThreadType::kCompositing:
+    case ThreadType::kDisplayCritical:
       desired_priority = THREAD_PRIORITY_ABOVE_NORMAL;
       break;
-    case ThreadPriority::REALTIME_AUDIO:
+    case ThreadType::kRealtimeAudio:
       desired_priority = THREAD_PRIORITY_TIME_CRITICAL;
       break;
-    default:
-      NOTREACHED() << "Unknown priority.";
-      break;
   }
   DCHECK_NE(desired_priority, THREAD_PRIORITY_ERROR_RETURN);
 
-#if DCHECK_IS_ON()
-  const BOOL success =
-#endif
-      ::SetThreadPriority(PlatformThread::CurrentHandle().platform_handle(),
-                          desired_priority);
-  DPLOG_IF(ERROR, !success) << "Failed to set thread priority to "
-                            << desired_priority;
+  [[maybe_unused]] const BOOL success =
+      ::SetThreadPriority(thread_handle, desired_priority);
+  DPLOG_IF(ERROR, !success)
+      << "Failed to set thread priority to " << desired_priority;
 
-  // Sanity check that GetCurrentThreadPriority() is consistent with
-  // SetCurrentThreadPriority().
-  DCHECK_EQ(GetCurrentThreadPriority(), priority);
+  if (!g_use_thread_priority_lowest && thread_type == ThreadType::kBackground) {
+    // In a background process, THREAD_MODE_BACKGROUND_BEGIN lowers the memory
+    // and I/O priorities but not the CPU priority (kernel bug?). Use
+    // THREAD_PRIORITY_LOWEST to also lower the CPU priority.
+    // https://crbug.com/901483
+    if (PlatformThread::GetCurrentThreadPriorityForTest() !=
+        ThreadPriorityForTest::kBackground) {
+      ::SetThreadPriority(thread_handle, THREAD_PRIORITY_LOWEST);
+      // We used to DCHECK that memory priority is MEMORY_PRIORITY_VERY_LOW
+      // here, but found that it is not always the case (e.g. in the installer).
+      // crbug.com/1340578#c2
+    }
+  }
 }
 
+void SetCurrentThreadQualityOfService(ThreadType thread_type) {
+  // QoS and power throttling were introduced in Win10 1709
+  if (win::GetVersion() < win::Version::WIN10_RS3) {
+    return;
+  }
+
+  static const auto set_thread_information_fn =
+      reinterpret_cast<decltype(&::SetThreadInformation)>(::GetProcAddress(
+          ::GetModuleHandle(L"kernel32.dll"), "SetThreadInformation"));
+  DCHECK(set_thread_information_fn);
+
+  bool desire_ecoqos = false;
+  switch (thread_type) {
+    case ThreadType::kBackground:
+    case ThreadType::kUtility:
+    case ThreadType::kResourceEfficient:
+      desire_ecoqos = true;
+      break;
+    case ThreadType::kDefault:
+    case ThreadType::kCompositing:
+    case ThreadType::kDisplayCritical:
+    case ThreadType::kRealtimeAudio:
+      desire_ecoqos = false;
+      break;
+  }
+
+  THREAD_POWER_THROTTLING_STATE thread_power_throttling_state{
+      .Version = THREAD_POWER_THROTTLING_CURRENT_VERSION,
+      .ControlMask =
+          desire_ecoqos ? THREAD_POWER_THROTTLING_EXECUTION_SPEED : 0ul,
+      .StateMask =
+          desire_ecoqos ? THREAD_POWER_THROTTLING_EXECUTION_SPEED : 0ul,
+  };
+  [[maybe_unused]] const BOOL success = set_thread_information_fn(
+      ::GetCurrentThread(), ::ThreadPowerThrottling,
+      &thread_power_throttling_state, sizeof(thread_power_throttling_state));
+  DPLOG_IF(ERROR, !success)
+      << "Failed to set EcoQoS to " << std::boolalpha << desire_ecoqos;
+}
+
+}  // namespace
+
+namespace internal {
+
+void SetCurrentThreadTypeImpl(ThreadType thread_type,
+                              MessagePumpType pump_type_hint) {
+  SetCurrentThreadPriority(thread_type, pump_type_hint);
+  SetCurrentThreadQualityOfService(thread_type);
+}
+
+}  // namespace internal
+
 // static
-ThreadPriority PlatformThread::GetCurrentThreadPriority() {
+ThreadPriorityForTest PlatformThread::GetCurrentThreadPriorityForTest() {
+  static_assert(
+      THREAD_PRIORITY_IDLE < 0,
+      "THREAD_PRIORITY_IDLE is >= 0 and will incorrectly cause errors.");
+  static_assert(
+      THREAD_PRIORITY_LOWEST < 0,
+      "THREAD_PRIORITY_LOWEST is >= 0 and will incorrectly cause errors.");
+  static_assert(THREAD_PRIORITY_BELOW_NORMAL < 0,
+                "THREAD_PRIORITY_BELOW_NORMAL is >= 0 and will incorrectly "
+                "cause errors.");
+  static_assert(
+      THREAD_PRIORITY_NORMAL == 0,
+      "The logic below assumes that THREAD_PRIORITY_NORMAL is zero. If it is "
+      "not, ThreadPriorityForTest::kBackground may be incorrectly detected.");
+  static_assert(THREAD_PRIORITY_ABOVE_NORMAL >= 0,
+                "THREAD_PRIORITY_ABOVE_NORMAL is < 0 and will incorrectly be "
+                "translated to ThreadPriorityForTest::kBackground.");
+  static_assert(THREAD_PRIORITY_HIGHEST >= 0,
+                "THREAD_PRIORITY_HIGHEST is < 0 and will incorrectly be "
+                "translated to ThreadPriorityForTest::kBackground.");
+  static_assert(THREAD_PRIORITY_TIME_CRITICAL >= 0,
+                "THREAD_PRIORITY_TIME_CRITICAL is < 0 and will incorrectly be "
+                "translated to ThreadPriorityForTest::kBackground.");
+  static_assert(THREAD_PRIORITY_ERROR_RETURN >= 0,
+                "THREAD_PRIORITY_ERROR_RETURN is < 0 and will incorrectly be "
+                "translated to ThreadPriorityForTest::kBackground.");
+
   const int priority =
       ::GetThreadPriority(PlatformThread::CurrentHandle().platform_handle());
 
+  // Negative values represent a background priority. We have observed -3, -4,
+  // -6 when THREAD_MODE_BACKGROUND_* is used. THREAD_PRIORITY_IDLE,
+  // THREAD_PRIORITY_LOWEST and THREAD_PRIORITY_BELOW_NORMAL are other possible
+  // negative values.
+  if (priority < THREAD_PRIORITY_BELOW_NORMAL)
+    return ThreadPriorityForTest::kBackground;
+
   switch (priority) {
-    case THREAD_PRIORITY_IDLE:
-    case kWin7BackgroundThreadModePriority:
-      DCHECK_EQ(win::GetVersion(), win::VERSION_WIN7);
-      FALLTHROUGH;
-    case kWin8AboveBackgroundThreadModePriority:
-    case THREAD_PRIORITY_LOWEST:
-      return ThreadPriority::BACKGROUND;
+    case THREAD_PRIORITY_BELOW_NORMAL:
+      return ThreadPriorityForTest::kUtility;
     case THREAD_PRIORITY_NORMAL:
-      return ThreadPriority::NORMAL;
+      return ThreadPriorityForTest::kNormal;
+    case kWinDisplayPriority1:
+      [[fallthrough]];
+    case kWinDisplayPriority2:
+      return ThreadPriorityForTest::kDisplay;
     case THREAD_PRIORITY_ABOVE_NORMAL:
-      return ThreadPriority::DISPLAY;
+    case THREAD_PRIORITY_HIGHEST:
+      return ThreadPriorityForTest::kDisplay;
     case THREAD_PRIORITY_TIME_CRITICAL:
-      return ThreadPriority::REALTIME_AUDIO;
+      return ThreadPriorityForTest::kRealtimeAudio;
     case THREAD_PRIORITY_ERROR_RETURN:
-      DPCHECK(false) << "GetThreadPriority error";
+      DPCHECK(false) << "::GetThreadPriority error";
   }
 
-  NOTREACHED() << "GetCurrentThreadPriority returned " << priority << ".";
-  return ThreadPriority::NORMAL;
+  NOTREACHED() << "::GetThreadPriority returned " << priority << ".";
+  return ThreadPriorityForTest::kNormal;
+}
+
+void InitializePlatformThreadFeatures() {
+  g_use_thread_priority_lowest.store(
+      FeatureList::IsEnabled(kUseThreadPriorityLowest),
+      std::memory_order_relaxed);
+  g_above_normal_compositing_browser.store(
+      FeatureList::IsEnabled(kAboveNormalCompositingBrowserWin),
+      std::memory_order_relaxed);
+}
+
+// static
+size_t PlatformThread::GetDefaultThreadStackSize() {
+  return 0;
 }
 
 }  // namespace base
diff --git a/base/threading/platform_thread_win.h b/base/threading/platform_thread_win.h
index 61cfd00..18a7260 100644
--- a/base/threading/platform_thread_win.h
+++ b/base/threading/platform_thread_win.h
@@ -1,26 +1,27 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef BASE_THREADING_PLATFORM_THREAD_WIN_H_
 #define BASE_THREADING_PLATFORM_THREAD_WIN_H_
 
+#include "base/win/windows_types.h"
+
 #include "base/threading/platform_thread.h"
 
 #include "base/base_export.h"
-#include "base/feature_list.h"
 
 namespace base {
-namespace features {
+namespace internal {
 
-// Use THREAD_MODE_BACKGROUND_BEGIN instead of THREAD_PRIORITY_LOWEST for
-// ThreadPriority::BACKGROUND threads. This lowers the disk and network I/O
-// priority of the thread in addition to the CPU scheduling priority. MSDN
-// recommends using this setting for threads that perform background work.
-// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority
-BASE_EXPORT extern const Feature kWindowsThreadModeBackground;
+// Assert that the memory priority of `thread` is `memory_priority`. Exposed
+// for unit tests.
+BASE_EXPORT void AssertMemoryPriority(HANDLE thread, int memory_priority);
 
-}  // namespace features
+}  // namespace internal
+
+BASE_EXPORT void InitializePlatformThreadFeatures();
+
 }  // namespace base
 
 #endif  // BASE_THREADING_PLATFORM_THREAD_WIN_H_
diff --git a/base/threading/platform_thread_win_unittest.cc b/base/threading/platform_thread_win_unittest.cc
new file mode 100644
index 0000000..3fc3a9e
--- /dev/null
+++ b/base/threading/platform_thread_win_unittest.cc
@@ -0,0 +1,91 @@
+// Copyright 2018 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread_win.h"
+
+#include <windows.h>
+
+#include <array>
+
+#include "base/process/process.h"
+#include "base/win/windows_version.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// It has been observed that calling
+// :SetThreadPriority(THREAD_MODE_BACKGROUND_BEGIN) in an IDLE_PRIORITY_CLASS
+// process never affects the return value of ::GetThreadPriority() or
+// the base priority reported in Process Explorer. It does however
+// set the memory and I/O priorities to very low. This test confirms that
+// behavior which we suspect is a Windows kernel bug. If this test starts
+// failing, the mitigation for https://crbug.com/901483 in
+// PlatformThread::SetCurrentThreadType() should be revisited.
+TEST(PlatformThreadWinTest, SetBackgroundThreadModeFailsInIdlePriorityProcess) {
+  PlatformThreadHandle::Handle thread_handle =
+      PlatformThread::CurrentHandle().platform_handle();
+
+  // ::GetThreadPriority() is NORMAL. Memory priority is NORMAL.
+  // Note: There is no practical way to verify the I/O priority.
+  EXPECT_EQ(::GetThreadPriority(thread_handle), THREAD_PRIORITY_NORMAL);
+  internal::AssertMemoryPriority(thread_handle, MEMORY_PRIORITY_NORMAL);
+
+  // Set the process priority to IDLE.
+  // Note: Do not use Process::SetProcessBackgrounded() because it uses
+  // PROCESS_MODE_BACKGROUND_BEGIN instead of IDLE_PRIORITY_CLASS when
+  // the target is the current process.
+  EXPECT_EQ(::GetPriorityClass(Process::Current().Handle()),
+            static_cast<DWORD>(NORMAL_PRIORITY_CLASS));
+  ::SetPriorityClass(Process::Current().Handle(), IDLE_PRIORITY_CLASS);
+  EXPECT_EQ(Process::Current().GetPriority(),
+            static_cast<int>(IDLE_PRIORITY_CLASS));
+
+  // GetThreadPriority() stays NORMAL. Memory priority stays NORMAL.
+  EXPECT_EQ(::GetThreadPriority(thread_handle), THREAD_PRIORITY_NORMAL);
+  internal::AssertMemoryPriority(thread_handle, MEMORY_PRIORITY_NORMAL);
+
+  // Begin thread mode background.
+  EXPECT_TRUE(::SetThreadPriority(thread_handle, THREAD_MODE_BACKGROUND_BEGIN));
+
+  // On Win10+, GetThreadPriority() stays NORMAL and memory priority becomes
+  // VERY_LOW.
+  //
+  // Note: this documents the aforementioned kernel bug. Ideally this would
+  // *not* be the case.
+  const int priority_after_thread_mode_background_begin =
+      ::GetThreadPriority(thread_handle);
+  EXPECT_EQ(priority_after_thread_mode_background_begin,
+            THREAD_PRIORITY_NORMAL);
+  internal::AssertMemoryPriority(thread_handle, MEMORY_PRIORITY_VERY_LOW);
+
+  PlatformThread::Sleep(base::Seconds(1));
+
+  // After 1 second, GetThreadPriority() and memory priority don't change (this
+  // refutes the hypothesis that it simply takes time before GetThreadPriority()
+  // is updated after entering thread mode background).
+  EXPECT_EQ(::GetThreadPriority(thread_handle),
+            priority_after_thread_mode_background_begin);
+  internal::AssertMemoryPriority(thread_handle, MEMORY_PRIORITY_VERY_LOW);
+
+  // Set the process priority to NORMAL.
+  ::SetPriorityClass(Process::Current().Handle(), NORMAL_PRIORITY_CLASS);
+
+  // GetThreadPriority() and memory priority don't change when the process
+  // priority changes.
+  EXPECT_EQ(::GetThreadPriority(thread_handle),
+            priority_after_thread_mode_background_begin);
+  internal::AssertMemoryPriority(thread_handle, MEMORY_PRIORITY_VERY_LOW);
+
+  // End thread mode background.
+  //
+  // Note: at least "ending" the semi-enforced background mode works...
+  EXPECT_TRUE(::SetThreadPriority(thread_handle, THREAD_MODE_BACKGROUND_END));
+
+  // GetThreadPriority() stays/becomes NORMAL. Memory priority becomes NORMAL.
+  EXPECT_EQ(::GetThreadPriority(thread_handle), THREAD_PRIORITY_NORMAL);
+  internal::AssertMemoryPriority(thread_handle, MEMORY_PRIORITY_NORMAL);
+}
+
+}  // namespace base
diff --git a/base/threading/post_task_and_reply_impl.cc b/base/threading/post_task_and_reply_impl.cc
index 5aacdad..fb72de3 100644
--- a/base/threading/post_task_and_reply_impl.cc
+++ b/base/threading/post_task_and_reply_impl.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -6,12 +6,12 @@
 
 #include <utility>
 
-#include "base/bind.h"
+#include "base/check_op.h"
 #include "base/debug/leak_annotations.h"
-#include "base/logging.h"
+#include "base/functional/bind.h"
 #include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
-#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/thread_pool/thread_pool_instance.h"
 
 namespace base {
 
@@ -21,55 +21,82 @@
  public:
   PostTaskAndReplyRelay(const Location& from_here,
                         OnceClosure task,
-                        OnceClosure reply)
+                        OnceClosure reply,
+                        scoped_refptr<SequencedTaskRunner> reply_task_runner)
       : from_here_(from_here),
         task_(std::move(task)),
-        reply_(std::move(reply)) {}
+        reply_(std::move(reply)),
+        reply_task_runner_(std::move(reply_task_runner)) {}
   PostTaskAndReplyRelay(PostTaskAndReplyRelay&&) = default;
 
+  PostTaskAndReplyRelay(const PostTaskAndReplyRelay&) = delete;
+  PostTaskAndReplyRelay& operator=(const PostTaskAndReplyRelay&) = delete;
+
+  // It is important that |reply_| always be deleted on the origin sequence
+  // (|reply_task_runner_|) since its destructor can be affine to it. More
+  // sutbly, it is also important that |task_| be destroyed on the origin
+  // sequence when it fails to run. This is because |task_| can own state which
+  // is affine to |reply_task_runner_| and was intended to be handed to
+  // |reply_|, e.g. https://crbug.com/829122. Since |task_| already needs to
+  // support deletion on the origin sequence (since the initial PostTask can
+  // always fail), it's safer to delete it there when PostTask succeeds but
+  // |task_| is later prevented from running.
+  //
+  // PostTaskAndReplyRelay's move semantics along with logic in this destructor
+  // enforce the above semantics in all the following cases :
+  //  1) Posting |task_| fails right away on the origin sequence:
+  //    a) |reply_task_runner_| is null (i.e. during late shutdown);
+  //    b) |reply_task_runner_| is set.
+  //  2) ~PostTaskAndReplyRelay() runs on the destination sequence:
+  //    a) RunTaskAndPostReply() is cancelled before running;
+  //    b) RunTaskAndPostReply() is skipped on shutdown;
+  //    c) Posting RunReply() fails.
+  //  3) ~PostTaskAndReplyRelay() runs on the origin sequence:
+  //    a) RunReply() is cancelled before running;
+  //    b) RunReply() is skipped on shutdown;
+  //    c) The DeleteSoon() posted by (2) runs.
+  //  4) ~PostTaskAndReplyRelay() should no-op:
+  //    a) This relay was moved to another relay instance;
+  //    b) RunReply() ran and completed this relay's mandate.
   ~PostTaskAndReplyRelay() {
-    if (reply_) {
-      // This can run:
-      // 1) On origin sequence, when:
-      //    1a) Posting |task_| fails.
-      //    1b) |reply_| is cancelled before running.
-      //    1c) The DeleteSoon() below is scheduled.
-      // 2) On destination sequence, when:
-      //    2a) |task_| is cancelled before running.
-      //    2b) Posting |reply_| fails.
-
-      if (!reply_task_runner_->RunsTasksInCurrentSequence()) {
-        // Case 2a) or 2b).
-        //
-        // Destroy callbacks asynchronously on |reply_task_runner| since their
-        // destructors can rightfully be affine to it. As always, DeleteSoon()
-        // might leak its argument if the target execution environment is
-        // shutdown (e.g. MessageLoop deleted, TaskScheduler shutdown).
-        //
-        // Note: while it's obvious why |reply_| can be affine to
-        // |reply_task_runner|, the reason that |task_| can also be affine to it
-        // is that it if neither tasks ran, |task_| may still hold an object
-        // which was intended to be moved to |reply_| when |task_| ran (such an
-        // object's destruction can be affine to |reply_task_runner_| -- e.g.
-        // https://crbug.com/829122).
-        auto relay_to_delete =
-            std::make_unique<PostTaskAndReplyRelay>(std::move(*this));
-        ANNOTATE_LEAKING_OBJECT_PTR(relay_to_delete.get());
-        reply_task_runner_->DeleteSoon(from_here_, std::move(relay_to_delete));
-      }
-
-      // Case 1a), 1b), 1c).
-      //
-      // Callbacks will be destroyed synchronously at the end of this scope.
-    } else {
-      // This can run when both callbacks have run or have been moved to another
-      // PostTaskAndReplyRelay instance. If |reply_| is null, |task_| must be
-      // null too.
-      DCHECK(!task_);
+    // Case 1a and 4a:
+    if (!reply_task_runner_) {
+      DCHECK_EQ(task_.is_null(), reply_.is_null());
+      return;
     }
+
+    // Case 4b:
+    if (!reply_) {
+      DCHECK(!task_);
+      return;
+    }
+
+    // Case 2:
+    if (!reply_task_runner_->RunsTasksInCurrentSequence()) {
+      DCHECK(reply_);
+      // Allow this task to be leaked on shutdown even if `reply_task_runner_`
+      // has the TaskShutdownBehaviour::BLOCK_SHUTDOWN trait. Without `fizzler`,
+      // such a task runner would DCHECK when posting to `reply_task_runner_`
+      // after shutdown. Ignore this DCHECK as the poster isn't in control when
+      // its Callback is destroyed late into shutdown. Ref. crbug.com/1375270.
+      base::ThreadPoolInstance::ScopedFizzleBlockShutdownTasks fizzler;
+
+      SequencedTaskRunner* reply_task_runner_raw = reply_task_runner_.get();
+      auto relay_to_delete =
+          std::make_unique<PostTaskAndReplyRelay>(std::move(*this));
+      // In case 2c, posting the DeleteSoon will also fail and |relay_to_delete|
+      // will be leaked. This only happens during shutdown and leaking is better
+      // than thread-unsafe execution.
+      ANNOTATE_LEAKING_OBJECT_PTR(relay_to_delete.get());
+      reply_task_runner_raw->DeleteSoon(from_here_, std::move(relay_to_delete));
+      return;
+    }
+
+    // Case 1b and 3: Any remaining state will be destroyed synchronously at the
+    // end of this scope.
   }
 
-  // No assignment operator because of const members.
+  // No assignment operator because of const member.
   PostTaskAndReplyRelay& operator=(PostTaskAndReplyRelay&&) = delete;
 
   // Static function is used because it is not possible to bind a method call to
@@ -78,13 +105,13 @@
     DCHECK(relay.task_);
     std::move(relay.task_).Run();
 
-    // Keep a reference to the reply TaskRunner for the PostTask() call before
+    // Keep a pointer to the reply TaskRunner for the PostTask() call before
     // |relay| is moved into a callback.
-    scoped_refptr<SequencedTaskRunner> reply_task_runner =
-        relay.reply_task_runner_;
+    SequencedTaskRunner* reply_task_runner_raw = relay.reply_task_runner_.get();
 
-    reply_task_runner->PostTask(
-        relay.from_here_,
+    const Location from_here = relay.from_here_;
+    reply_task_runner_raw->PostTask(
+        from_here,
         BindOnce(&PostTaskAndReplyRelay::RunReply, std::move(relay)));
   }
 
@@ -100,10 +127,8 @@
   const Location from_here_;
   OnceClosure task_;
   OnceClosure reply_;
-  const scoped_refptr<SequencedTaskRunner> reply_task_runner_ =
-      SequencedTaskRunnerHandle::Get();
-
-  DISALLOW_COPY_AND_ASSIGN(PostTaskAndReplyRelay);
+  // Not const to allow moving.
+  scoped_refptr<SequencedTaskRunner> reply_task_runner_;
 };
 
 }  // namespace
@@ -116,10 +141,23 @@
   DCHECK(task) << from_here.ToString();
   DCHECK(reply) << from_here.ToString();
 
-  return PostTask(from_here,
-                  BindOnce(&PostTaskAndReplyRelay::RunTaskAndPostReply,
-                           PostTaskAndReplyRelay(from_here, std::move(task),
-                                                 std::move(reply))));
+  const bool has_sequenced_context = SequencedTaskRunner::HasCurrentDefault();
+
+  const bool post_task_success = PostTask(
+      from_here, BindOnce(&PostTaskAndReplyRelay::RunTaskAndPostReply,
+                          PostTaskAndReplyRelay(
+                              from_here, std::move(task), std::move(reply),
+                              has_sequenced_context
+                                  ? SequencedTaskRunner::GetCurrentDefault()
+                                  : nullptr)));
+
+  // PostTaskAndReply() requires a SequencedTaskRunner::CurrentDefaultHandle to
+  // post the reply.  Having no SequencedTaskRunner::CurrentDefaultHandle is
+  // allowed when posting the task fails, to simplify calls during shutdown
+  // (https://crbug.com/922938).
+  CHECK(has_sequenced_context || !post_task_success);
+
+  return post_task_success;
 }
 
 }  // namespace internal
diff --git a/base/threading/post_task_and_reply_impl.h b/base/threading/post_task_and_reply_impl.h
index 388eb11..9e3fda1 100644
--- a/base/threading/post_task_and_reply_impl.h
+++ b/base/threading/post_task_and_reply_impl.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -8,7 +8,7 @@
 #define BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_
 
 #include "base/base_export.h"
-#include "base/callback.h"
+#include "base/functional/callback.h"
 #include "base/location.h"
 
 namespace base {
@@ -18,18 +18,19 @@
 // custom execution context.
 //
 // If you're looking for a concrete implementation of PostTaskAndReply, you
-// probably want base::TaskRunner or base/task/post_task.h
+// probably want a base::TaskRunner (typically obtained from
+// base/task/thread_pool.h).
 class BASE_EXPORT PostTaskAndReplyImpl {
  public:
   virtual ~PostTaskAndReplyImpl() = default;
 
   // Posts |task| by calling PostTask(). On completion, posts |reply| to the
   // origin sequence. Can only be called when
-  // SequencedTaskRunnerHandle::IsSet(). Each callback is deleted synchronously
-  // after running, or scheduled for asynchronous deletion on the origin
-  // sequence if it can't run (e.g. if a TaskRunner skips it on shutdown). See
-  // SequencedTaskRunner::DeleteSoon() for when objects scheduled for
-  // asynchronous deletion can be leaked. Note: All //base task posting APIs
+  // SequencedTaskRunner::HasCurrentDefault(). Each callback is deleted
+  // synchronously after running, or scheduled for asynchronous deletion on the
+  // origin sequence if it can't run (e.g. if a TaskRunner skips it on
+  // shutdown). See SequencedTaskRunner::DeleteSoon() for when objects scheduled
+  // for asynchronous deletion can be leaked. Note: All //base task posting APIs
   // require callbacks to support deletion on the posting sequence if they can't
   // be scheduled.
   bool PostTaskAndReply(const Location& from_here,
diff --git a/base/threading/post_task_and_reply_impl_unittest.cc b/base/threading/post_task_and_reply_impl_unittest.cc
index 319327d..e90ea9f 100644
--- a/base/threading/post_task_and_reply_impl_unittest.cc
+++ b/base/threading/post_task_and_reply_impl_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -7,10 +7,11 @@
 #include <utility>
 
 #include "base/auto_reset.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/macros.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
+#include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
+#include "base/task/sequenced_task_runner.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -33,7 +34,7 @@
   }
 
   // Non-owning.
-  TaskRunner* const destination_;
+  const raw_ptr<TaskRunner> destination_;
 };
 
 class ObjectToDelete : public RefCounted<ObjectToDelete> {
@@ -43,24 +44,25 @@
     EXPECT_FALSE(*delete_flag_);
   }
 
+  ObjectToDelete(const ObjectToDelete&) = delete;
+  ObjectToDelete& operator=(const ObjectToDelete&) = delete;
+
  private:
   friend class RefCounted<ObjectToDelete>;
   ~ObjectToDelete() { *delete_flag_ = true; }
 
-  bool* const delete_flag_;
-
-  DISALLOW_COPY_AND_ASSIGN(ObjectToDelete);
+  const raw_ptr<bool> delete_flag_;
 };
 
 class MockObject {
  public:
   MockObject() = default;
 
+  MockObject(const MockObject&) = delete;
+  MockObject& operator=(const MockObject&) = delete;
+
   MOCK_METHOD1(Task, void(scoped_refptr<ObjectToDelete>));
   MOCK_METHOD1(Reply, void(scoped_refptr<ObjectToDelete>));
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockObject);
 };
 
 class MockRunsTasksInCurrentSequenceTaskRunner : public TestMockTimeTaskRunner {
@@ -70,6 +72,13 @@
           TestMockTimeTaskRunner::Type::kStandalone)
       : TestMockTimeTaskRunner(type) {}
 
+  MockRunsTasksInCurrentSequenceTaskRunner(
+      const MockRunsTasksInCurrentSequenceTaskRunner&) = delete;
+  MockRunsTasksInCurrentSequenceTaskRunner& operator=(
+      const MockRunsTasksInCurrentSequenceTaskRunner&) = delete;
+
+  void StopAcceptingTasks() { accepts_tasks_ = false; }
+
   void RunUntilIdleWithRunsTasksInCurrentSequence() {
     AutoReset<bool> reset(&runs_tasks_in_current_sequence_, true);
     RunUntilIdle();
@@ -85,28 +94,44 @@
     return runs_tasks_in_current_sequence_;
   }
 
+  bool PostDelayedTask(const Location& from_here,
+                       OnceClosure task,
+                       TimeDelta delay) override {
+    if (!accepts_tasks_)
+      return false;
+
+    return TestMockTimeTaskRunner::PostDelayedTask(from_here, std::move(task),
+                                                   delay);
+  }
+
  private:
   ~MockRunsTasksInCurrentSequenceTaskRunner() override = default;
 
+  bool accepts_tasks_ = true;
   bool runs_tasks_in_current_sequence_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(MockRunsTasksInCurrentSequenceTaskRunner);
 };
 
 class PostTaskAndReplyImplTest : public testing::Test {
+ public:
+  PostTaskAndReplyImplTest(const PostTaskAndReplyImplTest&) = delete;
+  PostTaskAndReplyImplTest& operator=(const PostTaskAndReplyImplTest&) = delete;
+
  protected:
   PostTaskAndReplyImplTest() = default;
 
-  void PostTaskAndReplyToMockObject() {
+  bool PostTaskAndReplyToMockObject() {
+    return PostTaskAndReplyTaskRunner(post_runner_.get())
+        .PostTaskAndReply(
+            FROM_HERE,
+            BindOnce(&MockObject::Task, Unretained(&mock_object_),
+                     MakeRefCounted<ObjectToDelete>(&delete_task_flag_)),
+            BindOnce(&MockObject::Reply, Unretained(&mock_object_),
+                     MakeRefCounted<ObjectToDelete>(&delete_reply_flag_)));
+  }
+
+  void ExpectPostTaskAndReplyToMockObjectSucceeds() {
     // Expect the post to succeed.
-    EXPECT_TRUE(
-        PostTaskAndReplyTaskRunner(post_runner_.get())
-            .PostTaskAndReply(
-                FROM_HERE,
-                BindOnce(&MockObject::Task, Unretained(&mock_object_),
-                         MakeRefCounted<ObjectToDelete>(&delete_task_flag_)),
-                BindOnce(&MockObject::Reply, Unretained(&mock_object_),
-                         MakeRefCounted<ObjectToDelete>(&delete_reply_flag_))));
+    EXPECT_TRUE(PostTaskAndReplyToMockObject());
 
     // Expect the first task to be posted to |post_runner_|.
     EXPECT_TRUE(post_runner_->HasPendingTask());
@@ -123,15 +148,12 @@
   testing::StrictMock<MockObject> mock_object_;
   bool delete_task_flag_ = false;
   bool delete_reply_flag_ = false;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(PostTaskAndReplyImplTest);
 };
 
 }  // namespace
 
 TEST_F(PostTaskAndReplyImplTest, PostTaskAndReply) {
-  PostTaskAndReplyToMockObject();
+  ExpectPostTaskAndReplyToMockObjectSucceeds();
 
   EXPECT_CALL(mock_object_, Task(_));
   post_runner_->RunUntilIdleWithRunsTasksInCurrentSequence();
@@ -157,7 +179,7 @@
 }
 
 TEST_F(PostTaskAndReplyImplTest, TaskDoesNotRun) {
-  PostTaskAndReplyToMockObject();
+  ExpectPostTaskAndReplyToMockObjectSucceeds();
 
   // Clear the |post_runner_|. Both callbacks should be scheduled for deletion
   // on the |reply_runner_|.
@@ -174,7 +196,7 @@
 }
 
 TEST_F(PostTaskAndReplyImplTest, ReplyDoesNotRun) {
-  PostTaskAndReplyToMockObject();
+  ExpectPostTaskAndReplyToMockObjectSucceeds();
 
   EXPECT_CALL(mock_object_, Task(_));
   post_runner_->RunUntilIdleWithRunsTasksInCurrentSequence();
@@ -194,5 +216,20 @@
   EXPECT_TRUE(delete_reply_flag_);
 }
 
+// This is a regression test for crbug.com/922938.
+TEST_F(PostTaskAndReplyImplTest,
+       PostTaskToStoppedTaskRunnerWithoutSequencedContext) {
+  reply_runner_.reset();
+  EXPECT_FALSE(SequencedTaskRunner::HasCurrentDefault());
+  post_runner_->StopAcceptingTasks();
+
+  // Expect the post to return false, but not to crash.
+  EXPECT_FALSE(PostTaskAndReplyToMockObject());
+
+  // Expect all tasks to be deleted.
+  EXPECT_TRUE(delete_task_flag_);
+  EXPECT_TRUE(delete_reply_flag_);
+}
+
 }  // namespace internal
 }  // namespace base
diff --git a/base/threading/scoped_blocking_call.cc b/base/threading/scoped_blocking_call.cc
index 127bc11..e1c3679 100644
--- a/base/threading/scoped_blocking_call.cc
+++ b/base/threading/scoped_blocking_call.cc
@@ -1,91 +1,130 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/scoped_blocking_call.h"
 
 #include "base/lazy_instance.h"
-#include "base/scoped_clear_last_error.h"
 #include "base/threading/thread_local.h"
 #include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+#include "base/trace_event/base_tracing.h"
+#include "base/tracing_buildflags.h"
+#include "build/build_config.h"
+
+#if BUILDFLAG(ENABLE_BASE_TRACING)
+#include "third_party/perfetto/protos/perfetto/trace/track_event/source_location.pbzero.h"  // nogncheck
+#endif  // BUILDFLAG(ENABLE_BASE_TRACING)
+
+#if DCHECK_IS_ON()
+#include "base/auto_reset.h"
+#include "third_party/abseil-cpp/absl/base/attributes.h"
+#if defined(STARBOARD)
+#include <pthread.h>
+
+#include "base/check_op.h"
+#include "starboard/thread.h"
+#endif
+#endif
 
 namespace base {
 
 namespace {
 
-LazyInstance<ThreadLocalPointer<internal::BlockingObserver>>::Leaky
-    tls_blocking_observer = LAZY_INSTANCE_INITIALIZER;
+#if DCHECK_IS_ON()
+#if defined(STARBOARD)
+ABSL_CONST_INIT pthread_once_t s_once_flag = PTHREAD_ONCE_INIT;
+ABSL_CONST_INIT pthread_key_t s_thread_local_key = 0;
 
-// Last ScopedBlockingCall instantiated on this thread.
-LazyInstance<ThreadLocalPointer<internal::UncheckedScopedBlockingCall>>::Leaky
-    tls_last_scoped_blocking_call = LAZY_INSTANCE_INITIALIZER;
+void InitThreadLocalKey() {
+  int res = pthread_key_create(&s_thread_local_key , NULL);
+  DCHECK(res == 0);
+}
+
+void EnsureThreadLocalKeyInited() {
+  pthread_once(&s_once_flag, InitThreadLocalKey);
+}
+
+bool GetConstructionInProgress() {
+  EnsureThreadLocalKeyInited();
+  void* construction_in_progress = pthread_getspecific(s_thread_local_key);
+  return !!construction_in_progress ? reinterpret_cast<intptr_t>(construction_in_progress) != 0 : false;
+}
+#else
+// Used to verify that the trace events used in the constructor do not result in
+// instantiating a ScopedBlockingCall themselves (which would cause an infinite
+// reentrancy loop).
+ABSL_CONST_INIT thread_local bool construction_in_progress = false;
+#endif
+#endif
 
 }  // namespace
 
-namespace internal {
+ScopedBlockingCall::ScopedBlockingCall(const Location& from_here,
+                                       BlockingType blocking_type)
+    : UncheckedScopedBlockingCall(
+          blocking_type,
+          UncheckedScopedBlockingCall::BlockingCallType::kRegular) {
+#if DCHECK_IS_ON()
+#if defined(STARBOARD)
+  EnsureThreadLocalKeyInited();
+  pthread_setspecific(s_thread_local_key, reinterpret_cast<void*>(static_cast<intptr_t>(true)));
+#else
+  const AutoReset<bool> resetter(&construction_in_progress, true, false);
+#endif
+#endif
 
-UncheckedScopedBlockingCall::UncheckedScopedBlockingCall(
-    BlockingType blocking_type)
-    : blocking_observer_(tls_blocking_observer.Get().Get()),
-      previous_scoped_blocking_call_(tls_last_scoped_blocking_call.Get().Get()),
-      is_will_block_(blocking_type == BlockingType::WILL_BLOCK ||
-                     (previous_scoped_blocking_call_ &&
-                      previous_scoped_blocking_call_->is_will_block_)) {
-  tls_last_scoped_blocking_call.Get().Set(this);
+  internal::AssertBlockingAllowed();
+  TRACE_EVENT_BEGIN(
+      "base", "ScopedBlockingCall", [&](perfetto::EventContext ctx) {
+        ctx.event()->set_source_location_iid(
+            base::trace_event::InternedSourceLocation::Get(&ctx, from_here));
+      });
 
-  if (blocking_observer_) {
-    if (!previous_scoped_blocking_call_) {
-      blocking_observer_->BlockingStarted(blocking_type);
-    } else if (blocking_type == BlockingType::WILL_BLOCK &&
-               !previous_scoped_blocking_call_->is_will_block_) {
-      blocking_observer_->BlockingTypeUpgraded();
-    }
-  }
+#if DCHECK_IS_ON() && defined(STARBOARD)
+  pthread_setspecific(s_thread_local_key, reinterpret_cast<void*>(static_cast<intptr_t>(false)));
+#endif
 }
 
-UncheckedScopedBlockingCall::~UncheckedScopedBlockingCall() {
-  // TLS affects result of GetLastError() on Windows. ScopedClearLastError
-  // prevents side effect.
-  base::internal::ScopedClearLastError save_last_error;
-  DCHECK_EQ(this, tls_last_scoped_blocking_call.Get().Get());
-  tls_last_scoped_blocking_call.Get().Set(previous_scoped_blocking_call_);
-  if (blocking_observer_ && !previous_scoped_blocking_call_)
-    blocking_observer_->BlockingEnded();
-}
-
-}  // namespace internal
-
-ScopedBlockingCall::ScopedBlockingCall(BlockingType blocking_type)
-    : UncheckedScopedBlockingCall(blocking_type) {
-  base::AssertBlockingAllowed();
+ScopedBlockingCall::~ScopedBlockingCall() {
+  TRACE_EVENT_END("base");
 }
 
 namespace internal {
 
 ScopedBlockingCallWithBaseSyncPrimitives::
-    ScopedBlockingCallWithBaseSyncPrimitives(BlockingType blocking_type)
-    : UncheckedScopedBlockingCall(blocking_type) {
+    ScopedBlockingCallWithBaseSyncPrimitives(const Location& from_here,
+                                             BlockingType blocking_type)
+    : UncheckedScopedBlockingCall(
+          blocking_type,
+          UncheckedScopedBlockingCall::BlockingCallType::kBaseSyncPrimitives) {
+#if DCHECK_IS_ON()
+#if defined(STARBOARD)
+  EnsureThreadLocalKeyInited();
+  pthread_setspecific(s_thread_local_key, reinterpret_cast<void*>(static_cast<intptr_t>(true)));
+#else
+  const AutoReset<bool> resetter(&construction_in_progress, true, false);
+#endif
+#endif
+
   internal::AssertBaseSyncPrimitivesAllowed();
+  TRACE_EVENT_BEGIN(
+      "base", "ScopedBlockingCallWithBaseSyncPrimitives",
+      [&](perfetto::EventContext ctx) {
+        perfetto::protos::pbzero::SourceLocation* source_location_data =
+            ctx.event()->set_source_location();
+        source_location_data->set_file_name(from_here.file_name());
+        source_location_data->set_function_name(from_here.function_name());
+      });
+
+#if DCHECK_IS_ON() && defined(STARBOARD)
+  pthread_setspecific(s_thread_local_key, reinterpret_cast<void*>(static_cast<intptr_t>(false)));
+#endif
 }
 
-void SetBlockingObserverForCurrentThread(BlockingObserver* blocking_observer) {
-  DCHECK(!tls_blocking_observer.Get().Get());
-  tls_blocking_observer.Get().Set(blocking_observer);
-}
-
-void ClearBlockingObserverForTesting() {
-  tls_blocking_observer.Get().Set(nullptr);
-}
-
-ScopedClearBlockingObserverForTesting::ScopedClearBlockingObserverForTesting()
-    : blocking_observer_(tls_blocking_observer.Get().Get()) {
-  tls_blocking_observer.Get().Set(nullptr);
-}
-
-ScopedClearBlockingObserverForTesting::
-    ~ScopedClearBlockingObserverForTesting() {
-  DCHECK(!tls_blocking_observer.Get().Get());
-  tls_blocking_observer.Get().Set(blocking_observer_);
+ScopedBlockingCallWithBaseSyncPrimitives::
+    ~ScopedBlockingCallWithBaseSyncPrimitives() {
+  TRACE_EVENT_END("base");
 }
 
 }  // namespace internal
diff --git a/base/threading/scoped_blocking_call.h b/base/threading/scoped_blocking_call.h
index 516ac0a..1f37ca2 100644
--- a/base/threading/scoped_blocking_call.h
+++ b/base/threading/scoped_blocking_call.h
@@ -1,12 +1,16 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef BASE_THREADING_SCOPED_BLOCKING_CALL_H
-#define BASE_THREADING_SCOPED_BLOCKING_CALL_H
+#ifndef BASE_THREADING_SCOPED_BLOCKING_CALL_H_
+#define BASE_THREADING_SCOPED_BLOCKING_CALL_H_
 
 #include "base/base_export.h"
-#include "base/logging.h"
+#include "base/functional/callback_forward.h"
+#include "base/location.h"
+#include "base/strings/string_piece.h"
+#include "base/threading/scoped_blocking_call_internal.h"
+#include "base/types/strong_alias.h"
 
 namespace base {
 
@@ -26,32 +30,6 @@
   WILL_BLOCK
 };
 
-namespace internal {
-
-class BlockingObserver;
-
-// Common implementation class for both ScopedBlockingCall and
-// ScopedBlockingCallWithBaseSyncPrimitives without assertions.
-class BASE_EXPORT UncheckedScopedBlockingCall {
- public:
-  UncheckedScopedBlockingCall(BlockingType blocking_type);
-  ~UncheckedScopedBlockingCall();
-
- private:
-  internal::BlockingObserver* const blocking_observer_;
-
-  // Previous ScopedBlockingCall instantiated on this thread.
-  UncheckedScopedBlockingCall* const previous_scoped_blocking_call_;
-
-  // Whether the BlockingType of the current thread was WILL_BLOCK after this
-  // ScopedBlockingCall was instantiated.
-  const bool is_will_block_;
-
-  DISALLOW_COPY_AND_ASSIGN(UncheckedScopedBlockingCall);
-};
-
-}  // namespace internal
-
 // This class must be instantiated in every scope where a blocking call is made
 // and serves as a precise annotation of the scope that may/will block for the
 // scheduler. When a ScopedBlockingCall is instantiated, it asserts that
@@ -66,13 +44,15 @@
 // Good:
 //   Data data;
 //   {
-//     ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
+//     ScopedBlockingCall scoped_blocking_call(
+//         FROM_HERE, BlockingType::WILL_BLOCK);
 //     data = GetDataFromNetwork();
 //   }
 //   CPUIntensiveProcessing(data);
 //
 // Bad:
-//   ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
+//   ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+//       BlockingType::WILL_BLOCK);
 //   Data data = GetDataFromNetwork();
 //   CPUIntensiveProcessing(data);  // CPU usage within a ScopedBlockingCall.
 //
@@ -80,7 +60,8 @@
 //   Data a;
 //   Data b;
 //   {
-//     ScopedBlockingCall scoped_blocking_call(BlockingType::MAY_BLOCK);
+//     ScopedBlockingCall scoped_blocking_call(
+//         FROM_HERE, BlockingType::MAY_BLOCK);
 //     a = GetDataFromMemoryCacheOrNetwork();
 //     b = GetDataFromMemoryCacheOrNetwork();
 //   }
@@ -88,7 +69,8 @@
 //   CPUIntensiveProcessing(b);
 //
 // Bad:
-//   ScopedBlockingCall scoped_blocking_call(BlockingType::MAY_BLOCK);
+//   ScopedBlockingCall scoped_blocking_call(
+//       FROM_HERE, BlockingType::MAY_BLOCK);
 //   Data a = GetDataFromMemoryCacheOrNetwork();
 //   Data b = GetDataFromMemoryCacheOrNetwork();
 //   CPUIntensiveProcessing(a);  // CPU usage within a ScopedBlockingCall.
@@ -100,19 +82,21 @@
 //
 // Bad:
 //  base::WaitableEvent waitable_event(...);
-//  ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
+//  ScopedBlockingCall scoped_blocking_call(
+//      FROM_HERE, BlockingType::WILL_BLOCK);
 //  waitable_event.Wait();  // Wait() instantiates its own ScopedBlockingCall.
 //
-// When a ScopedBlockingCall is instantiated from a TaskScheduler parallel or
+// When a ScopedBlockingCall is instantiated from a ThreadPool parallel or
 // sequenced task, the thread pool size is incremented to compensate for the
 // blocked thread (more or less aggressively depending on BlockingType).
-class BASE_EXPORT ScopedBlockingCall
+class BASE_EXPORT [[nodiscard]] ScopedBlockingCall
     : public internal::UncheckedScopedBlockingCall {
  public:
-  ScopedBlockingCall(BlockingType blocking_type);
-  ~ScopedBlockingCall() = default;
+  ScopedBlockingCall(const Location& from_here, BlockingType blocking_type);
+  ~ScopedBlockingCall();
 };
 
+// Usage reserved for //base callers.
 namespace internal {
 
 // This class must be instantiated in every scope where a sync primitive is
@@ -120,56 +104,35 @@
 // asserts that sync primitives are allowed in its scope with a call to
 // internal::AssertBaseSyncPrimitivesAllowed(). The same guidelines as for
 // ScopedBlockingCall should be followed.
-class BASE_EXPORT ScopedBlockingCallWithBaseSyncPrimitives
+class BASE_EXPORT [[nodiscard]] ScopedBlockingCallWithBaseSyncPrimitives
     : public UncheckedScopedBlockingCall {
  public:
-  ScopedBlockingCallWithBaseSyncPrimitives(BlockingType blocking_type);
-  ~ScopedBlockingCallWithBaseSyncPrimitives() = default;
-};
-
-// Interface for an observer to be informed when a thread enters or exits
-// the scope of ScopedBlockingCall objects.
-class BASE_EXPORT BlockingObserver {
- public:
-  virtual ~BlockingObserver() = default;
-
-  // Invoked when a ScopedBlockingCall is instantiated on the observed thread
-  // where there wasn't an existing ScopedBlockingCall.
-  virtual void BlockingStarted(BlockingType blocking_type) = 0;
-
-  // Invoked when a WILL_BLOCK ScopedBlockingCall is instantiated on the
-  // observed thread where there was a MAY_BLOCK ScopedBlockingCall but not a
-  // WILL_BLOCK ScopedBlockingCall.
-  virtual void BlockingTypeUpgraded() = 0;
-
-  // Invoked when the last ScopedBlockingCall on the observed thread is
-  // destroyed.
-  virtual void BlockingEnded() = 0;
-};
-
-// Registers |blocking_observer| on the current thread. It is invalid to call
-// this on a thread where there is an active ScopedBlockingCall.
-BASE_EXPORT void SetBlockingObserverForCurrentThread(
-    BlockingObserver* blocking_observer);
-
-BASE_EXPORT void ClearBlockingObserverForTesting();
-
-// Unregisters the |blocking_observer| on the current thread within its scope.
-// Used in TaskScheduler tests to prevent calls to //base sync primitives from
-// affecting the thread pool capacity.
-class BASE_EXPORT ScopedClearBlockingObserverForTesting {
- public:
-  ScopedClearBlockingObserverForTesting();
-  ~ScopedClearBlockingObserverForTesting();
-
- private:
-  BlockingObserver* const blocking_observer_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedClearBlockingObserverForTesting);
+  ScopedBlockingCallWithBaseSyncPrimitives(const Location& from_here,
+                                           BlockingType blocking_type);
+  ~ScopedBlockingCallWithBaseSyncPrimitives();
 };
 
 }  // namespace internal
 
+using IOJankReportingCallback =
+    RepeatingCallback<void(int janky_intervals_per_minute,
+                           int total_janks_per_minute)>;
+using OnlyObservedThreadsForTest =
+    StrongAlias<class OnlyObservedThreadsTag, bool>;
+// Enables IO jank monitoring and reporting for this process. Should be called
+// at most once per process and only if
+// base::TimeTicks::IsConsistentAcrossProcesses() (the algorithm is unsafe
+// otherwise). |reporting_callback| will be invoked each time a monitoring
+// window completes, see internal::~IOJankMonitoringWindow() for details
+// (must be thread-safe). |only_observed_threads| can be set to true to have
+// the IOJank implementation ignore ScopedBlockingCalls on threads without a
+// BlockingObserver in tests that need to deterministically observe
+// ScopedBlockingCall side-effects.
+void BASE_EXPORT EnableIOJankMonitoringForProcess(
+    IOJankReportingCallback reporting_callback,
+    OnlyObservedThreadsForTest only_observed_threads =
+        OnlyObservedThreadsForTest(false));
+
 }  // namespace base
 
-#endif  // BASE_THREADING_SCOPED_BLOCKING_CALL_H
+#endif  // BASE_THREADING_SCOPED_BLOCKING_CALL_H_
diff --git a/base/threading/scoped_blocking_call_internal.cc b/base/threading/scoped_blocking_call_internal.cc
new file mode 100644
index 0000000..adaaf17
--- /dev/null
+++ b/base/threading/scoped_blocking_call_internal.cc
@@ -0,0 +1,457 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/scoped_blocking_call_internal.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/check_op.h"
+#include "base/compiler_specific.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
+#include "base/no_destructor.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/scoped_clear_last_error.h"
+#include "base/task/scoped_set_task_priority_for_current_thread.h"
+#include "base/task/thread_pool.h"
+#include "base/task/thread_pool/environment_config.h"
+#include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/threading/scoped_blocking_call.h"
+#include "build/build_config.h"
+#include "third_party/abseil-cpp/absl/base/attributes.h"
+
+#if defined(STARBOARD)
+#include <pthread.h>
+
+#include "starboard/thread.h"
+#endif
+
+namespace base {
+namespace internal {
+
+namespace {
+
+#if defined(STARBOARD)
+ABSL_CONST_INIT pthread_once_t s_once_observer_flag = PTHREAD_ONCE_INIT;
+ABSL_CONST_INIT pthread_key_t s_thread_local_observer_key = 0;
+ABSL_CONST_INIT pthread_once_t s_once_call_flag = PTHREAD_ONCE_INIT;
+ABSL_CONST_INIT pthread_key_t s_thread_local_call_key = 0;
+
+void InitThreadLocalObserverKey() {
+  int res = pthread_key_create(&s_thread_local_observer_key , NULL);
+  DCHECK(res == 0);
+}
+
+void InitThreadLocalCallKey() {
+  int res = pthread_key_create(&s_thread_local_call_key , NULL);
+  DCHECK(res == 0);
+}
+
+void EnsureThreadLocalObserverKeyInited() {
+  pthread_once(&s_once_observer_flag, InitThreadLocalObserverKey);
+}
+
+void EnsureThreadLocalCallKeyInited() {
+  pthread_once(&s_once_call_flag, InitThreadLocalCallKey);
+}
+#else
+ABSL_CONST_INIT thread_local BlockingObserver* blocking_observer = nullptr;
+
+// Last ScopedBlockingCall instantiated on this thread.
+ABSL_CONST_INIT thread_local UncheckedScopedBlockingCall*
+    last_scoped_blocking_call = nullptr;
+#endif
+
+// These functions can be removed, and the calls below replaced with direct
+// variable accesses, once the MSAN workaround is not necessary.
+BlockingObserver* GetBlockingObserver() {
+#if defined(STARBOARD)
+  EnsureThreadLocalObserverKeyInited();
+  return static_cast<BlockingObserver*>(
+      pthread_getspecific(s_thread_local_observer_key));
+#else
+  // Workaround false-positive MSAN use-of-uninitialized-value on
+  // thread_local storage for loaded libraries:
+  // https://github.com/google/sanitizers/issues/1265
+  MSAN_UNPOISON(&blocking_observer, sizeof(BlockingObserver*));
+
+  return blocking_observer;
+#endif
+}
+UncheckedScopedBlockingCall* GetLastScopedBlockingCall() {
+#if defined(STARBOARD)
+  EnsureThreadLocalCallKeyInited();
+  return static_cast<UncheckedScopedBlockingCall*>(
+      pthread_getspecific(s_thread_local_call_key));
+#else
+  // Workaround false-positive MSAN use-of-uninitialized-value on
+  // thread_local storage for loaded libraries:
+  // https://github.com/google/sanitizers/issues/1265
+  MSAN_UNPOISON(&last_scoped_blocking_call,
+                sizeof(UncheckedScopedBlockingCall*));
+
+  return last_scoped_blocking_call;
+#endif
+}
+
+// Set to true by scoped_blocking_call_unittest to ensure unrelated threads
+// entering ScopedBlockingCalls don't affect test outcomes.
+bool g_only_monitor_observed_threads = false;
+
+bool IsBackgroundPriorityWorker() {
+  return GetTaskPriorityForCurrentThread() == TaskPriority::BEST_EFFORT &&
+         CanUseBackgroundThreadTypeForWorkerThread();
+}
+
+}  // namespace
+
+void SetBlockingObserverForCurrentThread(
+    BlockingObserver* new_blocking_observer) {
+  DCHECK(!GetBlockingObserver());
+#if defined(STARBOARD)
+  EnsureThreadLocalObserverKeyInited();
+  pthread_setspecific(s_thread_local_observer_key, new_blocking_observer);
+#else
+  blocking_observer = new_blocking_observer;
+#endif
+}
+
+void ClearBlockingObserverForCurrentThread() {
+#if defined(STARBOARD)
+  EnsureThreadLocalObserverKeyInited();
+  pthread_setspecific(s_thread_local_observer_key, nullptr);
+#else
+  blocking_observer = nullptr;
+#endif
+}
+
+IOJankMonitoringWindow::ScopedMonitoredCall::ScopedMonitoredCall()
+    : call_start_(TimeTicks::Now()),
+      assigned_jank_window_(MonitorNextJankWindowIfNecessary(call_start_)) {
+  if (assigned_jank_window_ &&
+      call_start_ < assigned_jank_window_->start_time_) {
+    // Sampling |call_start_| and being assigned an IOJankMonitoringWindow is
+    // racy. It is possible that |call_start_| is sampled near the very end of
+    // the current window; meanwhile, another ScopedMonitoredCall on another
+    // thread samples a |call_start_| which lands in the next window. If that
+    // thread beats this one to MonitorNextJankWindowIfNecessary(), this thread
+    // will incorrectly be assigned that window (in the future w.r.t. to its
+    // |call_start_|). To avoid OOB-indexing in AddJank(), crbug.com/1209622, it
+    // is necessary to correct this by bumping |call_start_| to the received
+    // window's |start_time_|.
+    //
+    // Note: The alternate approach of getting |assigned_jank_window_| before
+    // |call_start_| has the opposite problem where |call_start_| can be more
+    // than kNumIntervals ahead of |start_time_| when sampling across the window
+    // boundary, resulting in OOB-indexing the other way. To solve that a loop
+    // would be required (re-getting the latest window and re-sampling
+    // |call_start_| until the condition holds). The loopless solution is thus
+    // preferred.
+    //
+    // A lock covering this entire constructor is also undesired because of the
+    // lock-free logic at the end of MonitorNextJankWindowIfNecessary().
+    call_start_ = assigned_jank_window_->start_time_;
+  }
+}
+
+IOJankMonitoringWindow::ScopedMonitoredCall::~ScopedMonitoredCall() {
+  if (assigned_jank_window_) {
+    assigned_jank_window_->OnBlockingCallCompleted(call_start_,
+                                                   TimeTicks::Now());
+  }
+}
+
+void IOJankMonitoringWindow::ScopedMonitoredCall::Cancel() {
+  assigned_jank_window_ = nullptr;
+}
+
+IOJankMonitoringWindow::IOJankMonitoringWindow(TimeTicks start_time)
+    : start_time_(start_time) {}
+
+// static
+void IOJankMonitoringWindow::CancelMonitoringForTesting() {
+  g_only_monitor_observed_threads = false;
+  AutoLock lock(current_jank_window_lock());
+  current_jank_window_storage() = nullptr;
+  reporting_callback_storage() = NullCallback();
+}
+
+// static
+constexpr TimeDelta IOJankMonitoringWindow::kIOJankInterval;
+// static
+constexpr TimeDelta IOJankMonitoringWindow::kMonitoringWindow;
+// static
+constexpr TimeDelta IOJankMonitoringWindow::kTimeDiscrepancyTimeout;
+// static
+constexpr int IOJankMonitoringWindow::kNumIntervals;
+
+// static
+scoped_refptr<IOJankMonitoringWindow>
+IOJankMonitoringWindow::MonitorNextJankWindowIfNecessary(TimeTicks recent_now) {
+  DCHECK_GE(TimeTicks::Now(), recent_now);
+
+  scoped_refptr<IOJankMonitoringWindow> next_jank_window;
+
+  {
+    AutoLock lock(current_jank_window_lock());
+
+    if (!reporting_callback_storage())
+      return nullptr;
+
+    scoped_refptr<IOJankMonitoringWindow>& current_jank_window_ref =
+        current_jank_window_storage();
+
+    // Start the next window immediately after the current one (rather than
+    // based on Now() to avoid uncovered gaps). Only use Now() for the very
+    // first window in a monitoring chain.
+    TimeTicks next_window_start_time =
+        current_jank_window_ref
+            ? current_jank_window_ref->start_time_ + kMonitoringWindow
+            : recent_now;
+
+    if (next_window_start_time > recent_now) {
+      // Another thread beat us to constructing the next monitoring window and
+      // |current_jank_window_ref| already covers |recent_now|.
+      return current_jank_window_ref;
+    }
+
+    if (recent_now - next_window_start_time >= kTimeDiscrepancyTimeout) {
+      // If the delayed task runs on a regular heartbeat, |recent_now| should be
+      // roughly equal to |next_window_start_time|. If we miss by more than
+      // kTimeDiscrepancyTimeout, we likely hit machine sleep, cancel sampling
+      // that window in that case.
+      //
+      // Note: It is safe to touch |canceled_| without a lock here as this is
+      // the only time it's set and it naturally happens-before
+      // |current_jank_window_ref|'s destructor reads it.
+      current_jank_window_ref->canceled_ = true;
+      next_window_start_time = recent_now;
+    }
+
+    next_jank_window =
+        MakeRefCounted<IOJankMonitoringWindow>(next_window_start_time);
+
+    if (current_jank_window_ref && !current_jank_window_ref->canceled_) {
+      // If there are still IO operations in progress within
+      // |current_jank_window_ref|, they have a ref to it and will be the ones
+      // triggering ~IOJankMonitoringWindow(). When doing so, they will overlap
+      // into the |next_jank_window| we are setting up (|next_| will also own a
+      // ref so a very long jank can safely unwind across a chain of pending
+      // |next_|'s).
+      DCHECK(!current_jank_window_ref->next_);
+      current_jank_window_ref->next_ = next_jank_window;
+    }
+
+    // Make |next_jank_window| the new current before releasing the lock.
+    current_jank_window_ref = next_jank_window;
+  }
+
+  // Post a task to kick off the next monitoring window if no monitored thread
+  // beats us to it. Adjust the timing to alleviate any drift in the timer. Do
+  // this outside the lock to avoid scheduling tasks while holding it.
+  ThreadPool::PostDelayedTask(
+      FROM_HERE, BindOnce([]() {
+        IOJankMonitoringWindow::MonitorNextJankWindowIfNecessary(
+            TimeTicks::Now());
+      }),
+      kMonitoringWindow - (recent_now - next_jank_window->start_time_));
+
+  return next_jank_window;
+}
+
+// NO_THREAD_SAFETY_ANALYSIS because ~RefCountedThreadSafe() guarantees we're
+// the last ones to access this state (and ordered after all other accesses).
+IOJankMonitoringWindow::~IOJankMonitoringWindow() NO_THREAD_SAFETY_ANALYSIS {
+  if (canceled_)
+    return;
+
+  int janky_intervals_count = 0;
+  int total_jank_count = 0;
+
+  for (size_t interval_jank_count : intervals_jank_count_) {
+    if (interval_jank_count > 0) {
+      ++janky_intervals_count;
+      total_jank_count += interval_jank_count;
+    }
+  }
+
+  // reporting_callback_storage() is safe to access without lock because an
+  // IOJankMonitoringWindow existing means we're after the call to
+  // EnableIOJankMonitoringForProcess() and it will not change after that call.
+  DCHECK(reporting_callback_storage());
+  reporting_callback_storage().Run(janky_intervals_count, total_jank_count);
+}
+
+void IOJankMonitoringWindow::OnBlockingCallCompleted(TimeTicks call_start,
+                                                     TimeTicks call_end) {
+  // Confirm we never hit a case of TimeTicks going backwards on the same thread
+  // nor of TimeTicks rolling over the int64_t boundary (which would break
+  // comparison operators).
+  DCHECK_LE(call_start, call_end);
+
+  if (call_end - call_start < kIOJankInterval)
+    return;
+
+  // Make sure the chain of |next_| pointers is sufficient to reach
+  // |call_end| (e.g. if this runs before the delayed task kicks in)
+  if (call_end >= start_time_ + kMonitoringWindow)
+    MonitorNextJankWindowIfNecessary(call_end);
+
+  // Begin attributing jank to the first interval in which it appeared, no
+  // matter how far into the interval the jank began.
+  const int jank_start_index =
+      ClampFloor((call_start - start_time_) / kIOJankInterval);
+
+  // Round the jank duration so the total number of intervals marked janky is as
+  // close as possible to the actual jank duration.
+  const int num_janky_intervals =
+      ClampRound((call_end - call_start) / kIOJankInterval);
+
+  AddJank(jank_start_index, num_janky_intervals);
+}
+
+void IOJankMonitoringWindow::AddJank(int local_jank_start_index,
+                                     int num_janky_intervals) {
+  DCHECK_GE(local_jank_start_index, 0);
+  DCHECK_LT(local_jank_start_index, kNumIntervals);
+
+  // Increment jank counts for intervals in this window. If
+  // |num_janky_intervals| lands beyond kNumIntervals, the additional intervals
+  // will be reported to |next_|.
+  const int jank_end_index = local_jank_start_index + num_janky_intervals;
+  const int local_jank_end_index = std::min(kNumIntervals, jank_end_index);
+
+  {
+    // Note: while this window could be |canceled| here we must add our count
+    // unconditionally as it is only thread-safe to read |canceled| in
+    // ~IOJankMonitoringWindow().
+    AutoLock lock(intervals_lock_);
+    for (int i = local_jank_start_index; i < local_jank_end_index; ++i)
+      ++intervals_jank_count_[i];
+  }
+
+  if (jank_end_index != local_jank_end_index) {
+    // OnBlockingCallCompleted() should have already ensured there's a |next_|
+    // chain covering |num_janky_intervals| unless it caused this to be
+    // |canceled_|. Exceptionally for this check, reading these fields when
+    // they're expected to be true is thread-safe as their only modification
+    // happened-before this point.
+    DCHECK(next_ || canceled_);
+    if (next_) {
+      // If |next_| is non-null, it means |this| wasn't canceled and it implies
+      // |next_| covers the time range starting immediately after this window.
+      DCHECK_EQ(next_->start_time_, start_time_ + kMonitoringWindow);
+      next_->AddJank(0, jank_end_index - local_jank_end_index);
+    }
+  }
+}
+
+// static
+Lock& IOJankMonitoringWindow::current_jank_window_lock() {
+  static NoDestructor<Lock> current_jank_window_lock;
+  return *current_jank_window_lock;
+}
+
+// static
+scoped_refptr<IOJankMonitoringWindow>&
+IOJankMonitoringWindow::current_jank_window_storage() {
+  static NoDestructor<scoped_refptr<IOJankMonitoringWindow>>
+      current_jank_window;
+  return *current_jank_window;
+}
+
+// static
+IOJankReportingCallback& IOJankMonitoringWindow::reporting_callback_storage() {
+  static NoDestructor<IOJankReportingCallback> reporting_callback;
+  return *reporting_callback;
+}
+
+UncheckedScopedBlockingCall::UncheckedScopedBlockingCall(
+    BlockingType blocking_type,
+    BlockingCallType blocking_call_type)
+    : blocking_observer_(GetBlockingObserver()),
+      previous_scoped_blocking_call_(GetLastScopedBlockingCall()),
+#if !defined(STARBOARD)
+      resetter_(&last_scoped_blocking_call, this),
+#endif
+      is_will_block_(blocking_type == BlockingType::WILL_BLOCK ||
+                     (previous_scoped_blocking_call_ &&
+                      previous_scoped_blocking_call_->is_will_block_)) {
+#if defined(STARBOARD)
+  EnsureThreadLocalCallKeyInited();
+  reset_to_ = pthread_getspecific(s_thread_local_call_key);
+  pthread_setspecific(s_thread_local_call_key, this);
+#endif
+
+  // Only monitor non-nested ScopedBlockingCall(MAY_BLOCK) calls on foreground
+  // threads. Cancels() any pending monitored call when a WILL_BLOCK or
+  // ScopedBlockingCallWithBaseSyncPrimitives nests into a
+  // ScopedBlockingCall(MAY_BLOCK).
+  if (!IsBackgroundPriorityWorker() &&
+      (!g_only_monitor_observed_threads || blocking_observer_)) {
+    const bool is_monitored_type =
+        blocking_call_type == BlockingCallType::kRegular && !is_will_block_;
+    if (is_monitored_type && !previous_scoped_blocking_call_) {
+      monitored_call_.emplace();
+    } else if (!is_monitored_type && previous_scoped_blocking_call_ &&
+               previous_scoped_blocking_call_->monitored_call_) {
+      previous_scoped_blocking_call_->monitored_call_->Cancel();
+    }
+  }
+
+  if (blocking_observer_) {
+    if (!previous_scoped_blocking_call_) {
+      blocking_observer_->BlockingStarted(blocking_type);
+    } else if (blocking_type == BlockingType::WILL_BLOCK &&
+               !previous_scoped_blocking_call_->is_will_block_) {
+      blocking_observer_->BlockingTypeUpgraded();
+    }
+  }
+}
+
+UncheckedScopedBlockingCall::~UncheckedScopedBlockingCall() {
+  // TLS affects result of GetLastError() on Windows. ScopedClearLastError
+  // prevents side effect.
+  ScopedClearLastError save_last_error;
+  DCHECK_EQ(this, GetLastScopedBlockingCall());
+  if (blocking_observer_ && !previous_scoped_blocking_call_)
+    blocking_observer_->BlockingEnded();
+
+#if defined(STARBOARD)
+  EnsureThreadLocalCallKeyInited();
+  pthread_setspecific(s_thread_local_call_key, reset_to_);
+#endif
+}
+
+}  // namespace internal
+
+void EnableIOJankMonitoringForProcess(
+    IOJankReportingCallback reporting_callback,
+    OnlyObservedThreadsForTest only_observed_threads) {
+  {
+    AutoLock lock(internal::IOJankMonitoringWindow::current_jank_window_lock());
+
+    DCHECK(internal::IOJankMonitoringWindow::reporting_callback_storage()
+               .is_null());
+    internal::IOJankMonitoringWindow::reporting_callback_storage() =
+        std::move(reporting_callback);
+  }
+
+  if (only_observed_threads) {
+    internal::g_only_monitor_observed_threads = true;
+  } else {
+    // Do not set it to `false` when it already is as that causes data races in
+    // browser tests (which EnableIOJankMonitoringForProcess after ThreadPool is
+    // already running).
+    DCHECK(!internal::g_only_monitor_observed_threads);
+  }
+
+  // Make sure monitoring starts now rather than randomly at the next
+  // ScopedMonitoredCall construction.
+  internal::IOJankMonitoringWindow::MonitorNextJankWindowIfNecessary(
+      TimeTicks::Now());
+}
+
+}  // namespace base
diff --git a/base/threading/scoped_blocking_call_internal.h b/base/threading/scoped_blocking_call_internal.h
new file mode 100644
index 0000000..0d5f418
--- /dev/null
+++ b/base/threading/scoped_blocking_call_internal.h
@@ -0,0 +1,212 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_SCOPED_BLOCKING_CALL_INTERNAL_H_
+#define BASE_THREADING_SCOPED_BLOCKING_CALL_INTERNAL_H_
+
+#include "base/auto_reset.h"
+#include "base/base_export.h"
+#include "base/functional/callback_forward.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
+#include "base/time/time.h"
+#include "base/types/strong_alias.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace base {
+
+// Forward-declare types from scoped_blocking_call.h to break cyclic dependency.
+enum class BlockingType;
+using IOJankReportingCallback = RepeatingCallback<void(int, int)>;
+using OnlyObservedThreadsForTest =
+    StrongAlias<class OnlyObservedThreadsTag, bool>;
+void BASE_EXPORT EnableIOJankMonitoringForProcess(IOJankReportingCallback,
+                                                  OnlyObservedThreadsForTest);
+
+// Implementation details of types in scoped_blocking_call.h and classes for a
+// few key //base types to observe and react to blocking calls.
+namespace internal {
+
+// Interface for an observer to be informed when a thread enters or exits
+// the scope of ScopedBlockingCall objects.
+class BASE_EXPORT BlockingObserver {
+ public:
+  virtual ~BlockingObserver() = default;
+
+  // Invoked when a ScopedBlockingCall is instantiated on the observed thread
+  // where there wasn't an existing ScopedBlockingCall.
+  virtual void BlockingStarted(BlockingType blocking_type) = 0;
+
+  // Invoked when a WILL_BLOCK ScopedBlockingCall is instantiated on the
+  // observed thread where there was a MAY_BLOCK ScopedBlockingCall but not a
+  // WILL_BLOCK ScopedBlockingCall.
+  virtual void BlockingTypeUpgraded() = 0;
+
+  // Invoked when the last ScopedBlockingCall on the observed thread is
+  // destroyed.
+  virtual void BlockingEnded() = 0;
+};
+
+// Registers |new_blocking_observer| on the current thread. It is invalid to
+// call this on a thread where there is an active ScopedBlockingCall.
+BASE_EXPORT void SetBlockingObserverForCurrentThread(
+    BlockingObserver* new_blocking_observer);
+
+BASE_EXPORT void ClearBlockingObserverForCurrentThread();
+
+// An IOJankMonitoringWindow instruments 1-minute of runtime. Any I/O jank > 1
+// second happening during that period will be reported to it. It will then
+// report via the IOJankReportingCallback in |reporting_callback_storage()| if
+// it's non-null. https://bit.ly/chrome-io-jank-metric.
+class BASE_EXPORT [[maybe_unused, nodiscard]] IOJankMonitoringWindow
+    : public RefCountedThreadSafe<IOJankMonitoringWindow> {
+ public:
+  explicit IOJankMonitoringWindow(TimeTicks start_time);
+
+  IOJankMonitoringWindow(const IOJankMonitoringWindow&) = delete;
+  IOJankMonitoringWindow& operator=(const IOJankMonitoringWindow&) = delete;
+
+  // Cancels monitoring and clears this class' static state.
+  static void CancelMonitoringForTesting();
+
+  class [[maybe_unused, nodiscard]] ScopedMonitoredCall {
+   public:
+    // Stores a ref to the current IOJankMonitoringWindow if monitoring is
+    // active, keeping it alive at least until the monitored call completes or
+    // Cancel() is invoked.
+    ScopedMonitoredCall();
+
+    // Reports to |assigned_jank_window_| if it's non-null.
+    ~ScopedMonitoredCall();
+
+    ScopedMonitoredCall(const ScopedMonitoredCall&) = delete;
+    ScopedMonitoredCall& operator=(const ScopedMonitoredCall&) = delete;
+
+    // Cancels monitoring of this call.
+    void Cancel();
+
+   private:
+    TimeTicks call_start_;
+    scoped_refptr<IOJankMonitoringWindow> assigned_jank_window_;
+  };
+
+  static constexpr TimeDelta kIOJankInterval = Seconds(1);
+  static constexpr TimeDelta kMonitoringWindow = Minutes(1);
+  static constexpr TimeDelta kTimeDiscrepancyTimeout = kIOJankInterval * 10;
+  static constexpr int kNumIntervals = kMonitoringWindow / kIOJankInterval;
+
+  // kIOJankIntervals must integrally fill kMonitoringWindow
+  static_assert((kMonitoringWindow % kIOJankInterval).is_zero(), "");
+
+  // Cancelation is simple because it can only affect the current window.
+  static_assert(kTimeDiscrepancyTimeout < kMonitoringWindow, "");
+
+ private:
+  friend class base::RefCountedThreadSafe<IOJankMonitoringWindow>;
+  friend void base::EnableIOJankMonitoringForProcess(
+      IOJankReportingCallback,
+      OnlyObservedThreadsForTest);
+
+  // No-op if reporting_callback_storage() is null (i.e. unless
+  // EnableIOJankMonitoringForProcess() was called).
+  // When reporting_callback_storage() is non-null : Ensures that there's an
+  // active IOJankMonitoringWindow for Now(), connects it via |next_| to the
+  // previous IOJankMonitoringWindow to let ScopedMonitoredCalls that span
+  // multiple windows report to each window they cover. In the event that Now()
+  // is farther ahead than expected (> 10s), the previous window is |canceled_|
+  // as it was likely interrupted by a system sleep and a new
+  // IOJankMonitoringWindow chain is started from Now(). In all cases, returns a
+  // live reference to the current (old or new) IOJankMonitoringWindow as a
+  // helper so callers that need it don't need to re-acquire
+  // current_jank_window_lock() after calling this.
+  // |recent_now| is a recent sampling of TimeTicks::Now(), avoids
+  // double-sampling Now() from most callers.
+  static scoped_refptr<IOJankMonitoringWindow> MonitorNextJankWindowIfNecessary(
+      TimeTicks recent_now);
+
+  // An IOJankMonitoringWindow is destroyed when all refs to it are gone, i.e.:
+  //  1) The window it covers has elapsed and MonitorNextJankWindowIfNecessary()
+  //     has replaced it.
+  //  2) All pending ScopedMonitoredCall's in their range have completed
+  //     (including the ones that transitively have it in their |next_| chain).
+  ~IOJankMonitoringWindow();
+
+  // Called from ~ScopedMonitoredCall().
+  void OnBlockingCallCompleted(TimeTicks call_start, TimeTicks call_end);
+
+  // Helper for OnBlockingCallCompleted(). Records |num_janky_intervals|
+  // starting at |local_jank_start_index|. Having this logic separately helps
+  // sane management of |intervals_lock_| when recursive calls through |next_|
+  // pointers are necessary.
+  void AddJank(int local_jank_start_index, int num_janky_intervals);
+
+  static Lock& current_jank_window_lock();
+  static scoped_refptr<IOJankMonitoringWindow>& current_jank_window_storage()
+      EXCLUSIVE_LOCKS_REQUIRED(current_jank_window_lock());
+
+  // Storage for callback used to report monitoring results.
+  // NullCallback if monitoring was not enabled for this process.
+  static IOJankReportingCallback& reporting_callback_storage()
+      EXCLUSIVE_LOCKS_REQUIRED(current_jank_window_lock());
+
+  Lock intervals_lock_;
+  size_t intervals_jank_count_[kNumIntervals] GUARDED_BY(intervals_lock_) = {};
+
+  const TimeTicks start_time_;
+
+  // Set only once per window, in MonitorNextJankWindowIfNecessary(). Any read
+  // of this value must be ordered after that call in memory and in time.
+  scoped_refptr<IOJankMonitoringWindow> next_;
+
+  // Set to true if ~IOJankMonitoringWindow() shouldn't record metrics.
+  // Modifications of this variable must be synchronized with each other and
+  // happen-before ~IOJankMonitoringWindow().
+  bool canceled_ = false;
+};
+
+// Common implementation class for both ScopedBlockingCall and
+// ScopedBlockingCallWithBaseSyncPrimitives without assertions.
+class BASE_EXPORT [[maybe_unused, nodiscard]] UncheckedScopedBlockingCall {
+ public:
+  enum class BlockingCallType {
+    kRegular,
+    kBaseSyncPrimitives,
+  };
+
+  UncheckedScopedBlockingCall(BlockingType blocking_type,
+                              BlockingCallType blocking_call_type);
+
+  UncheckedScopedBlockingCall(const UncheckedScopedBlockingCall&) = delete;
+  UncheckedScopedBlockingCall& operator=(const UncheckedScopedBlockingCall&) =
+      delete;
+
+  ~UncheckedScopedBlockingCall();
+
+ private:
+  const raw_ptr<BlockingObserver> blocking_observer_;
+
+  // Previous ScopedBlockingCall instantiated on this thread.
+  const raw_ptr<UncheckedScopedBlockingCall> previous_scoped_blocking_call_;
+
+#if defined(STARBOARD)
+  void* reset_to_;
+#else
+  const base::AutoReset<UncheckedScopedBlockingCall*> resetter_;
+#endif
+
+  // Whether the BlockingType of the current thread was WILL_BLOCK after this
+  // ScopedBlockingCall was instantiated.
+  const bool is_will_block_;
+
+  // Non-nullopt for non-nested blocking calls of type MAY_BLOCK on foreground
+  // threads which we monitor for I/O jank.
+  absl::optional<IOJankMonitoringWindow::ScopedMonitoredCall> monitored_call_;
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_THREADING_SCOPED_BLOCKING_CALL_INTERNAL_H_
diff --git a/base/threading/scoped_blocking_call_unittest.cc b/base/threading/scoped_blocking_call_unittest.cc
index 5e030f3..f4f29c6 100644
--- a/base/threading/scoped_blocking_call_unittest.cc
+++ b/base/threading/scoped_blocking_call_unittest.cc
@@ -1,15 +1,32 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/scoped_blocking_call.h"
 
 #include <memory>
+#include <utility>
+#include <vector>
 
-#include "base/macros.h"
+#include "base/barrier_closure.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/task/thread_pool.h"
+#include "base/task/thread_pool/environment_config.h"
+#include "base/task/thread_pool/thread_pool_impl.h"
+#include "base/test/bind.h"
 #include "base/test/gtest_util.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_waitable_event.h"
+#include "base/threading/scoped_blocking_call_internal.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time_override.h"
+#include "build/build_config.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+using testing::ElementsAre;
 
 namespace base {
 
@@ -19,54 +36,56 @@
  public:
   MockBlockingObserver() = default;
 
+  MockBlockingObserver(const MockBlockingObserver&) = delete;
+  MockBlockingObserver& operator=(const MockBlockingObserver&) = delete;
+
   MOCK_METHOD1(BlockingStarted, void(BlockingType));
   MOCK_METHOD0(BlockingTypeUpgraded, void());
   MOCK_METHOD0(BlockingEnded, void());
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockBlockingObserver);
 };
 
 class ScopedBlockingCallTest : public testing::Test {
+ public:
+  ScopedBlockingCallTest(const ScopedBlockingCallTest&) = delete;
+  ScopedBlockingCallTest& operator=(const ScopedBlockingCallTest&) = delete;
+
  protected:
   ScopedBlockingCallTest() {
     internal::SetBlockingObserverForCurrentThread(&observer_);
   }
 
   ~ScopedBlockingCallTest() override {
-    internal::ClearBlockingObserverForTesting();
+    internal::ClearBlockingObserverForCurrentThread();
   }
 
   testing::StrictMock<MockBlockingObserver> observer_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ScopedBlockingCallTest);
 };
 
 }  // namespace
 
 TEST_F(ScopedBlockingCallTest, MayBlock) {
   EXPECT_CALL(observer_, BlockingStarted(BlockingType::MAY_BLOCK));
-  ScopedBlockingCall scoped_blocking_call(BlockingType::MAY_BLOCK);
+  ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
   testing::Mock::VerifyAndClear(&observer_);
   EXPECT_CALL(observer_, BlockingEnded());
 }
 
 TEST_F(ScopedBlockingCallTest, WillBlock) {
   EXPECT_CALL(observer_, BlockingStarted(BlockingType::WILL_BLOCK));
-  ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
+  ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::WILL_BLOCK);
   testing::Mock::VerifyAndClear(&observer_);
   EXPECT_CALL(observer_, BlockingEnded());
 }
 
 TEST_F(ScopedBlockingCallTest, MayBlockWillBlock) {
   EXPECT_CALL(observer_, BlockingStarted(BlockingType::MAY_BLOCK));
-  ScopedBlockingCall scoped_blocking_call_a(BlockingType::MAY_BLOCK);
+  ScopedBlockingCall scoped_blocking_call_a(FROM_HERE, BlockingType::MAY_BLOCK);
   testing::Mock::VerifyAndClear(&observer_);
 
   {
     EXPECT_CALL(observer_, BlockingTypeUpgraded());
-    ScopedBlockingCall scoped_blocking_call_b(BlockingType::WILL_BLOCK);
+    ScopedBlockingCall scoped_blocking_call_b(FROM_HERE,
+                                              BlockingType::WILL_BLOCK);
     testing::Mock::VerifyAndClear(&observer_);
   }
 
@@ -75,47 +94,61 @@
 
 TEST_F(ScopedBlockingCallTest, WillBlockMayBlock) {
   EXPECT_CALL(observer_, BlockingStarted(BlockingType::WILL_BLOCK));
-  ScopedBlockingCall scoped_blocking_call_a(BlockingType::WILL_BLOCK);
+  ScopedBlockingCall scoped_blocking_call_a(FROM_HERE,
+                                            BlockingType::WILL_BLOCK);
   testing::Mock::VerifyAndClear(&observer_);
 
-  { ScopedBlockingCall scoped_blocking_call_b(BlockingType::MAY_BLOCK); }
+  {
+    ScopedBlockingCall scoped_blocking_call_b(FROM_HERE,
+                                              BlockingType::MAY_BLOCK);
+  }
 
   EXPECT_CALL(observer_, BlockingEnded());
 }
 
 TEST_F(ScopedBlockingCallTest, MayBlockMayBlock) {
   EXPECT_CALL(observer_, BlockingStarted(BlockingType::MAY_BLOCK));
-  ScopedBlockingCall scoped_blocking_call_a(BlockingType::MAY_BLOCK);
+  ScopedBlockingCall scoped_blocking_call_a(FROM_HERE, BlockingType::MAY_BLOCK);
   testing::Mock::VerifyAndClear(&observer_);
 
-  { ScopedBlockingCall scoped_blocking_call_b(BlockingType::MAY_BLOCK); }
+  {
+    ScopedBlockingCall scoped_blocking_call_b(FROM_HERE,
+                                              BlockingType::MAY_BLOCK);
+  }
 
   EXPECT_CALL(observer_, BlockingEnded());
 }
 
 TEST_F(ScopedBlockingCallTest, WillBlockWillBlock) {
   EXPECT_CALL(observer_, BlockingStarted(BlockingType::WILL_BLOCK));
-  ScopedBlockingCall scoped_blocking_call_a(BlockingType::WILL_BLOCK);
+  ScopedBlockingCall scoped_blocking_call_a(FROM_HERE,
+                                            BlockingType::WILL_BLOCK);
   testing::Mock::VerifyAndClear(&observer_);
 
-  { ScopedBlockingCall scoped_blocking_call_b(BlockingType::WILL_BLOCK); }
+  {
+    ScopedBlockingCall scoped_blocking_call_b(FROM_HERE,
+                                              BlockingType::WILL_BLOCK);
+  }
 
   EXPECT_CALL(observer_, BlockingEnded());
 }
 
 TEST_F(ScopedBlockingCallTest, MayBlockWillBlockTwice) {
   EXPECT_CALL(observer_, BlockingStarted(BlockingType::MAY_BLOCK));
-  ScopedBlockingCall scoped_blocking_call_a(BlockingType::MAY_BLOCK);
+  ScopedBlockingCall scoped_blocking_call_a(FROM_HERE, BlockingType::MAY_BLOCK);
   testing::Mock::VerifyAndClear(&observer_);
 
   {
     EXPECT_CALL(observer_, BlockingTypeUpgraded());
-    ScopedBlockingCall scoped_blocking_call_b(BlockingType::WILL_BLOCK);
+    ScopedBlockingCall scoped_blocking_call_b(FROM_HERE,
+                                              BlockingType::WILL_BLOCK);
     testing::Mock::VerifyAndClear(&observer_);
 
     {
-      ScopedBlockingCall scoped_blocking_call_c(BlockingType::MAY_BLOCK);
-      ScopedBlockingCall scoped_blocking_call_d(BlockingType::WILL_BLOCK);
+      ScopedBlockingCall scoped_blocking_call_c(FROM_HERE,
+                                                BlockingType::MAY_BLOCK);
+      ScopedBlockingCall scoped_blocking_call_d(FROM_HERE,
+                                                BlockingType::WILL_BLOCK);
     }
   }
 
@@ -124,11 +157,810 @@
 
 TEST(ScopedBlockingCallDestructionOrderTest, InvalidDestructionOrder) {
   auto scoped_blocking_call_a =
-      std::make_unique<ScopedBlockingCall>(BlockingType::WILL_BLOCK);
+      std::make_unique<ScopedBlockingCall>(FROM_HERE, BlockingType::WILL_BLOCK);
   auto scoped_blocking_call_b =
-      std::make_unique<ScopedBlockingCall>(BlockingType::WILL_BLOCK);
+      std::make_unique<ScopedBlockingCall>(FROM_HERE, BlockingType::WILL_BLOCK);
 
   EXPECT_DCHECK_DEATH({ scoped_blocking_call_a.reset(); });
 }
 
+namespace {
+
+class ScopedBlockingCallIOJankMonitoringTest : public testing::Test {
+ public:
+  explicit ScopedBlockingCallIOJankMonitoringTest(
+      test::TaskEnvironment::TimeSource time_source =
+          test::TaskEnvironment::TimeSource::MOCK_TIME)
+      : task_environment_(absl::in_place, time_source) {}
+
+  void SetUp() override {
+    // Note 1: While EnableIOJankMonitoringForProcess() is documented as being
+    // only callable once per process. The call to CancelMonitoringForTesting()
+    // in TearDown() makes it okay to call this in multiple tests in a row
+    // within a single process.
+    // Note 2: No need to check TimeTicks::IsConsistentAcrossProcesses() in
+    // spite of EnableIOJankMonitoringForProcess()'s requirement as
+    // TimeSource::MOCK_TIME avoids usage of the system clock and avoids the
+    // issue.
+    // OnlyObservedThreadsForTest(true) to prevent flakes which are believed to
+    // be caused by ScopedBlockingCall interference in the same process but
+    // outside this test's managed threads: crbug.com/1071166.
+    EnableIOJankMonitoringForProcess(
+        BindLambdaForTesting([&](int janky_intervals_per_minute,
+                                 int total_janks_per_minute) {
+          reports_.emplace_back(
+              janky_intervals_per_minute, total_janks_per_minute);
+        }),
+        OnlyObservedThreadsForTest(true));
+
+    internal::SetBlockingObserverForCurrentThread(&main_thread_observer);
+  }
+
+  void StopMonitoring() {
+    // Reclaim worker threads before CancelMonitoringForTesting() to avoid a
+    // data race (crbug.com/1071166#c16).
+    task_environment_.reset();
+    internal::IOJankMonitoringWindow::CancelMonitoringForTesting();
+    internal::ClearBlockingObserverForCurrentThread();
+  }
+
+  void TearDown() override {
+    if (task_environment_)
+      StopMonitoring();
+  }
+
+ protected:
+  // A member initialized before |task_environment_| that forces worker threads
+  // to be started synchronously. This avoids a tricky race where Linux invokes
+  // SetCurrentThreadType() from early main, before invoking ThreadMain and
+  // yielding control to the thread pool impl. That causes a ScopedBlockingCall
+  // in platform_thread_linux.cc:SetThreadCgroupForThreadType and interferes
+  // with this test. This solution is quite intrusive but is the simplest we can
+  // do for this unique corner case.
+  struct SetSynchronousThreadStart {
+    SetSynchronousThreadStart() {
+      internal::ThreadPoolImpl::SetSynchronousThreadStartForTesting(true);
+    }
+    ~SetSynchronousThreadStart() {
+      internal::ThreadPoolImpl::SetSynchronousThreadStartForTesting(false);
+    }
+  } set_synchronous_thread_start_;
+
+  // The registered lambda above may report to this from any thread. It is
+  // nonetheless safe to read this from the test body as
+  // TaskEnvironment+MOCK_TIME advances the test in lock steps.
+  std::vector<std::pair<int, int>> reports_;
+
+  absl::optional<test::TaskEnvironment> task_environment_;
+
+  // The main thread needs to register a BlockingObserver per
+  // OnlyObservedThreadsForTest(true) but doesn't otherwise care about
+  // observing.
+  testing::NiceMock<MockBlockingObserver> main_thread_observer;
+};
+
+}  // namespace
+
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, Basic) {
+  constexpr auto kJankTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 7;
+  {
+    ScopedBlockingCall blocked_for_7s(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(kJankTiming);
+  }
+
+  // No janks reported before the monitoring window completes.
+  EXPECT_THAT(reports_, ElementsAre());
+
+  // Advance precisely to the end of this window.
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow - kJankTiming);
+
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(7, 7)));
+}
+
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, NestedDoesntMatter) {
+  constexpr auto kJankTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 7;
+  {
+    ScopedBlockingCall blocked_for_7s(FROM_HERE, BlockingType::MAY_BLOCK);
+    ScopedBlockingCall nested(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(kJankTiming);
+  }
+
+  // No janks reported before the monitoring window completes.
+  EXPECT_THAT(reports_, ElementsAre());
+
+  // Jump to the next window.
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(7, 7)));
+}
+
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, ManyInAWindow) {
+  constexpr auto kJankTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 7;
+  constexpr auto kIdleTiming = Seconds(3);
+
+  for (int i = 0; i < 3; ++i) {
+    {
+      ScopedBlockingCall blocked_for_7s(FROM_HERE, BlockingType::MAY_BLOCK);
+      task_environment_->FastForwardBy(kJankTiming);
+    }
+    task_environment_->FastForwardBy(kIdleTiming);
+  }
+
+  // No janks reported before the monitoring window completes.
+  EXPECT_THAT(reports_, ElementsAre());
+
+  // Complete the current window.
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow -
+      (kJankTiming + kIdleTiming) * 3);
+
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(7 * 3, 7 * 3)));
+}
+
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, OverlappingMultipleWindows) {
+  constexpr auto kJankTiming =
+      internal::IOJankMonitoringWindow::kMonitoringWindow * 3 +
+      internal::IOJankMonitoringWindow::kIOJankInterval * 5;
+
+  {
+    ScopedBlockingCall blocked_for_3windows(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(kJankTiming);
+  }
+
+  // Fast-forward by another window with no active blocking calls.
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  // 3 windows janky for their full breadth and 1 window janky for 5 seconds.
+  EXPECT_THAT(reports_,
+              ElementsAre(std::make_pair(60, 60), std::make_pair(60, 60),
+                          std::make_pair(60, 60), std::make_pair(5, 5)));
+}
+
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, InstantUnblockReportsZero) {
+  { ScopedBlockingCall instant_unblock(FROM_HERE, BlockingType::MAY_BLOCK); }
+
+  // No janks reported before the monitoring window completes.
+  EXPECT_THAT(reports_, ElementsAre());
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(0, 0)));
+
+  // No blocking call in next window also reports zero.
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+  EXPECT_THAT(reports_,
+              ElementsAre(std::make_pair(0, 0), std::make_pair(0, 0)));
+}
+
+// Start the jank mid-interval; that interval should be counted but the last
+// incomplete interval won't count.
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, Jank7sMidInterval) {
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kIOJankInterval / 3);
+
+  constexpr auto kJankTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 7;
+  {
+    ScopedBlockingCall blocked_for_7s(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(kJankTiming);
+  }
+
+  // No janks reported before the monitoring window completes.
+  EXPECT_THAT(reports_, ElementsAre());
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(7, 7)));
+}
+
+// Start the jank mid-interval; that interval should be counted but the second
+// one won't count.
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, Jank1sMidInterval) {
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kIOJankInterval / 3);
+
+  constexpr auto kJankTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval;
+  {
+    ScopedBlockingCall blocked_for_1s(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(kJankTiming);
+  }
+
+  // No janks reported before the monitoring window completes.
+  EXPECT_THAT(reports_, ElementsAre());
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(1, 1)));
+}
+
+// Jank that lasts for 1.3 intervals should be rounded down to 1.
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, JankRoundDown) {
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kIOJankInterval * 0.9);
+
+  constexpr auto kJankTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 1.3;
+  {
+    ScopedBlockingCall blocked_for_1s(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(kJankTiming);
+  }
+
+  // No janks reported before the monitoring window completes.
+  EXPECT_THAT(reports_, ElementsAre());
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(1, 1)));
+}
+
+// Jank that lasts for 1.7 intervals should be rounded up to 2.
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, JankRoundUp) {
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kIOJankInterval * 0.5);
+
+  constexpr auto kJankTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 1.7;
+  {
+    ScopedBlockingCall blocked_for_1s(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(kJankTiming);
+  }
+
+  // No janks reported before the monitoring window completes.
+  EXPECT_THAT(reports_, ElementsAre());
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(2, 2)));
+}
+
+// Start mid-interval and perform an operation that overlaps into the next one
+// but is under the jank timing.
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, NoJankMidInterval) {
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kIOJankInterval / 3);
+
+  {
+    ScopedBlockingCall non_janky(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(
+        internal::IOJankMonitoringWindow::kIOJankInterval - Milliseconds(1));
+  }
+
+  // No janks reported before the monitoring window completes.
+  EXPECT_THAT(reports_, ElementsAre());
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(0, 0)));
+}
+
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, MultiThreaded) {
+  constexpr auto kJankTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 7;
+
+  // Every worker needs to block for precise clock management; hence we can't
+  // test beyond the TaskEnvironment's capacity.
+  const int kNumJankyTasks =
+      test::TaskEnvironment::kNumForegroundThreadPoolThreads;
+
+  TestWaitableEvent all_threads_blocked;
+  auto on_thread_blocked = BarrierClosure(
+      kNumJankyTasks,
+      BindOnce(&TestWaitableEvent::Signal, Unretained(&all_threads_blocked)));
+
+  TestWaitableEvent resume_all_threads;
+
+  for (int i = 0; i < kNumJankyTasks; ++i) {
+    base::ThreadPool::PostTask(
+        FROM_HERE, {MayBlock()}, BindLambdaForTesting([&]() {
+          ScopedBlockingCall blocked_until_signal(FROM_HERE,
+                                                  BlockingType::MAY_BLOCK);
+          on_thread_blocked.Run();
+
+          ScopedAllowBaseSyncPrimitivesForTesting allow_wait;
+          resume_all_threads.Wait();
+        }));
+  }
+
+  all_threads_blocked.Wait();
+  task_environment_->AdvanceClock(kJankTiming);
+  resume_all_threads.Signal();
+  task_environment_->RunUntilIdle();
+
+  // No janks reported before the monitoring window completes.
+  EXPECT_THAT(reports_, ElementsAre());
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  // Still only 7 janky internals, but more overall janks.
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(7, 7 * kNumJankyTasks)));
+}
+
+// 3 janks of 3 seconds; overlapping but starting 1 second apart from each
+// other.
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, MultiThreadedOverlapped) {
+  static const int kNumJankyTasks = 3;
+  static_assert(
+      kNumJankyTasks <= test::TaskEnvironment::kNumForegroundThreadPoolThreads,
+      "");
+
+  TestWaitableEvent next_task_is_blocked(WaitableEvent::ResetPolicy::AUTOMATIC);
+
+  TestWaitableEvent resume_thread[kNumJankyTasks] = {};
+  TestWaitableEvent exited_blocking_scope[kNumJankyTasks] = {};
+
+  auto blocking_task = BindLambdaForTesting([&](int task_index) {
+    {
+      // Simulate jank until |resume_thread[task_index]| is signaled.
+      ScopedBlockingCall blocked_until_signal(FROM_HERE,
+                                              BlockingType::MAY_BLOCK);
+      next_task_is_blocked.Signal();
+
+      ScopedAllowBaseSyncPrimitivesForTesting allow_wait;
+      resume_thread[task_index].Wait();
+    }
+    exited_blocking_scope[task_index].Signal();
+  });
+
+  // [0-1]s
+  base::ThreadPool::PostTask(FROM_HERE, {MayBlock()},
+                             BindOnce(blocking_task, 0));
+  next_task_is_blocked.Wait();
+  task_environment_->AdvanceClock(
+      internal::IOJankMonitoringWindow::kIOJankInterval);
+
+  // [1-2]s
+  base::ThreadPool::PostTask(FROM_HERE, {MayBlock()},
+                             BindOnce(blocking_task, 1));
+  next_task_is_blocked.Wait();
+  task_environment_->AdvanceClock(
+      internal::IOJankMonitoringWindow::kIOJankInterval);
+
+  // [2-3]s
+  base::ThreadPool::PostTask(FROM_HERE, {MayBlock()},
+                             BindOnce(blocking_task, 2));
+  next_task_is_blocked.Wait();
+  task_environment_->AdvanceClock(
+      internal::IOJankMonitoringWindow::kIOJankInterval);
+
+  // [3-6]s
+  for (int i = 0; i < kNumJankyTasks; ++i) {
+    resume_thread[i].Signal();
+    exited_blocking_scope[i].Wait();
+    task_environment_->AdvanceClock(
+        internal::IOJankMonitoringWindow::kIOJankInterval);
+  }
+
+  // No janks reported before the monitoring window completes.
+  EXPECT_THAT(reports_, ElementsAre());
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  // 9s of total janks spread across 5 intervals.
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(5, 9)));
+}
+
+// 3 janks of 180 seconds; overlapping but starting 60s apart from each other.
+// First one starting at 10 seconds (can't start later than that or we'll trip
+// the kTimeDiscrepancyTimeout per TaskEnvironment's inability to RunUntilIdle()
+// with pending blocked tasks).
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, MultiThreadedOverlappedWindows) {
+  constexpr int kNumJankyTasks = 3;
+  static_assert(
+      kNumJankyTasks <= test::TaskEnvironment::kNumForegroundThreadPoolThreads,
+      "");
+
+  TestWaitableEvent next_task_is_blocked(WaitableEvent::ResetPolicy::AUTOMATIC);
+
+  TestWaitableEvent resume_thread[kNumJankyTasks] = {};
+  TestWaitableEvent exited_blocking_scope[kNumJankyTasks] = {};
+
+  auto blocking_task = BindLambdaForTesting([&](int task_index) {
+    {
+      // Simulate jank until |resume_thread[task_index]| is signaled.
+      ScopedBlockingCall blocked_until_signal(FROM_HERE,
+                                              BlockingType::MAY_BLOCK);
+      next_task_is_blocked.Signal();
+
+      ScopedAllowBaseSyncPrimitivesForTesting allow_wait;
+      resume_thread[task_index].Wait();
+    }
+    exited_blocking_scope[task_index].Signal();
+  });
+
+  // [0-10s] (minus 1 ms to avoid reaching the timeout; this also tests the
+  // logic that intervals are rounded down to the starting interval (e.g.
+  // interval 9/60 in this case)).
+  task_environment_->AdvanceClock(
+      internal::IOJankMonitoringWindow::kTimeDiscrepancyTimeout -
+      Milliseconds(1));
+
+  // [10-70]s
+  base::ThreadPool::PostTask(FROM_HERE, {MayBlock()},
+                             BindOnce(blocking_task, 0));
+  next_task_is_blocked.Wait();
+  task_environment_->AdvanceClock(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  // [70-130]s
+  base::ThreadPool::PostTask(FROM_HERE, {MayBlock()},
+                             BindOnce(blocking_task, 1));
+  next_task_is_blocked.Wait();
+  task_environment_->AdvanceClock(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  // [130-190]s
+  base::ThreadPool::PostTask(FROM_HERE, {MayBlock()},
+                             BindOnce(blocking_task, 2));
+  next_task_is_blocked.Wait();
+  task_environment_->AdvanceClock(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  // [190-370]s
+  for (int i = 0; i < kNumJankyTasks; ++i) {
+    resume_thread[i].Signal();
+    exited_blocking_scope[i].Wait();
+    task_environment_->AdvanceClock(
+        internal::IOJankMonitoringWindow::kMonitoringWindow);
+  }
+
+  // Already past the last window (relevant events end at 360s); flush the
+  // pending ripe delayed task that will complete the last window.
+  task_environment_->RunUntilIdle();
+
+  // 540s(180s*3) of total janks spread across 300 intervals in 6 windows.
+  // Distributed as such (zoomed out to 6 intervals per window):
+  // [011111]
+  //        [122222]
+  //               [233333]
+  //                      [322222]
+  //                             [21111]
+  //                                   [100000]
+  // Starting at the 9th interval per the 10s-1ms offset start.
+  EXPECT_THAT(reports_,
+              ElementsAre(std::make_pair(51, 51), std::make_pair(60, 111),
+                          std::make_pair(60, 171), std::make_pair(60, 129),
+                          std::make_pair(60, 69), std::make_pair(9, 9)));
+}
+
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, CancellationAcrossSleep) {
+  constexpr auto kJankTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 7;
+  {
+    ScopedBlockingCall blocked_for_7s(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(kJankTiming);
+  }
+
+  // Jump just beyond the kTimeDiscrepancyTimeout for the next window.
+  task_environment_->AdvanceClock(
+      internal::IOJankMonitoringWindow::kMonitoringWindow +
+      internal::IOJankMonitoringWindow::kTimeDiscrepancyTimeout - kJankTiming);
+  task_environment_->RunUntilIdle();
+
+  // Window was canceled and previous jank was not reported.
+  EXPECT_THAT(reports_, ElementsAre());
+
+  // The second window should be independent and need a full kMonitoringWindow
+  // to elapse before reporting.
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow - Seconds(1));
+  EXPECT_THAT(reports_, ElementsAre());
+
+  task_environment_->FastForwardBy(Seconds(1));
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(0, 0)));
+}
+
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, SleepWithLongJank) {
+  {
+    ScopedBlockingCall blocked_through_sleep(FROM_HERE,
+                                             BlockingType::MAY_BLOCK);
+
+    // Fast-forward 2 full windows and almost to the end of the 3rd.
+    task_environment_->FastForwardBy(
+        internal::IOJankMonitoringWindow::kMonitoringWindow * 3 - Seconds(1));
+
+    // Simulate a "sleep" over the timeout threshold.
+    task_environment_->AdvanceClock(
+        Seconds(1) + internal::IOJankMonitoringWindow::kTimeDiscrepancyTimeout);
+  }
+
+  // Two full jank windows are reported when the ScopedBlokcingCall unwinds but
+  // the 3rd is canceled.
+  EXPECT_THAT(reports_,
+              ElementsAre(std::make_pair(60, 60), std::make_pair(60, 60)));
+
+  // The 4th window has a new |start_time| so completing the "remaining delta"
+  // doesn't cause a report from the cancelled 3rd window.
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow - Seconds(1));
+  EXPECT_THAT(reports_,
+              ElementsAre(std::make_pair(60, 60), std::make_pair(60, 60)));
+
+  // Completing the whole 4th window generates a report.
+  task_environment_->FastForwardBy(Seconds(1));
+  EXPECT_THAT(reports_,
+              ElementsAre(std::make_pair(60, 60), std::make_pair(60, 60),
+                          std::make_pair(0, 0)));
+}
+
+// Verifies that blocking calls on background workers aren't monitored.
+// Platforms where !CanUseBackgroundThreadTypeForWorkerThread() will still
+// monitor this jank (as it may interfere with other foreground work).
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, BackgroundBlockingCallsIgnored) {
+  constexpr auto kJankTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 7;
+
+  TestWaitableEvent task_running;
+  TestWaitableEvent resume_task;
+
+  base::ThreadPool::PostTask(
+      FROM_HERE, {TaskPriority::BEST_EFFORT, MayBlock()},
+      BindLambdaForTesting([&]() {
+        ScopedBlockingCall blocked_for_7s(FROM_HERE, BlockingType::MAY_BLOCK);
+        task_running.Signal();
+
+        ScopedAllowBaseSyncPrimitivesForTesting allow_wait;
+        resume_task.Wait();
+      }));
+
+  task_running.Wait();
+  task_environment_->AdvanceClock(kJankTiming);
+  resume_task.Signal();
+
+  // No janks reported before the monitoring window completes.
+  EXPECT_THAT(reports_, ElementsAre());
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  if (internal::CanUseBackgroundThreadTypeForWorkerThread())
+    EXPECT_THAT(reports_, ElementsAre(std::make_pair(0, 0)));
+  else
+    EXPECT_THAT(reports_, ElementsAre(std::make_pair(7, 7)));
+}
+
+TEST_F(ScopedBlockingCallIOJankMonitoringTest,
+       BackgroundAndForegroundCallsMixed) {
+  constexpr auto kJankTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 7;
+
+  TestWaitableEvent tasks_running;
+  auto on_task_running = BarrierClosure(
+      2, BindOnce(&TestWaitableEvent::Signal, Unretained(&tasks_running)));
+  TestWaitableEvent resume_tasks;
+
+  base::ThreadPool::PostTask(
+      FROM_HERE, {TaskPriority::BEST_EFFORT, MayBlock()},
+      BindLambdaForTesting([&]() {
+        ScopedBlockingCall blocked_for_7s(FROM_HERE, BlockingType::MAY_BLOCK);
+        on_task_running.Run();
+
+        ScopedAllowBaseSyncPrimitivesForTesting allow_wait;
+        resume_tasks.Wait();
+      }));
+
+  base::ThreadPool::PostTask(
+      FROM_HERE, {TaskPriority::USER_BLOCKING, MayBlock()},
+      BindLambdaForTesting([&]() {
+        ScopedBlockingCall blocked_for_7s(FROM_HERE, BlockingType::MAY_BLOCK);
+        on_task_running.Run();
+
+        ScopedAllowBaseSyncPrimitivesForTesting allow_wait;
+        resume_tasks.Wait();
+      }));
+
+  tasks_running.Wait();
+  task_environment_->AdvanceClock(kJankTiming);
+  resume_tasks.Signal();
+
+  // No janks reported before the monitoring window completes.
+  EXPECT_THAT(reports_, ElementsAre());
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  if (internal::CanUseBackgroundThreadTypeForWorkerThread())
+    EXPECT_THAT(reports_, ElementsAre(std::make_pair(7, 7)));
+  else
+    EXPECT_THAT(reports_, ElementsAre(std::make_pair(7, 14)));
+}
+
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, WillBlockNotMonitored) {
+  constexpr auto kBlockedTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 7;
+  {
+    ScopedBlockingCall blocked_for_7s(FROM_HERE, BlockingType::WILL_BLOCK);
+    task_environment_->FastForwardBy(kBlockedTiming);
+  }
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(0, 0)));
+}
+
+TEST_F(ScopedBlockingCallIOJankMonitoringTest,
+       NestedWillBlockCancelsMonitoring) {
+  constexpr auto kBlockedTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 7;
+  {
+    ScopedBlockingCall blocked_for_14s(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(kBlockedTiming);
+    ScopedBlockingCall will_block_for_7s(FROM_HERE, BlockingType::WILL_BLOCK);
+    task_environment_->FastForwardBy(kBlockedTiming);
+  }
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(0, 0)));
+}
+
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, NestedMayBlockIgnored) {
+  constexpr auto kBlockedTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 7;
+  {
+    ScopedBlockingCall blocked_for_14s(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(kBlockedTiming);
+    ScopedBlockingCall may_block_for_7s(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(kBlockedTiming);
+  }
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(14, 14)));
+}
+
+TEST_F(ScopedBlockingCallIOJankMonitoringTest, BaseSyncPrimitivesNotMonitored) {
+  constexpr auto kBlockedTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 7;
+  {
+    // Even with MAY_BLOCK; base-sync-primitives aren't considered I/O jank
+    // (base-sync-primitives induced janks/hangs are captured by other tools,
+    // like Slow Reports and HangWatcher).
+    internal::ScopedBlockingCallWithBaseSyncPrimitives
+        base_sync_primitives_for_7s(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(kBlockedTiming);
+  }
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(0, 0)));
+}
+
+TEST_F(ScopedBlockingCallIOJankMonitoringTest,
+       NestedBaseSyncPrimitivesCancels) {
+  constexpr auto kBlockedTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * 7;
+  {
+    ScopedBlockingCall blocked_for_14s(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(kBlockedTiming);
+    internal::ScopedBlockingCallWithBaseSyncPrimitives
+        base_sync_primitives_for_7s(FROM_HERE, BlockingType::MAY_BLOCK);
+    task_environment_->FastForwardBy(kBlockedTiming);
+  }
+
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow);
+
+  EXPECT_THAT(reports_, ElementsAre(std::make_pair(0, 0)));
+}
+
+// Regression test for crbug.com/1209622
+TEST_F(ScopedBlockingCallIOJankMonitoringTest,
+       RacySampleNearMonitoringWindowBoundary) {
+  constexpr auto kDeltaFromBoundary = Milliseconds(1);
+  const int kNumBlockedIntervals = 7;
+  constexpr auto kBlockedTiming =
+      internal::IOJankMonitoringWindow::kIOJankInterval * kNumBlockedIntervals;
+  // kBlockedTiming must be below kTimeDiscrepancyTimeout or racing worker
+  // threads might cancel the next window when ~ScopedBlockingCall lands too far
+  // in the future (since AdvanceClock() doesn't cause delayed tasks to run and
+  // the first window to expire when expected).
+  static_assert(kBlockedTiming <=
+                    internal::IOJankMonitoringWindow::kTimeDiscrepancyTimeout,
+                "");
+
+  // Start this test near an IOJankMonitoringWindow boundary.
+  task_environment_->FastForwardBy(
+      internal::IOJankMonitoringWindow::kMonitoringWindow - kDeltaFromBoundary);
+
+  const int kNumRacingThreads =
+      test::TaskEnvironment::kNumForegroundThreadPoolThreads;
+
+  TestWaitableEvent all_threads_blocked;
+  auto on_thread_blocked = BarrierClosure(
+      kNumRacingThreads,
+      BindOnce(&TestWaitableEvent::Signal, Unretained(&all_threads_blocked)));
+  TestWaitableEvent unblock_worker_threads;
+
+  // First warmup the ThreadPool so there are kNumRacingThreads ready threads
+  // (to maximize the likelihood of a race).
+  for (int i = 0; i < kNumRacingThreads; ++i) {
+    ThreadPool::PostTask(FROM_HERE, {MayBlock()}, BindLambdaForTesting([&]() {
+                           on_thread_blocked.Run();
+                           unblock_worker_threads.Wait();
+                         }));
+  }
+  all_threads_blocked.Wait();
+  unblock_worker_threads.Signal();
+  task_environment_->RunUntilIdle();
+
+  all_threads_blocked.Reset();
+  on_thread_blocked = BarrierClosure(
+      kNumRacingThreads,
+      BindOnce(&TestWaitableEvent::Signal, Unretained(&all_threads_blocked)));
+  unblock_worker_threads.Reset();
+
+  for (int i = 0; i < kNumRacingThreads; ++i) {
+    ThreadPool::PostTask(FROM_HERE, {MayBlock()}, BindLambdaForTesting([&]() {
+                           ScopedBlockingCall blocked_for_14s(
+                               FROM_HERE, BlockingType::MAY_BLOCK);
+                           on_thread_blocked.Run();
+                           unblock_worker_threads.Wait();
+                         }));
+  }
+
+  // Race the worker threads sampling Now() at the start of their blocking call
+  // to reproduce the conditions of crbug.com/1209622. The race occurs if a
+  // worker thread samples Now() before it moves across the boundary but then
+  // the boundary is crossed before it sampled its assigned
+  // IOJankMonitoringWindow, getting a window which doesn't overlap with the
+  // sampled Now() identifying the ScopedBlockingCall's entry point.
+  task_environment_->AdvanceClock(kDeltaFromBoundary);
+  {
+    // We have to use AdvanceClock() above as a FastForwardBy() would stall on
+    // the blocked workers. This means the delayed task causing the first
+    // IOJankMonitoringWindow to expire didn't run. Entering a new
+    // ScopedBlockingCall forces this to happen.
+    ScopedBlockingCall trigger_window(FROM_HERE, BlockingType::MAY_BLOCK);
+  }
+
+  all_threads_blocked.Wait();
+  task_environment_->AdvanceClock(kBlockedTiming);
+  // If a worker thread holds a "begin" timestamp in the past versus its
+  // assigned IOJankMonitoringWindow, completing the janky ScopedBlockingCall
+  // will result in an OOB-index into
+  // |IOJankMonitoringWindow::intervals_jank_count_|.
+  unblock_worker_threads.Signal();
+  task_environment_->RunUntilIdle();
+
+  // Force a report immediately.
+  StopMonitoring();
+
+  // Test covered 2 monitoring windows.
+  ASSERT_EQ(reports_.size(), 2U);
+
+  // Between 0 and kNumRacingThreads sampled Now() and their
+  // IOJankMonitoringWindow before Now() was fast-forwarded by
+  // kDeltaFromBoundary.
+  auto [janky_intervals_count, total_jank_count] = reports_[0];
+  EXPECT_GE(janky_intervals_count, 0);
+  EXPECT_LE(janky_intervals_count, 1);
+  EXPECT_GE(total_jank_count, 0);
+  EXPECT_LE(total_jank_count, kNumRacingThreads);
+  std::tie(janky_intervals_count, total_jank_count) = reports_[1];
+  EXPECT_GE(janky_intervals_count, kNumBlockedIntervals - 1);
+  EXPECT_LE(janky_intervals_count, kNumBlockedIntervals);
+  EXPECT_GE(total_jank_count, (kNumBlockedIntervals - 1) * kNumRacingThreads);
+  EXPECT_LE(total_jank_count, kNumBlockedIntervals * kNumRacingThreads);
+}
+
 }  // namespace base
diff --git a/base/threading/scoped_thread_priority.cc b/base/threading/scoped_thread_priority.cc
new file mode 100644
index 0000000..53922fb
--- /dev/null
+++ b/base/threading/scoped_thread_priority.cc
@@ -0,0 +1,85 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/scoped_thread_priority.h"
+
+#include "base/location.h"
+#include "base/threading/platform_thread.h"
+#include "base/trace_event/base_tracing.h"
+#include "build/build_config.h"
+
+namespace base {
+
+ScopedBoostPriority::ScopedBoostPriority(ThreadType target_thread_type) {
+  DCHECK_LT(target_thread_type, ThreadType::kRealtimeAudio);
+  const ThreadType original_thread_type =
+      PlatformThread::GetCurrentThreadType();
+  const bool should_boost = original_thread_type < target_thread_type &&
+                            PlatformThread::CanChangeThreadType(
+                                original_thread_type, target_thread_type) &&
+                            PlatformThread::CanChangeThreadType(
+                                target_thread_type, original_thread_type);
+  if (should_boost) {
+    original_thread_type_.emplace(original_thread_type);
+    PlatformThread::SetCurrentThreadType(target_thread_type);
+  }
+}
+
+ScopedBoostPriority::~ScopedBoostPriority() {
+  if (original_thread_type_.has_value())
+    PlatformThread::SetCurrentThreadType(original_thread_type_.value());
+}
+
+namespace internal {
+
+ScopedMayLoadLibraryAtBackgroundPriority::
+    ScopedMayLoadLibraryAtBackgroundPriority(const Location& from_here,
+                                             std::atomic_bool* already_loaded)
+#if BUILDFLAG(IS_WIN)
+    : already_loaded_(already_loaded)
+#endif  // BUILDFLAG(IS_WIN)
+{
+  TRACE_EVENT_BEGIN(
+      "base", "ScopedMayLoadLibraryAtBackgroundPriority",
+      [&](perfetto::EventContext ctx) {
+        ctx.event()->set_source_location_iid(
+            base::trace_event::InternedSourceLocation::Get(&ctx, from_here));
+      });
+
+#if BUILDFLAG(IS_WIN)
+  if (already_loaded_ && already_loaded_->load(std::memory_order_relaxed))
+    return;
+
+  const base::ThreadType thread_type = PlatformThread::GetCurrentThreadType();
+  if (thread_type == base::ThreadType::kBackground) {
+    original_thread_type_ = thread_type;
+    PlatformThread::SetCurrentThreadType(base::ThreadType::kDefault);
+
+    TRACE_EVENT_BEGIN0(
+        "base",
+        "ScopedMayLoadLibraryAtBackgroundPriority : Priority Increased");
+  }
+#endif  // BUILDFLAG(IS_WIN)
+}
+
+ScopedMayLoadLibraryAtBackgroundPriority::
+    ~ScopedMayLoadLibraryAtBackgroundPriority() {
+  // Trace events must be closed in reverse order of opening so that they nest
+  // correctly.
+#if BUILDFLAG(IS_WIN)
+  if (original_thread_type_) {
+    TRACE_EVENT_END0(
+        "base",
+        "ScopedMayLoadLibraryAtBackgroundPriority : Priority Increased");
+    PlatformThread::SetCurrentThreadType(original_thread_type_.value());
+  }
+
+  if (already_loaded_)
+    already_loaded_->store(true, std::memory_order_relaxed);
+#endif  // BUILDFLAG(IS_WIN)
+  TRACE_EVENT_END0("base", "ScopedMayLoadLibraryAtBackgroundPriority");
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/threading/scoped_thread_priority.h b/base/threading/scoped_thread_priority.h
new file mode 100644
index 0000000..7b29938
--- /dev/null
+++ b/base/threading/scoped_thread_priority.h
@@ -0,0 +1,109 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_SCOPED_THREAD_PRIORITY_H_
+#define BASE_THREADING_SCOPED_THREAD_PRIORITY_H_
+
+#include <atomic>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/location.h"
+#include "base/memory/raw_ptr.h"
+#include "build/build_config.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace base {
+
+class Location;
+enum class ThreadType : int;
+
+// INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE(name) produces an identifier by
+// appending the current line number to |name|. This is used to avoid name
+// collisions from variables defined inside a macro.
+#define INTERNAL_SCOPED_THREAD_PRIORITY_CONCAT(a, b) a##b
+// CONCAT1 provides extra level of indirection so that __LINE__ macro expands.
+#define INTERNAL_SCOPED_THREAD_PRIORITY_CONCAT1(a, b) \
+  INTERNAL_SCOPED_THREAD_PRIORITY_CONCAT(a, b)
+#define INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE(name) \
+  INTERNAL_SCOPED_THREAD_PRIORITY_CONCAT1(name, __LINE__)
+
+// All code that may load a DLL on a background thread must be surrounded by a
+// scope that starts with this macro.
+//
+// Example:
+//   Foo();
+//   {
+//     SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
+//     LoadMyDll();
+//   }
+//   Bar();
+//
+// The macro raises the thread priority to NORMAL for the scope if no other
+// thread has completed the current scope already (multiple threads can racily
+// begin the initialization and will all be boosted for it). On Windows, loading
+// a DLL on a background thread can lead to a priority inversion on the loader
+// lock and cause huge janks.
+#define SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY()               \
+  static std::atomic_bool INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE( \
+      already_loaded){false};                                          \
+  base::internal::ScopedMayLoadLibraryAtBackgroundPriority             \
+      INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE(                     \
+          scoped_may_load_library_at_background_priority)(             \
+          FROM_HERE,                                                   \
+          &INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE(already_loaded));
+
+// Like SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY, but raises the thread
+// priority every time the scope is entered. Use this around code that may
+// conditionally load a DLL each time it is executed, or which repeatedly loads
+// and unloads DLLs.
+#define SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY_REPEATEDLY() \
+  base::internal::ScopedMayLoadLibraryAtBackgroundPriority          \
+      INTERNAL_SCOPED_THREAD_PRIORITY_APPEND_LINE(                  \
+          scoped_may_load_library_at_background_priority)(FROM_HERE, nullptr);
+
+// Boosts the current thread's priority to match the priority of threads of
+// |target_thread_type| in this scope.
+class BASE_EXPORT ScopedBoostPriority {
+ public:
+  explicit ScopedBoostPriority(ThreadType target_thread_type);
+  ~ScopedBoostPriority();
+
+  ScopedBoostPriority(const ScopedBoostPriority&) = delete;
+  ScopedBoostPriority& operator=(const ScopedBoostPriority&) = delete;
+
+ private:
+  absl::optional<ThreadType> original_thread_type_;
+};
+
+namespace internal {
+
+class BASE_EXPORT ScopedMayLoadLibraryAtBackgroundPriority {
+ public:
+  // Boosts thread priority to NORMAL within its scope if |already_loaded| is
+  // nullptr or set to false.
+  explicit ScopedMayLoadLibraryAtBackgroundPriority(
+      const Location& from_here,
+      std::atomic_bool* already_loaded);
+
+  ScopedMayLoadLibraryAtBackgroundPriority(
+      const ScopedMayLoadLibraryAtBackgroundPriority&) = delete;
+  ScopedMayLoadLibraryAtBackgroundPriority& operator=(
+      const ScopedMayLoadLibraryAtBackgroundPriority&) = delete;
+
+  ~ScopedMayLoadLibraryAtBackgroundPriority();
+
+ private:
+#if BUILDFLAG(IS_WIN)
+  // The original priority when invoking entering the scope().
+  absl::optional<ThreadType> original_thread_type_;
+  const raw_ptr<std::atomic_bool> already_loaded_;
+#endif
+};
+
+}  // namespace internal
+
+}  // namespace base
+
+#endif  // BASE_THREADING_SCOPED_THREAD_PRIORITY_H_
diff --git a/base/threading/scoped_thread_priority_unittest.cc b/base/threading/scoped_thread_priority_unittest.cc
new file mode 100644
index 0000000..b44c1a3
--- /dev/null
+++ b/base/threading/scoped_thread_priority_unittest.cc
@@ -0,0 +1,180 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/scoped_thread_priority.h"
+
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// Tests in this file invoke an API that tracks state in static variable. They
+// can therefore only be invoked once per process.
+#define ASSERT_RUNS_ONCE()                                              \
+  static int num_times_run = 0;                                         \
+  ++num_times_run;                                                      \
+  if (num_times_run > 1)                                                \
+    ADD_FAILURE() << "This test cannot run multiple times in the same " \
+                     "process.";
+
+static ThreadType kAllThreadTypes[] = {
+    ThreadType::kRealtimeAudio, ThreadType::kDisplayCritical,
+    ThreadType::kCompositing, ThreadType::kDefault, ThreadType::kBackground};
+
+static_assert(static_cast<int>(ThreadType::kBackground) == 0,
+              "kBackground isn't lowest");
+static_assert(ThreadType::kRealtimeAudio == ThreadType::kMaxValue,
+              "kRealtimeAudio isn't highest");
+
+class ScopedThreadPriorityTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Ensures the default thread priority is set.
+    ASSERT_EQ(ThreadPriorityForTest::kNormal,
+              PlatformThread::GetCurrentThreadPriorityForTest());
+  }
+};
+
+#if BUILDFLAG(IS_WIN)
+void FunctionThatBoostsPriorityOnFirstInvoke(
+    ThreadPriorityForTest expected_priority) {
+  SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
+  EXPECT_EQ(expected_priority,
+            PlatformThread::GetCurrentThreadPriorityForTest());
+}
+
+void FunctionThatBoostsPriorityOnEveryInvoke() {
+  SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY_REPEATEDLY();
+  EXPECT_EQ(base::ThreadPriorityForTest::kNormal,
+            PlatformThread::GetCurrentThreadPriorityForTest());
+}
+
+#endif  // BUILDFLAG(IS_WIN)
+
+}  // namespace
+
+TEST_F(ScopedThreadPriorityTest, BasicTest) {
+  for (auto from : kAllThreadTypes) {
+    if (!PlatformThread::CanChangeThreadType(ThreadType::kDefault, from))
+      continue;
+    for (auto to : kAllThreadTypes) {
+      // ThreadType::kRealtimeAudio is not a valid |target_thread_type| for
+      // ScopedBoostPriority.
+      if (to == ThreadType::kRealtimeAudio)
+        continue;
+      Thread thread("ScopedThreadPriorityTest");
+      thread.StartWithOptions(Thread::Options(from));
+      thread.WaitUntilThreadStarted();
+      thread.task_runner()->PostTask(
+          FROM_HERE,
+          BindOnce(
+              [](ThreadType from, ThreadType to) {
+                EXPECT_EQ(PlatformThread::GetCurrentThreadType(), from);
+                {
+                  ScopedBoostPriority scoped_boost_priority(to);
+                  bool will_boost_priority =
+                      from < to &&
+                      PlatformThread::CanChangeThreadType(from, to) &&
+                      PlatformThread::CanChangeThreadType(to, from);
+                  EXPECT_EQ(PlatformThread::GetCurrentThreadType(),
+                            will_boost_priority ? to : from);
+                }
+                EXPECT_EQ(PlatformThread::GetCurrentThreadType(), from);
+              },
+              from, to));
+    }
+  }
+}
+
+TEST_F(ScopedThreadPriorityTest, WithoutPriorityBoost) {
+  ASSERT_RUNS_ONCE();
+
+  // Validates that a thread at normal priority keep the same priority.
+  {
+    SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
+    EXPECT_EQ(ThreadPriorityForTest::kNormal,
+              PlatformThread::GetCurrentThreadPriorityForTest());
+  }
+  EXPECT_EQ(ThreadPriorityForTest::kNormal,
+            PlatformThread::GetCurrentThreadPriorityForTest());
+}
+
+#if BUILDFLAG(IS_WIN)
+TEST_F(ScopedThreadPriorityTest, WithPriorityBoost) {
+  ASSERT_RUNS_ONCE();
+
+  // Validates that a thread at background priority is boosted to normal
+  // priority.
+  PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
+  {
+    SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
+    EXPECT_EQ(ThreadPriorityForTest::kNormal,
+              PlatformThread::GetCurrentThreadPriorityForTest());
+  }
+  EXPECT_EQ(ThreadPriorityForTest::kBackground,
+            PlatformThread::GetCurrentThreadPriorityForTest());
+
+  // Put back the default thread priority.
+  PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
+}
+#endif  // BUILDFLAG(IS_WIN)
+
+#if BUILDFLAG(IS_WIN)
+TEST_F(ScopedThreadPriorityTest, NestedScope) {
+  ASSERT_RUNS_ONCE();
+
+  PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
+
+  {
+    SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
+    EXPECT_EQ(ThreadPriorityForTest::kNormal,
+              PlatformThread::GetCurrentThreadPriorityForTest());
+    {
+      SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
+      EXPECT_EQ(ThreadPriorityForTest::kNormal,
+                PlatformThread::GetCurrentThreadPriorityForTest());
+    }
+    EXPECT_EQ(ThreadPriorityForTest::kNormal,
+              PlatformThread::GetCurrentThreadPriorityForTest());
+  }
+
+  EXPECT_EQ(ThreadPriorityForTest::kBackground,
+            PlatformThread::GetCurrentThreadPriorityForTest());
+
+  // Put back the default thread priority.
+  PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
+}
+#endif  // BUILDFLAG(IS_WIN)
+
+#if BUILDFLAG(IS_WIN)
+TEST_F(ScopedThreadPriorityTest, FunctionThatBoostsPriorityOnFirstInvoke) {
+  ASSERT_RUNS_ONCE();
+
+  PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
+
+  FunctionThatBoostsPriorityOnFirstInvoke(base::ThreadPriorityForTest::kNormal);
+  FunctionThatBoostsPriorityOnFirstInvoke(
+      base::ThreadPriorityForTest::kBackground);
+
+  // Put back the default thread priority.
+  PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
+}
+
+TEST_F(ScopedThreadPriorityTest, FunctionThatBoostsPriorityOnEveryInvoke) {
+  PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
+
+  FunctionThatBoostsPriorityOnEveryInvoke();
+  FunctionThatBoostsPriorityOnEveryInvoke();
+
+  // Put back the default thread priority.
+  PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
+}
+
+#endif  // BUILDFLAG(IS_WIN)
+
+}  // namespace base
diff --git a/base/threading/sequence_bound.h b/base/threading/sequence_bound.h
index b4bd183..02380d7 100644
--- a/base/threading/sequence_bound.h
+++ b/base/threading/sequence_bound.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -6,247 +6,700 @@
 #define BASE_THREADING_SEQUENCE_BOUND_H_
 
 #include <new>
+#include <tuple>
 #include <type_traits>
+#include <utility>
 
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
+#include "base/check.h"
 #include "base/location.h"
-#include "base/memory/aligned_memory.h"
-#include "base/memory/ptr_util.h"
-#include "base/sequenced_task_runner.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/run_loop.h"
+#include "base/sequence_checker.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/threading/sequence_bound_internal.h"
 
 namespace base {
 
-// SequenceBound facilitates owning objects that live on a specified sequence,
-// which is potentially different than the owner's sequence.  It encapsulates
-// the work of posting tasks to the specified sequence to construct T, call
-// methods on T, and destroy T.
+// Performing blocking work on a different task runner is a common pattern for
+// improving responsiveness of foreground task runners. `SequenceBound<T>`
+// provides an abstraction for an owner object living on the owner sequence, to
+// construct, call methods on, and destroy an object of type T that lives on a
+// different sequence (the bound sequence).
 //
-// It does not provide explicit access to the underlying object directly, to
-// prevent accidentally using it from the wrong sequence.
+// This makes it natural for code running on different sequences to be
+// partitioned along class boundaries, e.g.:
 //
-// Like std::unique_ptr<T>, a SequenceBound<T> may be moved between owners,
-// and posted across threads.  It may also be up-casted (only), to permit
-// SequenceBound to be used with interfaces.
+// class Tab {
+//  private:
+//   void OnScroll() {
+//     // ...
+//     io_helper_.AsyncCall(&IOHelper::SaveScrollPosition);
+//   }
+//   base::SequenceBound<IOHelper> io_helper_{GetBackgroundTaskRunner()};
+// };
 //
-// Basic usage looks like this:
+// Note: `SequenceBound<T>` intentionally does not expose a raw pointer to the
+// managed `T` to ensure its internal sequence-safety invariants are not
+// violated. As a result, `AsyncCall()` cannot simply use `base::OnceCallback`
 //
-//   // Some class that lives on |main_task_runner|.
-//   class MyClass {
+// SequenceBound also supports replies:
+//
+//   class Database {
 //    public:
-//     explicit MyClass(const char* widget_title) {}
-//     virtual ~MyClass() { ... }
-//     virtual void DoSomething(int arg) { ... }
+//     int Query(int value) {
+//       return value * value;
+//     }
 //   };
 //
-//   // On any thread...
-//   scoped_refptr<SequencedTaskRunner> main_task_runner = ...;
-//   auto widget = SequenceBound<MyClass>(main_task_runner, "My Title");
-//   widget.Post(&MyObject::DoSomething, 1234);
+//   // SequenceBound itself is owned on
+//   // `SequencedTaskRunner::GetCurrentDefault()`. The managed Database
+//   // instance managed by it is constructed and owned on `GetDBTaskRunner()`.
+//   base::SequenceBound<Database> db(GetDBTaskRunner());
 //
-// Note that |widget| is constructed asynchronously on |main_task_runner|,
-// but calling Post() immediately is safe, since the actual call is posted
-// to |main_task_runner| as well.
-//
-// |widget| will be deleted on |main_task_runner| asynchronously when it goes
-// out of scope, or when Reset() is called.
-//
-// Here is a more complicated example that shows injection and upcasting:
-//
-//   // Some unrelated class that uses a |MyClass| to do something.
-//   class SomeConsumer {
-//    public:
-//    // Note that ownership of |widget| is given to us!
-//    explicit SomeConsumer(SequenceBound<MyClass> widget)
-//        : widget_(std::move(widget)) { ... }
-//
-//    ~SomeConsumer() {
-//      // |widget_| will be destroyed on the associated task runner.
-//    }
-//
-//     SequenceBound<MyClass> widget_;
+//   // `Database::Query()` runs on `GetDBTaskRunner()`, but
+//   // `reply_callback` will run on the owner task runner.
+//   auto reply_callback = [] (int result) {
+//     LOG(ERROR) << result;  // Prints 25.
 //   };
+//   db.AsyncCall(&Database::Query).WithArgs(5)
+//     .Then(base::BindOnce(reply_callback));
 //
-//   // Implementation of MyClass.
-//   class MyDerivedClass : public MyClass { ... };
+//   // When `db` goes out of scope, the Database instance will also be
+//   // destroyed via a task posted to `GetDBTaskRunner()`.
 //
-//   auto widget =
-//     SequenceBound<MyDerivedClass>(main_task_runner, ctor args);
-//   auto c = new SomeConsumer(std::move(widget));  // upcasts to MyClass
-
-namespace internal {
-
-// If we can't cast |Base*| into |Derived*|, then it's a virtual base if and
-// only if |Base| is actually a base class of |Derived|.  Otherwise (including
-// unrelated types), it isn't.  We default to Derived* so that the
-// specialization below will apply when the cast to |Derived*| is valid.
-template <typename Base, typename Derived, typename = Derived*>
-struct is_virtual_base_of : public std::is_base_of<Base, Derived> {};
-
-// If we can cast |Base*| into |Derived*|, then it's definitely not a virtual
-// base.  When this happens, we'll match the default third template argument.
-template <typename Base, typename Derived>
-struct is_virtual_base_of<Base,
-                          Derived,
-                          decltype(static_cast<Derived*>(
-                              static_cast<Base*>(nullptr)))> : std::false_type {
-};
-
-};  // namespace internal
-
-template <typename T>
+// Sequence safety:
+//
+// Const-qualified methods may be used concurrently from multiple sequences,
+// e.g. `AsyncCall()` or `is_null()`. Calls that are forwarded to the
+// managed `T` will be posted to the bound sequence and executed serially
+// there.
+//
+// Mutable methods (e.g. `Reset()`, destruction, or move assignment) require
+// external synchronization if used concurrently with any other methods,
+// including const-qualified methods.
+//
+// Advanced usage:
+//
+// Using `SequenceBound<std::unique_ptr<T>>` allows transferring ownership of an
+// already-constructed `T` to `SequenceBound`. This can be helpful for more
+// complex situations, where `T` needs to be constructed on a specific sequence
+// that is different from where `T` will ultimately live.
+//
+// Construction (via the constructor or emplace) takes a `std::unique_ptr<T>`
+// instead of forwarding the arguments to `T`'s constructor:
+//
+//   std::unique_ptr<Database> db_impl = MakeDatabaseOnMainThread();
+//   base::SequenceBound<std::unique_ptr<Database>> db(GetDbTaskRunner(),
+//                                                     std::move(db_impl));
+//
+// All other usage (e.g. `AsyncCall()`, `Reset()`) functions identically to a
+// regular `SequenceBound<T>`:
+//
+//   // No need to dereference the `std::unique_ptr` explicitly:
+//   db.AsyncCall(&Database::Query).WithArgs(5).Then(base::BindOnce(...));
+template <typename T,
+          typename CrossThreadTraits =
+              sequence_bound_internal::CrossThreadTraits>
 class SequenceBound {
+ private:
+  using Storage = sequence_bound_internal::Storage<T, CrossThreadTraits>;
+  // This is usually just `T` except if `T` is a `std::unique_ptr`; in that
+  // case, `UnwrappedT` is the type of the object owned by the
+  // `std::unique_ptr`, e.g. if `T` is `std::unique_ptr<std::string>`, then
+  // UnwrappedT is `std::string`.
+  using UnwrappedT = std::remove_pointer_t<typename Storage::Ptr>;
+
  public:
-  // Allow explicit null.
+  template <typename Signature>
+  using CrossThreadTask =
+      typename CrossThreadTraits::template CrossThreadTask<Signature>;
+
+  // Note: on construction, SequenceBound binds to the current sequence. Any
+  // subsequent SequenceBound calls (including destruction) must run on that
+  // same sequence.
+
+  // Constructs a null SequenceBound with no managed `T`.
   SequenceBound() = default;
 
-  // Construct a new instance of |T| that will be accessed only on
-  // |task_runner|.  One may post calls to it immediately upon return.
-  // This is marked as NO_SANITIZE because cfi doesn't like that we're casting
-  // uninitialized memory to a |T*|.  However, it's safe since (a) the cast is
-  // defined (see http://eel.is/c++draft/basic.life#6 for details), and (b) we
-  // don't use the resulting pointer in any way that requries it to be
-  // constructed, except by posting such a access to |impl_task_runner_| after
-  // posting construction there as well.
+  // Constructs a SequenceBound that manages a new instance of `T` on
+  // `task_runner`. `T` will be constructed on `task_runner`.
+  //
+  // Once this constructor returns, it is safe to immediately use `AsyncCall()`,
+  // et cetera; these calls will be sequenced after the construction of the
+  // managed `T`.
   template <typename... Args>
-  SequenceBound(scoped_refptr<base::SequencedTaskRunner> task_runner,
-                Args&&... args) NO_SANITIZE("cfi-unrelated-cast")
+  explicit SequenceBound(scoped_refptr<SequencedTaskRunner> task_runner,
+                         Args&&... args)
       : impl_task_runner_(std::move(task_runner)) {
-    // Allocate space for but do not construct an instance of |T|.
-    storage_ = AlignedAlloc(sizeof(T), alignof(T));
-    t_ = reinterpret_cast<T*>(storage_);
-
-    // Post construction to the impl thread.
-    impl_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&ConstructOwnerRecord<Args...>, base::Unretained(t_),
-                       std::forward<Args>(args)...));
+    storage_.Construct(*impl_task_runner_, std::forward<Args>(args)...);
   }
 
+  // If non-null, the managed `T` will be destroyed on `impl_task_runner_`.`
   ~SequenceBound() { Reset(); }
 
-  // Move construction from the same type can just take the pointer without
-  // adjusting anything.  This is required in addition to the move conversion
-  // constructor below.
+  // Disallow copy or assignment. SequenceBound has single ownership of the
+  // managed `T`.
+  SequenceBound(const SequenceBound&) = delete;
+  SequenceBound& operator=(const SequenceBound&) = delete;
+
+  // Move construction and assignment.
   SequenceBound(SequenceBound&& other) { MoveRecordFrom(other); }
 
-  // Move construction is supported from any type that's compatible with |T|.
-  // This case handles |From| != |T|, so we must adjust the pointer offset.
-  template <typename From>
-  SequenceBound(SequenceBound<From>&& other) {
-    MoveRecordFrom(other);
-  }
-
   SequenceBound& operator=(SequenceBound&& other) {
-    // Clean up any object we currently own.
     Reset();
     MoveRecordFrom(other);
     return *this;
   }
 
-  template <typename From>
-  SequenceBound<T>& operator=(SequenceBound<From>&& other) {
-    // Clean up any object that we currently own.
+  // Move conversion helpers: allows upcasting from SequenceBound<Derived> to
+  // SequenceBound<Base>.
+  template <typename U>
+  // NOLINTNEXTLINE(google-explicit-constructor): Intentionally implicit.
+  SequenceBound(SequenceBound<U, CrossThreadTraits>&& other) {
+    // TODO(https://crbug.com/1382549): static_assert that U* is convertible to
+    // T*.
+    MoveRecordFrom(other);
+  }
+
+  template <typename U>
+  SequenceBound& operator=(SequenceBound<U, CrossThreadTraits>&& other) {
+    // TODO(https://crbug.com/1382549): static_assert that U* is convertible to
+    // T*.
     Reset();
     MoveRecordFrom(other);
     return *this;
   }
 
-  // Move everything from |other|, doing pointer adjustment as needed.
-  // This method is marked as NO_SANITIZE since (a) it might run before the
-  // posted ctor runs on |impl_task_runner_|, and (b) implicit conversions to
-  // non-virtual base classes are allowed before construction by the standard.
-  // See http://eel.is/c++draft/basic.life#6 for more information.
-  template <typename From>
-  void MoveRecordFrom(From&& other) NO_SANITIZE("cfi-unrelated-cast") {
-    // |other| might be is_null(), but that's okay.
-    impl_task_runner_ = std::move(other.impl_task_runner_);
-
-    // Note that static_cast<> isn't, in general, safe, since |other| might not
-    // be constructed yet.  Implicit conversion is supported, as long as it
-    // doesn't convert to a virtual base.  Of course, it allows only upcasts.
-    t_ = other.t_;
-
-    // The original storage is kept unmodified, so we can free it later.
-    storage_ = other.storage_;
-
-    other.storage_ = nullptr;
-    other.t_ = nullptr;
-  }
-
-  // Post a call to |method| to |impl_task_runner_|.
+  // Constructs a new managed instance of `T` on `task_runner`. If `this` is
+  // already managing another instance of `T`, that pre-existing instance will
+  // first be destroyed by calling `Reset()`.
+  //
+  // Once `emplace()` returns, it is safe to immediately use `AsyncCall()`,
+  // et cetera; these calls will be sequenced after the construction of the
+  // managed `T`.
   template <typename... Args>
-  void Post(const base::Location& from_here,
-            void (T::*method)(Args...),
-            Args&&... args) const {
-    impl_task_runner_->PostTask(
-        from_here, base::BindOnce(
-                       [](void (T::*method)(Args...), T* t, Args... args) {
-                         (t->*method)(std::forward<Args>(args)...);
-                       },
-                       std::move(method), base::Unretained(t_),
-                       std::forward<Args>(args)...));
+  SequenceBound& emplace(scoped_refptr<SequencedTaskRunner> task_runner,
+                         Args&&... args) {
+    Reset();
+    impl_task_runner_ = std::move(task_runner);
+    storage_.Construct(*impl_task_runner_, std::forward<Args>(args)...);
+    return *this;
+  }
+
+  // Invokes `method` of the managed `T` on `impl_task_runner_`. May only be
+  // used when `is_null()` is false.
+  //
+  // Basic usage:
+  //
+  //   helper.AsyncCall(&IOHelper::DoWork);
+  //
+  // If `method` accepts arguments, use `WithArgs()` to bind them:
+  //
+  //   helper.AsyncCall(&IOHelper::DoWorkWithArgs)
+  //       .WithArgs(args);
+  //
+  // Use `Then()` to run a callback on the owner sequence after `method`
+  // completes:
+  //
+  //   helper.AsyncCall(&IOHelper::GetValue)
+  //       .Then(std::move(process_result_callback));
+  //
+  // If a method returns a non-void type, use of `Then()` is required, and the
+  // method's return value will be passed to the `Then()` callback. To ignore
+  // the method's return value instead, wrap `method` in `base::IgnoreResult()`:
+  //
+  //   // Calling `GetPrefs` to force-initialize prefs.
+  //   helper.AsyncCall(base::IgnoreResult(&IOHelper::GetPrefs));
+  //
+  // `WithArgs()` and `Then()` may also be combined:
+  //
+  //   // Ordering is important: `Then()` must come last.
+  //   helper.AsyncCall(&IOHelper::GetValueWithArgs)
+  //       .WithArgs(args)
+  //       .Then(std::move(process_result_callback));
+  //
+  // Note: internally, `AsyncCall()` is implemented using a series of helper
+  // classes that build the callback chain and post it on destruction. Capturing
+  // the return value and passing it elsewhere or triggering lifetime extension
+  // (e.g. by binding the return value to a reference) are both unsupported.
+  template <typename R,
+            typename C,
+            typename... Args,
+            typename = std::enable_if_t<std::is_base_of_v<C, UnwrappedT>>>
+  auto AsyncCall(R (C::*method)(Args...),
+                 const Location& location = Location::Current()) const {
+    return AsyncCallBuilder<R (C::*)(Args...), R, std::tuple<Args...>>(
+        this, &location, method);
+  }
+
+  template <typename R,
+            typename C,
+            typename... Args,
+            typename = std::enable_if_t<std::is_base_of_v<C, UnwrappedT>>>
+  auto AsyncCall(R (C::*method)(Args...) const,
+                 const Location& location = Location::Current()) const {
+    return AsyncCallBuilder<R (C::*)(Args...) const, R, std::tuple<Args...>>(
+        this, &location, method);
+  }
+
+  template <typename R,
+            typename C,
+            typename... Args,
+            typename = std::enable_if_t<std::is_base_of_v<C, UnwrappedT>>>
+  auto AsyncCall(internal::IgnoreResultHelper<R (C::*)(Args...) const> method,
+                 const Location& location = Location::Current()) const {
+    return AsyncCallBuilder<
+        internal::IgnoreResultHelper<R (C::*)(Args...) const>, void,
+        std::tuple<Args...>>(this, &location, method);
+  }
+
+  template <typename R,
+            typename C,
+            typename... Args,
+            typename = std::enable_if_t<std::is_base_of_v<C, UnwrappedT>>>
+  auto AsyncCall(internal::IgnoreResultHelper<R (C::*)(Args...)> method,
+                 const Location& location = Location::Current()) const {
+    return AsyncCallBuilder<internal::IgnoreResultHelper<R (C::*)(Args...)>,
+                            void, std::tuple<Args...>>(this, &location, method);
+  }
+
+  // Posts `task` to `impl_task_runner_`, passing it a reference to the wrapped
+  // object. This allows arbitrary logic to be safely executed on the object's
+  // task runner. The object is guaranteed to remain alive for the duration of
+  // the task.
+  // TODO(crbug.com/1182140): Consider checking whether the task runner can run
+  // tasks in current sequence, and using "plain" binds and task posting (here
+  // and other places that `CrossThreadTraits::PostTask`).
+  using ConstPostTaskCallback = CrossThreadTask<void(const UnwrappedT&)>;
+  void PostTaskWithThisObject(
+      ConstPostTaskCallback callback,
+      const Location& location = Location::Current()) const {
+    DCHECK(!is_null());
+    // Even though the lifetime of the object pointed to by `get()` may not have
+    // begun yet, the storage has been allocated. Per [basic.life/6] and
+    // [basic.life/7], "Indirection through such a pointer is permitted but the
+    // resulting lvalue may only be used in limited ways, as described below."
+    CrossThreadTraits::PostTask(
+        *impl_task_runner_, location,
+        CrossThreadTraits::BindOnce(std::move(callback),
+                                    std::cref(*storage_.get())));
+  }
+
+  // Same as above, but for non-const operations. The callback takes a pointer
+  // to the wrapped object rather than a const ref.
+  using PostTaskCallback = CrossThreadTask<void(UnwrappedT*)>;
+  void PostTaskWithThisObject(
+      PostTaskCallback callback,
+      const Location& location = Location::Current()) const {
+    DCHECK(!is_null());
+    CrossThreadTraits::PostTask(
+        *impl_task_runner_, location,
+        CrossThreadTraits::BindOnce(
+            std::move(callback),
+            CrossThreadTraits::Unretained(storage_.get())));
+  }
+
+  void FlushPostedTasksForTesting() const {
+    DCHECK(!is_null());
+    RunLoop run_loop;
+    CrossThreadTraits::PostTask(*impl_task_runner_, FROM_HERE,
+                                run_loop.QuitClosure());
+    run_loop.Run();
   }
 
   // TODO(liberato): Add PostOrCall(), to support cases where synchronous calls
   // are okay if it's the same task runner.
 
-  // TODO(liberato): Add PostAndReply()
-
-  // TODO(liberato): Allow creation of callbacks that bind to a weak pointer,
-  // and thread-hop to |impl_task_runner_| if needed.
-
-  // Post destruction of any object we own, and return to the null state.
+  // Resets `this` to null. If `this` is not currently null, posts destruction
+  // of the managed `T` to `impl_task_runner_`.
   void Reset() {
     if (is_null())
       return;
 
-    // Destruct the object on the impl thread.
-    impl_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&DeleteOwnerRecord, base::Unretained(t_),
-                                  base::Unretained(storage_)));
-
+    storage_.Destruct(*impl_task_runner_);
     impl_task_runner_ = nullptr;
-    t_ = nullptr;
-    storage_ = nullptr;
   }
 
-  // Return whether we own anything.  Note that this does not guarantee that any
-  // previously owned object has been destroyed.  In particular, it will return
-  // true immediately after a call to Reset(), though the underlying object
-  // might still be pending destruction on the impl thread.
-  bool is_null() const { return !t_; }
+  // Resets `this` to null. If `this` is not currently null, posts destruction
+  // of the managed `T` to `impl_task_runner_`. Blocks until the destructor has
+  // run.
+  void SynchronouslyResetForTest() {
+    if (is_null())
+      return;
+
+    scoped_refptr<SequencedTaskRunner> task_runner = impl_task_runner_;
+    Reset();
+    // `Reset()` posts a task to destroy the managed `T`; synchronously wait for
+    // that posted task to complete.
+    RunLoop run_loop;
+    CrossThreadTraits::PostTask(*task_runner, FROM_HERE,
+                                run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  // Return true if `this` is logically null; otherwise, returns false.
+  //
+  // A SequenceBound is logically null if there is no managed `T`; it is only
+  // valid to call `AsyncCall()` on a non-null SequenceBound.
+  //
+  // Note that the concept of 'logically null' here does not exactly match the
+  // lifetime of `T`, which lives on `impl_task_runner_`. In particular, when
+  // SequenceBound is first constructed, `is_null()` may return false, even
+  // though the lifetime of `T` may not have begun yet on `impl_task_runner_`.
+  // Similarly, after `SequenceBound::Reset()`, `is_null()` may return true,
+  // even though the lifetime of `T` may not have ended yet on
+  // `impl_task_runner_`.
+  bool is_null() const { return !storage_.get(); }
+
+  // True if `this` is not logically null. See `is_null()`.
+  explicit operator bool() const { return !is_null(); }
 
  private:
-  // Pointer to the object,  Pointer may be modified on the owning thread.
-  T* t_ = nullptr;
-
-  // Original allocated storage for the object.
-  void* storage_ = nullptr;
-
-  // The task runner on which all access to |t_| should happen.
-  scoped_refptr<base::SequencedTaskRunner> impl_task_runner_;
-
   // For move conversion.
-  template <typename U>
+  template <typename U, typename V>
   friend class SequenceBound;
 
-  // Run on impl thread to construct |t|'s storage.
-  template <typename... Args>
-  static void ConstructOwnerRecord(T* t, Args&&... args) {
-    new (t) T(std::forward<Args>(args)...);
+  template <template <typename> class CallbackType>
+  using EnableIfIsCrossThreadTask =
+      typename CrossThreadTraits::template EnableIfIsCrossThreadTask<
+          CallbackType>;
+
+  // Support helpers for `AsyncCall()` implementation.
+  //
+  // Several implementation notes:
+  // 1. Tasks are posted via destroying the builder or an explicit call to
+  //    `Then()`.
+  //
+  // 2. A builder may be consumed by:
+  //
+  //    - calling `Then()`, which immediately posts the task chain
+  //    - calling `WithArgs()`, which returns a new builder with the captured
+  //      arguments
+  //
+  //    Builders that are consumed have the internal `sequence_bound_` field
+  //    nulled out; the hope is the compiler can see this and use it to
+  //    eliminate dead branches (e.g. correctness checks that aren't needed
+  //    since the code can be statically proved correct).
+  //
+  // 3. Builder methods are rvalue-qualified to try to enforce that the builder
+  //    is only used as a temporary. Note that this only helps so much; nothing
+  //    prevents a determined caller from using `std::move()` to force calls to
+  //    a non-temporary instance.
+  //
+  // TODO(dcheng): It might also be possible to use Gmock-style matcher
+  // composition, e.g. something like:
+  //
+  //   sb.AsyncCall(&Helper::DoWork, WithArgs(args),
+  //                Then(std::move(process_result));
+  //
+  // In theory, this might allow the elimination of magic destructors and
+  // better static checking by the compiler.
+  template <typename MethodRef>
+  class AsyncCallBuilderBase {
+   protected:
+    AsyncCallBuilderBase(const SequenceBound* sequence_bound,
+                         const Location* location,
+                         MethodRef method)
+        : sequence_bound_(sequence_bound),
+          location_(location),
+          method_(method) {
+      // Common entry point for `AsyncCall()`, so check preconditions here.
+      DCHECK(sequence_bound_);
+      DCHECK(sequence_bound_->storage_.get());
+    }
+
+    AsyncCallBuilderBase(AsyncCallBuilderBase&&) = default;
+    AsyncCallBuilderBase& operator=(AsyncCallBuilderBase&&) = default;
+
+    // `sequence_bound_` is consumed and set to `nullptr` when `Then()` is
+    // invoked. This is used as a flag for two potential states
+    //
+    // - if a method returns void, invoking `Then()` is optional. The destructor
+    //   will check if `sequence_bound_` is null; if it is, `Then()` was
+    //   already invoked and the task chain has already been posted, so the
+    //   destructor does not need to do anything. Otherwise, the destructor
+    //   needs to post the task to make the async call. In theory, the compiler
+    //   should be able to eliminate this branch based on the presence or
+    //   absence of a call to `Then()`.
+    //
+    // - if a method returns a non-void type, `Then()` *must* be invoked. The
+    //   destructor will `CHECK()` if `sequence_bound_` is non-null, since that
+    //   indicates `Then()` was not invoked. Similarly, note this branch should
+    //   be eliminated by the optimizer if the code is free of bugs. :)
+    raw_ptr<const SequenceBound<T, CrossThreadTraits>, DanglingUntriaged>
+        sequence_bound_;
+    // Subtle: this typically points at a Location *temporary*. This is used to
+    // try to detect errors resulting from lifetime extension of the async call
+    // factory temporaries, since the factory destructors can perform work. If
+    // the lifetime of the factory is incorrectly extended, dereferencing
+    // `location_` will trigger a stack-use-after-scope when running with ASan.
+    const raw_ptr<const Location> location_;
+    MethodRef method_;
+  };
+
+  template <typename MethodRef, typename ReturnType, typename ArgsTuple>
+  class AsyncCallBuilderImpl;
+
+  // Selected method has no arguments and returns void.
+  template <typename MethodRef>
+  class AsyncCallBuilderImpl<MethodRef, void, std::tuple<>>
+      : public AsyncCallBuilderBase<MethodRef> {
+   public:
+    // Note: despite being here, this is actually still protected, since it is
+    // protected on the base class.
+    using AsyncCallBuilderBase<MethodRef>::AsyncCallBuilderBase;
+
+    ~AsyncCallBuilderImpl() {
+      if (this->sequence_bound_) {
+        CrossThreadTraits::PostTask(
+            *this->sequence_bound_->impl_task_runner_, *this->location_,
+            CrossThreadTraits::BindOnce(
+                this->method_, CrossThreadTraits::Unretained(
+                                   this->sequence_bound_->storage_.get())));
+      }
+    }
+
+    void Then(CrossThreadTask<void()> then_callback) && {
+      this->sequence_bound_->PostTaskAndThenHelper(
+          *this->location_,
+          CrossThreadTraits::BindOnce(
+              this->method_, CrossThreadTraits::Unretained(
+                                 this->sequence_bound_->storage_.get())),
+          std::move(then_callback));
+      this->sequence_bound_ = nullptr;
+    }
+
+   private:
+    friend SequenceBound;
+
+    AsyncCallBuilderImpl(AsyncCallBuilderImpl&&) = default;
+    AsyncCallBuilderImpl& operator=(AsyncCallBuilderImpl&&) = default;
+  };
+
+  // Selected method has no arguments and returns non-void.
+  template <typename MethodRef, typename ReturnType>
+  class AsyncCallBuilderImpl<MethodRef, ReturnType, std::tuple<>>
+      : public AsyncCallBuilderBase<MethodRef> {
+   public:
+    // Note: despite being here, this is actually still protected, since it is
+    // protected on the base class.
+    using AsyncCallBuilderBase<MethodRef>::AsyncCallBuilderBase;
+
+    ~AsyncCallBuilderImpl() {
+      // Must use Then() since the method's return type is not void.
+      // Should be optimized out if the code is bug-free.
+      CHECK(!this->sequence_bound_)
+          << "Then() not invoked for a method that returns a non-void type; "
+          << "make sure to invoke Then() or use base::IgnoreResult()";
+    }
+
+    template <template <typename> class CallbackType,
+              typename ThenArg,
+              typename = EnableIfIsCrossThreadTask<CallbackType>>
+    void Then(CallbackType<void(ThenArg)> then_callback) && {
+      this->sequence_bound_->PostTaskAndThenHelper(
+          *this->location_,
+          CrossThreadTraits::BindOnce(
+              this->method_, CrossThreadTraits::Unretained(
+                                 this->sequence_bound_->storage_.get())),
+          std::move(then_callback));
+      this->sequence_bound_ = nullptr;
+    }
+
+   private:
+    friend SequenceBound;
+
+    AsyncCallBuilderImpl(AsyncCallBuilderImpl&&) = default;
+    AsyncCallBuilderImpl& operator=(AsyncCallBuilderImpl&&) = default;
+  };
+
+  // Selected method has arguments. Return type can be void or non-void.
+  template <typename MethodRef, typename ReturnType, typename... Args>
+  class AsyncCallBuilderImpl<MethodRef, ReturnType, std::tuple<Args...>>
+      : public AsyncCallBuilderBase<MethodRef> {
+   public:
+    // Note: despite being here, this is actually still protected, since it is
+    // protected on the base class.
+    using AsyncCallBuilderBase<MethodRef>::AsyncCallBuilderBase;
+
+    ~AsyncCallBuilderImpl() {
+      // Must use WithArgs() since the method takes arguments.
+      // Should be optimized out if the code is bug-free.
+      CHECK(!this->sequence_bound_);
+    }
+
+    template <typename... BoundArgs>
+    auto WithArgs(BoundArgs&&... bound_args) {
+      const SequenceBound* const sequence_bound =
+          std::exchange(this->sequence_bound_, nullptr);
+      return AsyncCallWithBoundArgsBuilder<ReturnType>(
+          sequence_bound, this->location_,
+          CrossThreadTraits::BindOnce(
+              this->method_,
+              CrossThreadTraits::Unretained(sequence_bound->storage_.get()),
+              std::forward<BoundArgs>(bound_args)...));
+    }
+
+   private:
+    friend SequenceBound;
+
+    AsyncCallBuilderImpl(AsyncCallBuilderImpl&&) = default;
+    AsyncCallBuilderImpl& operator=(AsyncCallBuilderImpl&&) = default;
+  };
+
+  // `MethodRef` is either a member function pointer type or a member function
+  //     pointer type wrapped with `internal::IgnoreResultHelper`.
+  // `R` is the return type of `MethodRef`. This is always `void` if
+  //     `MethodRef` is an `internal::IgnoreResultHelper` wrapper.
+  // `ArgsTuple` is a `std::tuple` with template type arguments corresponding to
+  //     the types of the method's parameters.
+  template <typename MethodRef, typename R, typename ArgsTuple>
+  using AsyncCallBuilder = AsyncCallBuilderImpl<MethodRef, R, ArgsTuple>;
+
+  // Support factories when arguments are bound using `WithArgs()`. These
+  // factories don't need to handle raw method pointers, since everything has
+  // already been packaged into a base::OnceCallback.
+  template <typename ReturnType>
+  class AsyncCallWithBoundArgsBuilderBase {
+   protected:
+    AsyncCallWithBoundArgsBuilderBase(const SequenceBound* sequence_bound,
+                                      const Location* location,
+                                      CrossThreadTask<ReturnType()> callback)
+        : sequence_bound_(sequence_bound),
+          location_(location),
+          callback_(std::move(callback)) {
+      DCHECK(sequence_bound_);
+      DCHECK(sequence_bound_->storage_.get());
+    }
+
+    // Subtle: the internal helpers rely on move elision. Preventing move
+    // elision (e.g. using `std::move()` when returning the temporary) will
+    // trigger a `CHECK()` since `sequence_bound_` is not reset to nullptr on
+    // move.
+    AsyncCallWithBoundArgsBuilderBase(
+        AsyncCallWithBoundArgsBuilderBase&&) noexcept = default;
+    AsyncCallWithBoundArgsBuilderBase& operator=(
+        AsyncCallWithBoundArgsBuilderBase&&) noexcept = default;
+
+    raw_ptr<const SequenceBound<T, CrossThreadTraits>> sequence_bound_;
+    const raw_ptr<const Location> location_;
+    CrossThreadTask<ReturnType()> callback_;
+  };
+
+  // Note: this doesn't handle a void return type, which has an explicit
+  // specialization below.
+  template <typename ReturnType>
+  class AsyncCallWithBoundArgsBuilderDefault
+      : public AsyncCallWithBoundArgsBuilderBase<ReturnType> {
+   public:
+    ~AsyncCallWithBoundArgsBuilderDefault() {
+      // Must use Then() since the method's return type is not void.
+      // Should be optimized out if the code is bug-free.
+      CHECK(!this->sequence_bound_);
+    }
+
+    template <template <typename> class CallbackType,
+              typename ThenArg,
+              typename = EnableIfIsCrossThreadTask<CallbackType>>
+    void Then(CallbackType<void(ThenArg)> then_callback) && {
+      this->sequence_bound_->PostTaskAndThenHelper(*this->location_,
+                                                   std::move(this->callback_),
+                                                   std::move(then_callback));
+      this->sequence_bound_ = nullptr;
+    }
+
+   protected:
+    using AsyncCallWithBoundArgsBuilderBase<
+        ReturnType>::AsyncCallWithBoundArgsBuilderBase;
+
+   private:
+    friend SequenceBound;
+
+    AsyncCallWithBoundArgsBuilderDefault(
+        AsyncCallWithBoundArgsBuilderDefault&&) = default;
+    AsyncCallWithBoundArgsBuilderDefault& operator=(
+        AsyncCallWithBoundArgsBuilderDefault&&) = default;
+  };
+
+  class AsyncCallWithBoundArgsBuilderVoid
+      : public AsyncCallWithBoundArgsBuilderBase<void> {
+   public:
+    // Note: despite being here, this is actually still protected, since it is
+    // protected on the base class.
+    using AsyncCallWithBoundArgsBuilderBase<
+        void>::AsyncCallWithBoundArgsBuilderBase;
+
+    ~AsyncCallWithBoundArgsBuilderVoid() {
+      if (this->sequence_bound_) {
+        CrossThreadTraits::PostTask(*this->sequence_bound_->impl_task_runner_,
+                                    *this->location_,
+                                    std::move(this->callback_));
+      }
+    }
+
+    void Then(CrossThreadTask<void()> then_callback) && {
+      this->sequence_bound_->PostTaskAndThenHelper(*this->location_,
+                                                   std::move(this->callback_),
+                                                   std::move(then_callback));
+      this->sequence_bound_ = nullptr;
+    }
+
+   private:
+    friend SequenceBound;
+
+    AsyncCallWithBoundArgsBuilderVoid(AsyncCallWithBoundArgsBuilderVoid&&) =
+        default;
+    AsyncCallWithBoundArgsBuilderVoid& operator=(
+        AsyncCallWithBoundArgsBuilderVoid&&) = default;
+  };
+
+  template <typename ReturnType>
+  using AsyncCallWithBoundArgsBuilder = typename std::conditional<
+      std::is_void<ReturnType>::value,
+      AsyncCallWithBoundArgsBuilderVoid,
+      AsyncCallWithBoundArgsBuilderDefault<ReturnType>>::type;
+
+  void PostTaskAndThenHelper(const Location& location,
+                             CrossThreadTask<void()> callback,
+                             CrossThreadTask<void()> then_callback) const {
+    CrossThreadTraits::PostTaskAndReply(*impl_task_runner_, location,
+                                        std::move(callback),
+                                        std::move(then_callback));
   }
 
-  // Destruct the object associated with |t|, and delete |storage|.
-  static void DeleteOwnerRecord(T* t, void* storage) {
-    t->~T();
-    AlignedFree(storage);
+  template <typename ReturnType,
+            template <typename>
+            class CallbackType,
+            typename ThenArg,
+            typename = EnableIfIsCrossThreadTask<CallbackType>>
+  void PostTaskAndThenHelper(const Location& location,
+                             CrossThreadTask<ReturnType()> callback,
+                             CallbackType<void(ThenArg)> then_callback) const {
+    CrossThreadTask<void(ThenArg)>&& once_then_callback =
+        std::move(then_callback);
+    CrossThreadTraits::PostTaskAndReplyWithResult(
+        *impl_task_runner_, location, std::move(callback),
+        std::move(once_then_callback));
   }
 
-  // To preserve ownership semantics, we disallow copy construction / copy
-  // assignment.  Move construction / assignment is fine.
-  DISALLOW_COPY_AND_ASSIGN(SequenceBound);
+  // Helper to support move construction and move assignment.
+  //
+  // TODO(https://crbug.com/1382549): Constrain this so converting between
+  // std::unique_ptr<T> and T are explicitly forbidden (rather than simply
+  // failing to build in spectacular ways).
+  template <typename From>
+  void MoveRecordFrom(From&& other) {
+    impl_task_runner_ = std::move(other.impl_task_runner_);
+
+    storage_.TakeFrom(std::move(other.storage_));
+  }
+
+  Storage storage_;
+
+  // Task runner which manages `storage_.get()`. `storage_.get()`'s pointee is
+  // constructed, destroyed, and otherwise used only on this task runner.
+  scoped_refptr<SequencedTaskRunner> impl_task_runner_;
 };
 
 }  // namespace base
diff --git a/base/threading/sequence_bound_internal.h b/base/threading/sequence_bound_internal.h
new file mode 100644
index 0000000..0e4b37c
--- /dev/null
+++ b/base/threading/sequence_bound_internal.h
@@ -0,0 +1,201 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_SEQUENCE_BOUND_INTERNAL_H_
+#define BASE_THREADING_SEQUENCE_BOUND_INTERNAL_H_
+
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "base/compiler_specific.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/functional/callback_helpers.h"
+#include "base/location.h"
+#include "base/memory/aligned_memory.h"
+#include "base/memory/raw_ptr.h"
+#include "base/task/sequenced_task_runner.h"
+
+namespace base::sequence_bound_internal {
+
+struct CrossThreadTraits {
+  template <typename Signature>
+  using CrossThreadTask = OnceCallback<Signature>;
+
+  template <typename Functor, typename... Args>
+  static inline auto BindOnce(Functor&& functor, Args&&... args) {
+    return ::base::BindOnce(std::forward<Functor>(functor),
+                            std::forward<Args>(args)...);
+  }
+
+  template <typename T>
+  static inline auto Unretained(T ptr) {
+    return ::base::Unretained(ptr);
+  }
+
+  static inline bool PostTask(SequencedTaskRunner& task_runner,
+                              const Location& location,
+                              OnceClosure&& task) {
+    return task_runner.PostTask(location, std::move(task));
+  }
+
+  static inline bool PostTaskAndReply(SequencedTaskRunner& task_runner,
+                                      const Location& location,
+                                      OnceClosure&& task,
+                                      OnceClosure&& reply) {
+    return task_runner.PostTaskAndReply(location, std::move(task),
+                                        std::move(reply));
+  }
+
+  template <typename TaskReturnType, typename ReplyArgType>
+  static inline bool PostTaskAndReplyWithResult(
+      SequencedTaskRunner& task_runner,
+      const Location& location,
+      OnceCallback<TaskReturnType()>&& task,
+      OnceCallback<void(ReplyArgType)>&& reply) {
+    return task_runner.PostTaskAndReplyWithResult(location, std::move(task),
+                                                  std::move(reply));
+  }
+
+  // Accept RepeatingCallback here since it's convertible to a OnceCallback.
+  template <template <typename> class CallbackType>
+  using EnableIfIsCrossThreadTask = EnableIfIsBaseCallback<CallbackType>;
+};
+
+template <typename T, typename CrossThreadTraits>
+class Storage {
+ public:
+  using Ptr = T*;
+
+  Ptr get() const { return ptr_; }
+
+  // Marked NO_SANITIZE because cfi doesn't like casting uninitialized memory to
+  // `T*`. However, this is safe here because:
+  //
+  // 1. The cast is well-defined (see https://eel.is/c++draft/basic.life#6) and
+  // 2. The resulting pointer is only ever dereferenced on `task_runner`.
+  //    By the time SequenceBound's constructor returns, the task to construct
+  //    `T` will already be posted; thus, subsequent dereference of `ptr_` on
+  //    `task_runner` are safe.
+  template <typename... Args>
+  NO_SANITIZE("cfi-unrelated-cast")
+  void Construct(SequencedTaskRunner& task_runner, Args&&... args) {
+    // TODO(https://crbug.com/1382549): Use universal forwarding and assert that
+    // T is constructible from args for better error messages.
+    DCHECK(!alloc_);
+    DCHECK(!ptr_);
+
+    // Allocate space for but do not construct an instance of `T`.
+    // AlignedAlloc() requires alignment be a multiple of sizeof(void*).
+    alloc_ = AlignedAlloc(
+        sizeof(T), sizeof(void*) > alignof(T) ? sizeof(void*) : alignof(T));
+    ptr_ = reinterpret_cast<Ptr>(alloc_.get());
+
+    // Ensure that `ptr_` will be initialized.
+    CrossThreadTraits::PostTask(
+        task_runner, FROM_HERE,
+        CrossThreadTraits::BindOnce(&InternalConstruct<Args...>,
+                                    CrossThreadTraits::Unretained(ptr_),
+                                    std::forward<Args>(args)...));
+  }
+
+  // Marked NO_SANITIZE since:
+  // 1. SequenceBound can be moved before `ptr_` is constructed on its managing
+  //    `SequencedTaskRunner` but
+  // 2. Implicit conversions to non-virtual base classes are allowed before the
+  //    lifetime of the object that `ptr_` points at has begun (see
+  //    https://eel.is/c++draft/basic.life#6).
+  template <typename U>
+  NO_SANITIZE("cfi-unrelated-cast")
+  void TakeFrom(Storage<U, CrossThreadTraits>&& other) {
+    // Subtle: this must not use static_cast<>, since the lifetime of the
+    // managed `T` may not have begun yet. However, the standard explicitly
+    // still allows implicit conversion to a non-virtual base class.
+    ptr_ = std::exchange(other.ptr_, nullptr);
+    alloc_ = std::exchange(other.alloc_, nullptr);
+  }
+
+  void Destruct(SequencedTaskRunner& task_runner) {
+    CrossThreadTraits::PostTask(
+        task_runner, FROM_HERE,
+        CrossThreadTraits::BindOnce(
+            &InternalDestruct, CrossThreadTraits::Unretained(ptr_),
+            CrossThreadTraits::Unretained(alloc_.get())));
+    ptr_ = nullptr;
+    alloc_ = nullptr;
+  }
+
+ private:
+  // Needed to allow conversions from compatible `U`s.
+  template <typename U, typename V>
+  friend class Storage;
+
+  // Helpers for constructing and destroying `T` on its managing
+  // `SequencedTaskRunner`.
+  template <typename... Args>
+  static void InternalConstruct(T* ptr, std::decay_t<Args>&&... args) {
+    new (ptr) T(std::move(args)...);
+  }
+
+  static void InternalDestruct(T* ptr, void* alloc) {
+    ptr->~T();
+    AlignedFree(alloc);
+  }
+
+  // Pointer to the managed `T`.
+  Ptr ptr_ = nullptr;
+
+  // Storage originally allocated by `AlignedAlloc()`. Maintained separately
+  // from  `ptr_` since the original, unadjusted pointer needs to be passed to
+  // `AlignedFree()`.
+  raw_ptr<void, DanglingUntriaged> alloc_ = nullptr;
+};
+
+template <typename T, typename CrossThreadTraits>
+struct Storage<std::unique_ptr<T>, CrossThreadTraits> {
+ public:
+  using Ptr = T*;
+
+  Ptr get() const { return ptr_; }
+
+  template <typename U>
+  void Construct(SequencedTaskRunner& task_runner, std::unique_ptr<U> arg) {
+    // TODO(https://crbug.com/1382549): Use universal forwarding and assert that
+    // there is one arg that is a unique_ptr for better error messages.
+    DCHECK(!ptr_);
+
+    ptr_ = arg.release();
+    // No additional storage needs to be allocated since `T` is already
+    // constructed and lives on the heap.
+  }
+
+  template <typename U>
+  void TakeFrom(Storage<std::unique_ptr<U>, CrossThreadTraits>&& other) {
+    ptr_ = std::exchange(other.ptr_, nullptr);
+  }
+
+  void Destruct(SequencedTaskRunner& task_runner) {
+    CrossThreadTraits::PostTask(
+        task_runner, FROM_HERE,
+        CrossThreadTraits::BindOnce(&InternalDestruct,
+                                    CrossThreadTraits::Unretained(ptr_)));
+
+    ptr_ = nullptr;
+  }
+
+ private:
+  // Needed to allow conversions from compatible `U`s.
+  template <typename U, typename V>
+  friend class Storage;
+
+  static void InternalDestruct(T* ptr) { delete ptr; }
+
+  // Pointer to the heap-allocated `T`.
+  Ptr ptr_ = nullptr;
+};
+
+}  // namespace base::sequence_bound_internal
+
+#endif  // BASE_THREADING_SEQUENCE_BOUND_INTERNAL_H_
diff --git a/base/threading/sequence_bound_unittest.cc b/base/threading/sequence_bound_unittest.cc
index 9288b06..5d9a718 100644
--- a/base/threading/sequence_bound_unittest.cc
+++ b/base/threading/sequence_bound_unittest.cc
@@ -1,317 +1,1152 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/sequence_bound.h"
 
+#include <functional>
+#include <memory>
+#include <utility>
+
+#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ref.h"
 #include "base/run_loop.h"
-#include "base/test/scoped_task_environment.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/sequence_checker.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/lock.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/thread_pool.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
+#include "build/build_config.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
 
-class SequenceBoundTest : public ::testing::Test {
+namespace {
+
+class EventLogger {
  public:
-  // Helpful values that our test classes use.
-  enum Value {
-    kInitialValue = 0,
-    kDifferentValue = 1,
+  EventLogger() = default;
 
-    // Values used by the Derived class.
-    kDerivedCtorValue = 111,
-    kDerivedDtorValue = 222,
+  void AddEvent(StringPiece event) {
+    AutoLock guard(lock_);
+    events_.push_back(std::string(event));
+  }
+  std::vector<std::string> TakeEvents() {
+    AutoLock guard(lock_);
+    return std::exchange(events_, {});
+  }
 
-    // Values used by the Other class.
-    kOtherCtorValue = 333,
-    kOtherDtorValue = 444,
-  };
-
-  void SetUp() override { task_runner_ = base::ThreadTaskRunnerHandle::Get(); }
-
-  void TearDown() override { scoped_task_environment_.RunUntilIdle(); }
-
-  // Do-nothing base class, just so we can test assignment of derived classes.
-  // It introduces a virtual destructor, so that casting derived classes to
-  // Base should still use the appropriate (virtual) destructor.
-  class Base {
-   public:
-    virtual ~Base() {}
-  };
-
-  // Handy class to set an int ptr to different values, to verify that things
-  // are being run properly.
-  class Derived : public Base {
-   public:
-    Derived(Value* ptr) : ptr_(ptr) { *ptr_ = kDerivedCtorValue; }
-    ~Derived() override { *ptr_ = kDerivedDtorValue; }
-    void SetValue(Value value) { *ptr_ = value; }
-    Value* ptr_;
-  };
-
-  // Another base class, which sets ints to different values.
-  class Other {
-   public:
-    Other(Value* ptr) : ptr_(ptr) { *ptr = kOtherCtorValue; };
-    virtual ~Other() { *ptr_ = kOtherDtorValue; }
-    void SetValue(Value value) { *ptr_ = value; }
-    Value* ptr_;
-  };
-
-  class MultiplyDerived : public Other, public Derived {
-   public:
-    MultiplyDerived(Value* ptr1, Value* ptr2) : Other(ptr1), Derived(ptr2) {}
-  };
-
-  struct VirtuallyDerived : public virtual Base {};
-
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-  Value value = kInitialValue;
+ private:
+  Lock lock_;
+  std::vector<std::string> events_ GUARDED_BY(lock_);
 };
 
-TEST_F(SequenceBoundTest, ConstructThenPostThenReset) {
-  auto derived = SequenceBound<Derived>(task_runner_, &value);
-  EXPECT_FALSE(derived.is_null());
+// Helpers for writing type tests against both `SequenceBound<T>` and
+// `SequenceBound<std::unique_ptr<T>`. The tricky part here is that the
+// constructor and emplace both need to accept variadic args; however,
+// construction of the actual `T` depends on the storage strategy.  The
+// `Wrapper` template provides this layer of indirection to construct the
+// managed `T` while still passing through all the other remaining
+// `SequenceBound` APIs.
+struct DirectVariation {
+  static constexpr bool kManagingTaskRunnerConstructsT = true;
 
-  // Nothing should happen until we run the message loop.
-  EXPECT_EQ(value, kInitialValue);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kDerivedCtorValue);
+  template <typename T>
+  class Wrapper : public SequenceBound<T> {
+   public:
+    template <typename... Args>
+    explicit Wrapper(scoped_refptr<SequencedTaskRunner> task_runner,
+                     Args&&... args)
+        : SequenceBound<T>(std::move(task_runner),
+                           std::forward<Args>(args)...) {}
 
-  // Post now that the object has been constructed.
-  derived.Post(FROM_HERE, &Derived::SetValue, kDifferentValue);
-  EXPECT_EQ(value, kDerivedCtorValue);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kDifferentValue);
+    template <typename... Args>
+    void WrappedEmplace(scoped_refptr<SequencedTaskRunner> task_runner,
+                        Args&&... args) {
+      this->emplace(std::move(task_runner), std::forward<Args>(args)...);
+    }
 
-  // Reset it, and make sure that destruction is posted.  The owner should
-  // report that it is null immediately.
-  derived.Reset();
-  EXPECT_TRUE(derived.is_null());
-  EXPECT_EQ(value, kDifferentValue);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kDerivedDtorValue);
+    using SequenceBound<T>::SequenceBound;
+    using SequenceBound<T>::operator=;
+
+   private:
+    using SequenceBound<T>::emplace;
+  };
+};
+
+struct UniquePtrVariation {
+  static constexpr bool kManagingTaskRunnerConstructsT = false;
+
+  template <typename T>
+  struct Wrapper : public SequenceBound<std::unique_ptr<T>> {
+   public:
+    template <typename... Args>
+    explicit Wrapper(scoped_refptr<SequencedTaskRunner> task_runner,
+                     Args&&... args)
+        : SequenceBound<std::unique_ptr<T>>(
+              std::move(task_runner),
+              std::make_unique<T>(std::forward<Args>(args)...)) {}
+
+    template <typename... Args>
+    void WrappedEmplace(scoped_refptr<SequencedTaskRunner> task_runner,
+                        Args&&... args) {
+      this->emplace(std::move(task_runner),
+                    std::make_unique<T>(std::forward<Args>(args)...));
+    }
+
+    using SequenceBound<std::unique_ptr<T>>::SequenceBound;
+    using SequenceBound<std::unique_ptr<T>>::operator=;
+
+   private:
+    using SequenceBound<std::unique_ptr<T>>::emplace;
+  };
+};
+
+// Helper macros since using the name directly is otherwise quite unwieldy.
+#define SEQUENCE_BOUND_T typename TypeParam::template Wrapper
+// Try to catch tests that inadvertently use SequenceBound<T> directly instead
+// of SEQUENCE_BOUND_T, as that bypasses the point of having a typed test.
+#define SequenceBound PleaseUseSequenceBoundT
+
+template <typename Variation>
+class SequenceBoundTest : public ::testing::Test {
+ public:
+  void TearDown() override {
+    // Make sure that any objects owned by `SequenceBound` have been destroyed
+    // to avoid tripping leak detection.
+    task_environment_.RunUntilIdle();
+  }
+
+  // Helper for tests that want to synchronize on a `SequenceBound` which has
+  // already been `Reset()`: a null `SequenceBound` has no `SequencedTaskRunner`
+  // associated with it, so the usual `FlushPostedTasksForTesting()` helper does
+  // not work.
+  void FlushPostedTasks() {
+    RunLoop run_loop;
+    background_task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  test::TaskEnvironment task_environment_;
+
+  // Task runner to use for SequenceBound's managed `T`.
+  scoped_refptr<SequencedTaskRunner> background_task_runner_ =
+      ThreadPool::CreateSequencedTaskRunner({});
+
+  // Defined as part of the test fixture so that tests using `EventLogger` do
+  // not need to explicitly synchronize on `Reset() to avoid use-after-frees;
+  // instead, tests should rely on `TearDown()` to drain and run any
+  // already-posted cleanup tasks.
+  EventLogger logger_;
+};
+
+using Variations = ::testing::Types<DirectVariation, UniquePtrVariation>;
+TYPED_TEST_SUITE(SequenceBoundTest, Variations);
+
+class Base {
+ public:
+  explicit Base(EventLogger& logger) : logger_(logger) {
+    logger_->AddEvent("constructed Base");
+  }
+  virtual ~Base() { logger_->AddEvent("destroyed Base"); }
+
+ protected:
+  EventLogger& GetLogger() { return *logger_; }
+
+ private:
+  const raw_ref<EventLogger> logger_;
+};
+
+class Derived : public Base {
+ public:
+  explicit Derived(EventLogger& logger) : Base(logger) {
+    GetLogger().AddEvent("constructed Derived");
+  }
+
+  ~Derived() override { GetLogger().AddEvent("destroyed Derived"); }
+
+  void SetValue(int value) {
+    GetLogger().AddEvent(StringPrintf("set Derived to %d", value));
+  }
+};
+
+class Leftmost {
+ public:
+  explicit Leftmost(EventLogger& logger) : logger_(logger) {
+    logger_->AddEvent("constructed Leftmost");
+  }
+  virtual ~Leftmost() { logger_->AddEvent("destroyed Leftmost"); }
+
+  void SetValue(int value) {
+    logger_->AddEvent(StringPrintf("set Leftmost to %d", value));
+  }
+
+ private:
+  const raw_ref<EventLogger> logger_;
+};
+
+class Rightmost : public Base {
+ public:
+  explicit Rightmost(EventLogger& logger) : Base(logger) {
+    GetLogger().AddEvent("constructed Rightmost");
+  }
+
+  ~Rightmost() override { GetLogger().AddEvent("destroyed Rightmost"); }
+
+  void SetValue(int value) {
+    GetLogger().AddEvent(StringPrintf("set Rightmost to %d", value));
+  }
+};
+
+class MultiplyDerived : public Leftmost, public Rightmost {
+ public:
+  explicit MultiplyDerived(EventLogger& logger)
+      : Leftmost(logger), Rightmost(logger) {
+    GetLogger().AddEvent("constructed MultiplyDerived");
+  }
+
+  ~MultiplyDerived() override {
+    GetLogger().AddEvent("destroyed MultiplyDerived");
+  }
+};
+
+class BoxedValue {
+ public:
+  explicit BoxedValue(int initial_value, EventLogger* logger = nullptr)
+      : logger_(logger), value_(initial_value) {
+    sequence_checker_.DetachFromSequence();
+    AddEventIfNeeded(StringPrintf("constructed BoxedValue = %d", value_));
+  }
+
+  BoxedValue(const BoxedValue&) = delete;
+  BoxedValue& operator=(const BoxedValue&) = delete;
+
+  ~BoxedValue() {
+    EXPECT_TRUE(sequence_checker_.CalledOnValidSequence());
+    AddEventIfNeeded(StringPrintf("destroyed BoxedValue = %d", value_));
+    if (destruction_callback_)
+      std::move(destruction_callback_).Run();
+  }
+
+  void set_destruction_callback(OnceClosure callback) {
+    EXPECT_TRUE(sequence_checker_.CalledOnValidSequence());
+    destruction_callback_ = std::move(callback);
+  }
+
+  int value() const {
+    EXPECT_TRUE(sequence_checker_.CalledOnValidSequence());
+    AddEventIfNeeded(StringPrintf("accessed BoxedValue = %d", value_));
+    return value_;
+  }
+  void set_value(int value) {
+    EXPECT_TRUE(sequence_checker_.CalledOnValidSequence());
+    AddEventIfNeeded(
+        StringPrintf("updated BoxedValue from %d to %d", value_, value));
+    value_ = value;
+  }
+
+ private:
+  void AddEventIfNeeded(StringPiece event) const {
+    if (logger_) {
+      logger_->AddEvent(event);
+    }
+  }
+
+  SequenceChecker sequence_checker_;
+
+  mutable raw_ptr<EventLogger> logger_ = nullptr;
+
+  int value_ = 0;
+  OnceClosure destruction_callback_;
+};
+
+// Smoke test that all interactions with the wrapped object are posted to the
+// correct task runner.
+class SequenceValidator {
+ public:
+  explicit SequenceValidator(scoped_refptr<SequencedTaskRunner> task_runner,
+                             bool constructs_on_managing_task_runner)
+      : task_runner_(std::move(task_runner)) {
+    if (constructs_on_managing_task_runner) {
+      EXPECT_TRUE(task_runner_->RunsTasksInCurrentSequence());
+    }
+  }
+
+  ~SequenceValidator() {
+    EXPECT_TRUE(task_runner_->RunsTasksInCurrentSequence());
+  }
+
+  void ReturnsVoid() const {
+    EXPECT_TRUE(task_runner_->RunsTasksInCurrentSequence());
+  }
+
+  void ReturnsVoidMutable() {
+    EXPECT_TRUE(task_runner_->RunsTasksInCurrentSequence());
+  }
+
+  int ReturnsInt() const {
+    EXPECT_TRUE(task_runner_->RunsTasksInCurrentSequence());
+    return 0;
+  }
+
+  int ReturnsIntMutable() {
+    EXPECT_TRUE(task_runner_->RunsTasksInCurrentSequence());
+    return 0;
+  }
+
+ private:
+  scoped_refptr<SequencedTaskRunner> task_runner_;
+};
+
+TYPED_TEST(SequenceBoundTest, SequenceValidation) {
+  SEQUENCE_BOUND_T<SequenceValidator> validator(
+      this->background_task_runner_, this->background_task_runner_,
+      TypeParam::kManagingTaskRunnerConstructsT);
+  validator.AsyncCall(&SequenceValidator::ReturnsVoid);
+  validator.AsyncCall(&SequenceValidator::ReturnsVoidMutable);
+  validator.AsyncCall(&SequenceValidator::ReturnsInt).Then(BindOnce([](int) {
+  }));
+  validator.AsyncCall(&SequenceValidator::ReturnsIntMutable)
+      .Then(BindOnce([](int) {}));
+  validator.AsyncCall(IgnoreResult(&SequenceValidator::ReturnsInt));
+  validator.AsyncCall(IgnoreResult(&SequenceValidator::ReturnsIntMutable));
+  validator.WrappedEmplace(this->background_task_runner_,
+                           this->background_task_runner_,
+                           TypeParam::kManagingTaskRunnerConstructsT);
+  validator.PostTaskWithThisObject(BindLambdaForTesting(
+      [](const SequenceValidator& v) { v.ReturnsVoid(); }));
+  validator.PostTaskWithThisObject(BindLambdaForTesting(
+      [](SequenceValidator* v) { v->ReturnsVoidMutable(); }));
+  validator.Reset();
+  this->FlushPostedTasks();
 }
 
-TEST_F(SequenceBoundTest, PostBeforeConstruction) {
-  // Construct an object and post a message to it, before construction has been
-  // run on |task_runner_|.
-  auto derived = SequenceBound<Derived>(task_runner_, &value);
-  derived.Post(FROM_HERE, &Derived::SetValue, kDifferentValue);
-  EXPECT_EQ(value, kInitialValue);
-  // Both construction and SetValue should run.
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kDifferentValue);
+TYPED_TEST(SequenceBoundTest, Basic) {
+  SEQUENCE_BOUND_T<BoxedValue> value(this->background_task_runner_, 0,
+                                     &this->logger_);
+  // Construction of `BoxedValue` may be posted to `background_task_runner_`,
+  // but the `SequenceBound` itself should immediately be treated as valid /
+  // non-null.
+  EXPECT_FALSE(value.is_null());
+  EXPECT_TRUE(value);
+  value.FlushPostedTasksForTesting();
+  EXPECT_THAT(this->logger_.TakeEvents(),
+              ::testing::ElementsAre("constructed BoxedValue = 0"));
+
+  value.AsyncCall(&BoxedValue::set_value).WithArgs(66);
+  value.FlushPostedTasksForTesting();
+  EXPECT_THAT(this->logger_.TakeEvents(),
+              ::testing::ElementsAre("updated BoxedValue from 0 to 66"));
+
+  // Destruction of `BoxedValue` may be posted to `background_task_runner_`, but
+  // the `SequenceBound` itself should immediately be treated as valid /
+  // non-null.
+  value.Reset();
+  EXPECT_TRUE(value.is_null());
+  EXPECT_FALSE(value);
+  this->FlushPostedTasks();
+  EXPECT_THAT(this->logger_.TakeEvents(),
+              ::testing::ElementsAre("destroyed BoxedValue = 66"));
 }
 
-TEST_F(SequenceBoundTest, MoveConstructionFromSameClass) {
-  // Verify that we can move-construct with the same class.
-  auto derived_old = SequenceBound<Derived>(task_runner_, &value);
-  auto derived_new = std::move(derived_old);
+TYPED_TEST(SequenceBoundTest, ConstructAndImmediateAsyncCall) {
+  // Calling `AsyncCall` immediately after construction should always work.
+  SEQUENCE_BOUND_T<BoxedValue> value(this->background_task_runner_, 0,
+                                     &this->logger_);
+  value.AsyncCall(&BoxedValue::set_value).WithArgs(8);
+  value.FlushPostedTasksForTesting();
+  EXPECT_THAT(this->logger_.TakeEvents(),
+              ::testing::ElementsAre("constructed BoxedValue = 0",
+                                     "updated BoxedValue from 0 to 8"));
+}
+
+TYPED_TEST(SequenceBoundTest, MoveConstruction) {
+  // std::ref() is required here: internally, the async work is bound into the
+  // standard base callback infrastructure, which requires the explicit use of
+  // `std::cref()` and `std::ref()` when passing by reference.
+  SEQUENCE_BOUND_T<Derived> derived_old(this->background_task_runner_,
+                                        std::ref(this->logger_));
+  SEQUENCE_BOUND_T<Derived> derived_new = std::move(derived_old);
+  // NOLINTNEXTLINE(bugprone-use-after-move)
   EXPECT_TRUE(derived_old.is_null());
   EXPECT_FALSE(derived_new.is_null());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kDerivedCtorValue);
-
-  // Verify that |derived_new| owns the object now, and that the virtual
-  // destructor is called.
   derived_new.Reset();
-  EXPECT_EQ(value, kDerivedCtorValue);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kDerivedDtorValue);
+  this->FlushPostedTasks();
+  EXPECT_THAT(this->logger_.TakeEvents(),
+              ::testing::ElementsAre("constructed Base", "constructed Derived",
+                                     "destroyed Derived", "destroyed Base"));
 }
 
-TEST_F(SequenceBoundTest, MoveConstructionFromDerivedClass) {
-  // Verify that we can move-construct to a base class from a derived class.
-  auto derived = SequenceBound<Derived>(task_runner_, &value);
-  SequenceBound<Base> base(std::move(derived));
+TYPED_TEST(SequenceBoundTest, MoveConstructionUpcastsToBase) {
+  SEQUENCE_BOUND_T<Derived> derived(this->background_task_runner_,
+                                    std::ref(this->logger_));
+  SEQUENCE_BOUND_T<Base> base = std::move(derived);
+  // NOLINTNEXTLINE(bugprone-use-after-move)
   EXPECT_TRUE(derived.is_null());
   EXPECT_FALSE(base.is_null());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kDerivedCtorValue);
 
-  // Verify that |base| owns the object now, and that destruction still destroys
-  // Derived properly.
+  // The original `Derived` object is now owned by `SequencedBound<Base>`; make
+  // sure `~Derived()` still runs when it is reset.
   base.Reset();
-  EXPECT_EQ(value, kDerivedCtorValue);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kDerivedDtorValue);
+  this->FlushPostedTasks();
+  EXPECT_THAT(this->logger_.TakeEvents(),
+              ::testing::ElementsAre("constructed Base", "constructed Derived",
+                                     "destroyed Derived", "destroyed Base"));
 }
 
-TEST_F(SequenceBoundTest, MultiplyDerivedDestructionWorksLeftSuper) {
-  // Verify that everything works when we're casting around in ways that might
-  // change the address.  We cast to the left side of MultiplyDerived and then
-  // reset the owner.  ASAN will catch free() errors.
-  Value value2 = kInitialValue;
-  auto mderived = SequenceBound<MultiplyDerived>(task_runner_, &value, &value2);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kOtherCtorValue);
-  EXPECT_EQ(value2, kDerivedCtorValue);
-  SequenceBound<Other> other = std::move(mderived);
+// Classes with multiple-derived bases may need pointer adjustments when
+// upcasting. These tests rely on sanitizers to catch potential mistakes.
+TYPED_TEST(SequenceBoundTest, MoveConstructionUpcastsToLeftmost) {
+  SEQUENCE_BOUND_T<MultiplyDerived> multiply_derived(
+      this->background_task_runner_, std::ref(this->logger_));
+  SEQUENCE_BOUND_T<Leftmost> leftmost_base = std::move(multiply_derived);
+  // NOLINTNEXTLINE(bugprone-use-after-move)
+  EXPECT_TRUE(multiply_derived.is_null());
+  EXPECT_FALSE(leftmost_base.is_null());
 
-  other.Reset();
-  base::RunLoop().RunUntilIdle();
-
-  // Both destructors should have run.
-  EXPECT_EQ(value, kOtherDtorValue);
-  EXPECT_EQ(value2, kDerivedDtorValue);
+  // The original `MultiplyDerived` object is now owned by
+  // `SequencedBound<Leftmost>`; make sure all the expected destructors
+  // still run when it is reset.
+  leftmost_base.Reset();
+  this->FlushPostedTasks();
+  EXPECT_THAT(
+      this->logger_.TakeEvents(),
+      ::testing::ElementsAre(
+          "constructed Leftmost", "constructed Base", "constructed Rightmost",
+          "constructed MultiplyDerived", "destroyed MultiplyDerived",
+          "destroyed Rightmost", "destroyed Base", "destroyed Leftmost"));
 }
 
-TEST_F(SequenceBoundTest, MultiplyDerivedDestructionWorksRightSuper) {
-  // Verify that everything works when we're casting around in ways that might
-  // change the address.  We cast to the right side of MultiplyDerived and then
-  // reset the owner.  ASAN will catch free() errors.
-  Value value2 = kInitialValue;
-  auto mderived = SequenceBound<MultiplyDerived>(task_runner_, &value, &value2);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kOtherCtorValue);
-  EXPECT_EQ(value2, kDerivedCtorValue);
-  SequenceBound<Base> base = std::move(mderived);
+TYPED_TEST(SequenceBoundTest, MoveConstructionUpcastsToRightmost) {
+  SEQUENCE_BOUND_T<MultiplyDerived> multiply_derived(
+      this->background_task_runner_, std::ref(this->logger_));
+  SEQUENCE_BOUND_T<Rightmost> rightmost_base = std::move(multiply_derived);
+  // NOLINTNEXTLINE(bugprone-use-after-move)
+  EXPECT_TRUE(multiply_derived.is_null());
+  EXPECT_FALSE(rightmost_base.is_null());
 
-  base.Reset();
-  base::RunLoop().RunUntilIdle();
-
-  // Both destructors should have run.
-  EXPECT_EQ(value, kOtherDtorValue);
-  EXPECT_EQ(value2, kDerivedDtorValue);
+  // The original `MultiplyDerived` object is now owned by
+  // `SequencedBound<Rightmost>`; make sure all the expected destructors
+  // still run when it is reset.
+  rightmost_base.Reset();
+  this->FlushPostedTasks();
+  EXPECT_THAT(
+      this->logger_.TakeEvents(),
+      ::testing::ElementsAre(
+          "constructed Leftmost", "constructed Base", "constructed Rightmost",
+          "constructed MultiplyDerived", "destroyed MultiplyDerived",
+          "destroyed Rightmost", "destroyed Base", "destroyed Leftmost"));
 }
 
-TEST_F(SequenceBoundTest, MoveAssignmentFromSameClass) {
-  // Test move-assignment using the same classes.
-  auto derived_old = SequenceBound<Derived>(task_runner_, &value);
-  SequenceBound<Derived> derived_new;
+TYPED_TEST(SequenceBoundTest, MoveAssignment) {
+  SEQUENCE_BOUND_T<Derived> derived_old(this->background_task_runner_,
+                                        std::ref(this->logger_));
+  SEQUENCE_BOUND_T<Derived> derived_new;
 
   derived_new = std::move(derived_old);
+  // NOLINTNEXTLINE(bugprone-use-after-move)
   EXPECT_TRUE(derived_old.is_null());
   EXPECT_FALSE(derived_new.is_null());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kDerivedCtorValue);
 
-  // Verify that |derived_new| owns the object now.  Also verifies that move
-  // assignment from the same class deletes the outgoing object.
-  derived_new = SequenceBound<Derived>();
-  EXPECT_EQ(value, kDerivedCtorValue);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kDerivedDtorValue);
+  // Note that this explicitly avoids using `Reset()` as a basic test that
+  // assignment resets any previously-owned object.
+  derived_new = SEQUENCE_BOUND_T<Derived>();
+  this->FlushPostedTasks();
+  EXPECT_THAT(this->logger_.TakeEvents(),
+              ::testing::ElementsAre("constructed Base", "constructed Derived",
+                                     "destroyed Derived", "destroyed Base"));
 }
 
-TEST_F(SequenceBoundTest, MoveAssignmentFromDerivedClass) {
-  // Move-assignment from a derived class to a base class.
-  auto derived = SequenceBound<Derived>(task_runner_, &value);
-  SequenceBound<Base> base;
+TYPED_TEST(SequenceBoundTest, MoveAssignmentUpcastsToBase) {
+  SEQUENCE_BOUND_T<Derived> derived(this->background_task_runner_,
+                                    std::ref(this->logger_));
+  SEQUENCE_BOUND_T<Base> base;
 
   base = std::move(derived);
+  // NOLINTNEXTLINE(bugprone-use-after-move)
   EXPECT_TRUE(derived.is_null());
   EXPECT_FALSE(base.is_null());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kDerivedCtorValue);
 
-  // Verify that |base| owns the object now, and that destruction still destroys
-  // Derived properly.
+  // The original `Derived` object is now owned by `SequencedBound<Base>`; make
+  // sure `~Derived()` still runs when it is reset.
   base.Reset();
-  EXPECT_EQ(value, kDerivedCtorValue);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kDerivedDtorValue);
+  this->FlushPostedTasks();
+  EXPECT_THAT(this->logger_.TakeEvents(),
+              ::testing::ElementsAre("constructed Base", "constructed Derived",
+                                     "destroyed Derived", "destroyed Base"));
 }
 
-TEST_F(SequenceBoundTest, MoveAssignmentFromDerivedClassDestroysOldObject) {
-  // Verify that move-assignment from a derived class runs the dtor of the
-  // outgoing object.
-  auto derived = SequenceBound<Derived>(task_runner_, &value);
+TYPED_TEST(SequenceBoundTest, MoveAssignmentUpcastsToLeftmost) {
+  SEQUENCE_BOUND_T<MultiplyDerived> multiply_derived(
+      this->background_task_runner_, std::ref(this->logger_));
+  SEQUENCE_BOUND_T<Leftmost> leftmost_base;
 
-  Value value1 = kInitialValue;
-  Value value2 = kInitialValue;
-  auto mderived =
-      SequenceBound<MultiplyDerived>(task_runner_, &value1, &value2);
-  base::RunLoop().RunUntilIdle();
+  leftmost_base = std::move(multiply_derived);
+  // NOLINTNEXTLINE(bugprone-use-after-move)
+  EXPECT_TRUE(multiply_derived.is_null());
+  EXPECT_FALSE(leftmost_base.is_null());
 
-  EXPECT_EQ(value, kDerivedCtorValue);
-
-  // Assign |mderived|, and verify that the original object in |derived| is
-  // destroyed properly.
-  derived = std::move(mderived);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(value, kDerivedDtorValue);
-
-  // Delete |derived|, since it has pointers to local vars.
-  derived.Reset();
-  base::RunLoop().RunUntilIdle();
+  // The original `MultiplyDerived` object is now owned by
+  // `SequencedBound<Leftmost>`; make sure all the expected destructors
+  // still run when it is reset.
+  leftmost_base.Reset();
+  this->FlushPostedTasks();
+  EXPECT_THAT(
+      this->logger_.TakeEvents(),
+      ::testing::ElementsAre(
+          "constructed Leftmost", "constructed Base", "constructed Rightmost",
+          "constructed MultiplyDerived", "destroyed MultiplyDerived",
+          "destroyed Rightmost", "destroyed Base", "destroyed Leftmost"));
 }
 
-TEST_F(SequenceBoundTest, MultiplyDerivedPostToLeftBaseClass) {
-  // Cast and call methods on the left base class.
-  Value value1 = kInitialValue;
-  Value value2 = kInitialValue;
-  auto mderived =
-      SequenceBound<MultiplyDerived>(task_runner_, &value1, &value2);
+TYPED_TEST(SequenceBoundTest, MoveAssignmentUpcastsToRightmost) {
+  SEQUENCE_BOUND_T<MultiplyDerived> multiply_derived(
+      this->background_task_runner_, std::ref(this->logger_));
+  SEQUENCE_BOUND_T<Rightmost> rightmost_base;
 
-  // Cast to Other, the left base.
-  SequenceBound<Other> other(std::move(mderived));
-  other.Post(FROM_HERE, &Other::SetValue, kDifferentValue);
+  rightmost_base = std::move(multiply_derived);
+  // NOLINTNEXTLINE(bugprone-use-after-move)
+  EXPECT_TRUE(multiply_derived.is_null());
+  EXPECT_FALSE(rightmost_base.is_null());
 
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(value1, kDifferentValue);
-  EXPECT_EQ(value2, kDerivedCtorValue);
-
-  other.Reset();
-  base::RunLoop().RunUntilIdle();
+  // The original `MultiplyDerived` object is now owned by
+  // `SequencedBound<Rightmost>`; make sure all the expected destructors
+  // still run when it is reset.
+  rightmost_base.Reset();
+  this->FlushPostedTasks();
+  EXPECT_THAT(
+      this->logger_.TakeEvents(),
+      ::testing::ElementsAre(
+          "constructed Leftmost", "constructed Base", "constructed Rightmost",
+          "constructed MultiplyDerived", "destroyed MultiplyDerived",
+          "destroyed Rightmost", "destroyed Base", "destroyed Leftmost"));
 }
 
-TEST_F(SequenceBoundTest, MultiplyDerivedPostToRightBaseClass) {
-  // Cast and call methods on the right base class.
-  Value value1 = kInitialValue;
-  Value value2 = kInitialValue;
-  auto mderived =
-      SequenceBound<MultiplyDerived>(task_runner_, &value1, &value2);
-
-  SequenceBound<Derived> derived(std::move(mderived));
-  derived.Post(FROM_HERE, &Derived::SetValue, kDifferentValue);
-
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(value1, kOtherCtorValue);
-  EXPECT_EQ(value2, kDifferentValue);
-
-  derived.Reset();
-  base::RunLoop().RunUntilIdle();
+TYPED_TEST(SequenceBoundTest, AsyncCallLeftmost) {
+  SEQUENCE_BOUND_T<MultiplyDerived> multiply_derived(
+      this->background_task_runner_, std::ref(this->logger_));
+  multiply_derived.AsyncCall(&Leftmost::SetValue).WithArgs(3);
+  multiply_derived.FlushPostedTasksForTesting();
+  EXPECT_THAT(this->logger_.TakeEvents(),
+              ::testing::ElementsAre("constructed Leftmost", "constructed Base",
+                                     "constructed Rightmost",
+                                     "constructed MultiplyDerived",
+                                     "set Leftmost to 3"));
 }
 
-TEST_F(SequenceBoundTest, MoveConstructionFromNullWorks) {
-  // Verify that this doesn't crash.
-  SequenceBound<Derived> derived1;
-  SequenceBound<Derived> derived2(std::move(derived1));
+TYPED_TEST(SequenceBoundTest, AsyncCallRightmost) {
+  SEQUENCE_BOUND_T<MultiplyDerived> multiply_derived(
+      this->background_task_runner_, std::ref(this->logger_));
+  multiply_derived.AsyncCall(&Rightmost::SetValue).WithArgs(3);
+  multiply_derived.FlushPostedTasksForTesting();
+  EXPECT_THAT(this->logger_.TakeEvents(),
+              ::testing::ElementsAre("constructed Leftmost", "constructed Base",
+                                     "constructed Rightmost",
+                                     "constructed MultiplyDerived",
+                                     "set Rightmost to 3"));
 }
 
-TEST_F(SequenceBoundTest, MoveAssignmentFromNullWorks) {
-  // Verify that this doesn't crash.
-  SequenceBound<Derived> derived1;
-  SequenceBound<Derived> derived2;
-  derived2 = std::move(derived1);
+TYPED_TEST(SequenceBoundTest, MoveConstructionFromNull) {
+  SEQUENCE_BOUND_T<BoxedValue> value1;
+  // Should not crash.
+  SEQUENCE_BOUND_T<BoxedValue> value2(std::move(value1));
 }
 
-TEST_F(SequenceBoundTest, ResetOnNullObjectWorks) {
-  // Verify that this doesn't crash.
-  SequenceBound<Derived> derived;
-  derived.Reset();
+TYPED_TEST(SequenceBoundTest, MoveAssignmentFromNull) {
+  SEQUENCE_BOUND_T<BoxedValue> value1;
+  SEQUENCE_BOUND_T<BoxedValue> value2;
+  // Should not crash.
+  value2 = std::move(value1);
 }
 
-TEST_F(SequenceBoundTest, IsVirtualBaseClassOf) {
-  // Check that is_virtual_base_of<> works properly.
-
-  // Neither |Base| nor |Derived| is a virtual base of the other.
-  static_assert(!internal::is_virtual_base_of<Base, Derived>::value,
-                "|Base| shouldn't be a virtual base of |Derived|");
-  static_assert(!internal::is_virtual_base_of<Derived, Base>::value,
-                "|Derived| shouldn't be a virtual base of |Base|");
-
-  // |Base| should be a virtual base class of |VirtuallyDerived|, but not the
-  // other way.
-  static_assert(internal::is_virtual_base_of<Base, VirtuallyDerived>::value,
-                "|Base| should be a virtual base of |VirtuallyDerived|");
-  static_assert(!internal::is_virtual_base_of<VirtuallyDerived, Base>::value,
-                "|VirtuallyDerived shouldn't be a virtual base of |Base|");
+TYPED_TEST(SequenceBoundTest, MoveAssignmentFromSelf) {
+  SEQUENCE_BOUND_T<BoxedValue> value;
+  // Cheat to avoid clang self-move warning.
+  auto& value2 = value;
+  // Should not crash.
+  value2 = std::move(value);
 }
 
+TYPED_TEST(SequenceBoundTest, ResetNullSequenceBound) {
+  SEQUENCE_BOUND_T<BoxedValue> value;
+  // Should not crash.
+  value.Reset();
+}
+
+TYPED_TEST(SequenceBoundTest, ConstructWithLvalue) {
+  int lvalue = 99;
+  SEQUENCE_BOUND_T<BoxedValue> value(this->background_task_runner_, lvalue,
+                                     &this->logger_);
+  value.FlushPostedTasksForTesting();
+  EXPECT_THAT(this->logger_.TakeEvents(),
+              ::testing::ElementsAre("constructed BoxedValue = 99"));
+}
+
+TYPED_TEST(SequenceBoundTest, PostTaskWithThisObject) {
+  constexpr int kTestValue1 = 42;
+  constexpr int kTestValue2 = 42;
+  SEQUENCE_BOUND_T<BoxedValue> value(this->background_task_runner_,
+                                     kTestValue1);
+  value.PostTaskWithThisObject(BindLambdaForTesting(
+      [&](const BoxedValue& v) { EXPECT_EQ(kTestValue1, v.value()); }));
+  value.PostTaskWithThisObject(
+      BindLambdaForTesting([&](BoxedValue* v) { v->set_value(kTestValue2); }));
+  value.PostTaskWithThisObject(BindLambdaForTesting(
+      [&](const BoxedValue& v) { EXPECT_EQ(kTestValue2, v.value()); }));
+  value.FlushPostedTasksForTesting();
+}
+
+TYPED_TEST(SequenceBoundTest, SynchronouslyResetForTest) {
+  SEQUENCE_BOUND_T<BoxedValue> value(this->background_task_runner_, 0);
+
+  bool destroyed = false;
+  value.AsyncCall(&BoxedValue::set_destruction_callback)
+      .WithArgs(BindLambdaForTesting([&] { destroyed = true; }));
+
+  value.SynchronouslyResetForTest();
+  EXPECT_TRUE(destroyed);
+}
+
+TYPED_TEST(SequenceBoundTest, FlushPostedTasksForTesting) {
+  SEQUENCE_BOUND_T<BoxedValue> value(this->background_task_runner_, 0,
+                                     &this->logger_);
+
+  value.AsyncCall(&BoxedValue::set_value).WithArgs(42);
+  value.FlushPostedTasksForTesting();
+
+  EXPECT_THAT(this->logger_.TakeEvents(),
+              ::testing::ElementsAre("constructed BoxedValue = 0",
+                                     "updated BoxedValue from 0 to 42"));
+}
+
+TYPED_TEST(SequenceBoundTest, SmallObject) {
+  class EmptyClass {};
+  SEQUENCE_BOUND_T<EmptyClass> value(this->background_task_runner_);
+  // Test passes if SequenceBound constructor does not crash in AlignedAlloc().
+}
+
+TYPED_TEST(SequenceBoundTest, SelfMoveAssign) {
+  class EmptyClass {};
+  SEQUENCE_BOUND_T<EmptyClass> value(this->background_task_runner_);
+  EXPECT_FALSE(value.is_null());
+  // Clang has a warning for self-move, so be clever.
+  auto& actually_the_same_value = value;
+  value = std::move(actually_the_same_value);
+  // Note: in general, moved-from objects are in a valid but undefined state.
+  // This is merely a test that self-move doesn't result in something bad
+  // happening; this is not an assertion that self-move will always have this
+  // behavior.
+  EXPECT_TRUE(value.is_null());
+}
+
+TYPED_TEST(SequenceBoundTest, Emplace) {
+  SEQUENCE_BOUND_T<BoxedValue> value;
+  EXPECT_TRUE(value.is_null());
+  value.WrappedEmplace(this->background_task_runner_, 8);
+  value.AsyncCall(&BoxedValue::value)
+      .Then(BindLambdaForTesting(
+          [&](int actual_value) { EXPECT_EQ(8, actual_value); }));
+  value.FlushPostedTasksForTesting();
+}
+
+TYPED_TEST(SequenceBoundTest, EmplaceOverExisting) {
+  SEQUENCE_BOUND_T<BoxedValue> value(this->background_task_runner_, 8,
+                                     &this->logger_);
+  EXPECT_FALSE(value.is_null());
+  value.WrappedEmplace(this->background_task_runner_, 9, &this->logger_);
+  value.AsyncCall(&BoxedValue::value)
+      .Then(BindLambdaForTesting(
+          [&](int actual_value) { EXPECT_EQ(9, actual_value); }));
+  value.FlushPostedTasksForTesting();
+
+  if constexpr (TypeParam::kManagingTaskRunnerConstructsT) {
+    // Both the replaced `BoxedValue` and the current `BoxedValue` should
+    // live on the same sequence: make sure the replaced `BoxedValue` was
+    // destroyed before the current `BoxedValue` was constructed.
+    EXPECT_THAT(this->logger_.TakeEvents(),
+                ::testing::ElementsAre(
+                    "constructed BoxedValue = 8", "destroyed BoxedValue = 8",
+                    "constructed BoxedValue = 9", "accessed BoxedValue = 9"));
+  } else {
+    // When `SequenceBound` manages a `std::unique_ptr<T>`, `T` is constructed
+    // on the current sequence so construction of the new managed instance will
+    // happen before the previously-managed instance is destroyed on the
+    // managing task runner.
+    EXPECT_THAT(this->logger_.TakeEvents(),
+                ::testing::ElementsAre(
+                    "constructed BoxedValue = 8", "constructed BoxedValue = 9",
+                    "destroyed BoxedValue = 8", "accessed BoxedValue = 9"));
+  }
+}
+
+TYPED_TEST(SequenceBoundTest, EmplaceOverExistingWithTaskRunnerSwap) {
+  scoped_refptr<SequencedTaskRunner> another_task_runner =
+      ThreadPool::CreateSequencedTaskRunner({});
+  // No `EventLogger` here since destruction of the old `BoxedValue` and
+  // construction of the new `BoxedValue` take place on different sequences and
+  // can arbitrarily race.
+  SEQUENCE_BOUND_T<BoxedValue> value(another_task_runner, 8);
+  EXPECT_FALSE(value.is_null());
+  value.WrappedEmplace(this->background_task_runner_, 9);
+  {
+    value.PostTaskWithThisObject(BindLambdaForTesting(
+        [another_task_runner,
+         background_task_runner =
+             this->background_task_runner_](const BoxedValue& boxed_value) {
+          EXPECT_FALSE(another_task_runner->RunsTasksInCurrentSequence());
+          EXPECT_TRUE(background_task_runner->RunsTasksInCurrentSequence());
+          EXPECT_EQ(9, boxed_value.value());
+        }));
+    value.FlushPostedTasksForTesting();
+  }
+}
+
+namespace {
+
+class NoArgsVoidReturn {
+ public:
+  void Method() {
+    if (loop_) {
+      loop_->Quit();
+      loop_ = nullptr;
+    }
+  }
+  void ConstMethod() const {
+    if (loop_) {
+      loop_->Quit();
+      loop_ = nullptr;
+    }
+  }
+
+  void set_loop(RunLoop* loop) { loop_ = loop; }
+
+ private:
+  mutable raw_ptr<RunLoop> loop_ = nullptr;
+};
+
+class NoArgsIntReturn {
+ public:
+  int Method() { return 123; }
+  int ConstMethod() const { return 456; }
+};
+
+class IntArgVoidReturn {
+ public:
+  IntArgVoidReturn(int* method_called_with, int* const_method_called_with)
+      : method_called_with_(method_called_with),
+        const_method_called_with_(const_method_called_with) {}
+
+  void Method(int x) {
+    *method_called_with_ = x;
+    method_called_with_ = nullptr;
+    if (loop_) {
+      loop_->Quit();
+      loop_ = nullptr;
+    }
+  }
+  void ConstMethod(int x) const {
+    *const_method_called_with_ = x;
+    const_method_called_with_ = nullptr;
+    if (loop_) {
+      loop_->Quit();
+      loop_ = nullptr;
+    }
+  }
+
+  void set_loop(RunLoop* loop) { loop_ = loop; }
+
+ private:
+  raw_ptr<int> method_called_with_;
+  mutable raw_ptr<int> const_method_called_with_;
+  mutable raw_ptr<RunLoop> loop_ = nullptr;
+};
+
+class IntArgIntReturn {
+ public:
+  int Method(int x) { return -x; }
+  int ConstMethod(int x) const { return -x; }
+};
+
+}  // namespace
+
+TYPED_TEST(SequenceBoundTest, AsyncCallNoArgsNoThen) {
+  SEQUENCE_BOUND_T<NoArgsVoidReturn> s(this->background_task_runner_);
+
+  {
+    RunLoop loop;
+    s.AsyncCall(&NoArgsVoidReturn::set_loop).WithArgs(&loop);
+    s.AsyncCall(&NoArgsVoidReturn::Method);
+    loop.Run();
+  }
+
+  {
+    RunLoop loop;
+    s.AsyncCall(&NoArgsVoidReturn::set_loop).WithArgs(&loop);
+    s.AsyncCall(&NoArgsVoidReturn::ConstMethod);
+    loop.Run();
+  }
+}
+
+TYPED_TEST(SequenceBoundTest, AsyncCallIntArgNoThen) {
+  int method_called_with = 0;
+  int const_method_called_with = 0;
+  SEQUENCE_BOUND_T<IntArgVoidReturn> s(this->background_task_runner_,
+                                       &method_called_with,
+                                       &const_method_called_with);
+
+  {
+    RunLoop loop;
+    s.AsyncCall(&IntArgVoidReturn::set_loop).WithArgs(&loop);
+    s.AsyncCall(&IntArgVoidReturn::Method).WithArgs(123);
+    loop.Run();
+    EXPECT_EQ(123, method_called_with);
+  }
+
+  {
+    RunLoop loop;
+    s.AsyncCall(&IntArgVoidReturn::set_loop).WithArgs(&loop);
+    s.AsyncCall(&IntArgVoidReturn::ConstMethod).WithArgs(456);
+    loop.Run();
+    EXPECT_EQ(456, const_method_called_with);
+  }
+}
+
+TYPED_TEST(SequenceBoundTest, AsyncCallNoArgsVoidThen) {
+  SEQUENCE_BOUND_T<NoArgsVoidReturn> s(this->background_task_runner_);
+
+  {
+    RunLoop loop;
+    s.AsyncCall(&NoArgsVoidReturn::Method).Then(BindLambdaForTesting([&]() {
+      loop.Quit();
+    }));
+    loop.Run();
+  }
+
+  {
+    RunLoop loop;
+    s.AsyncCall(&NoArgsVoidReturn::ConstMethod)
+        .Then(BindLambdaForTesting([&]() { loop.Quit(); }));
+    loop.Run();
+  }
+}
+
+TYPED_TEST(SequenceBoundTest, AsyncCallNoArgsIntThen) {
+  SEQUENCE_BOUND_T<NoArgsIntReturn> s(this->background_task_runner_);
+
+  {
+    RunLoop loop;
+    s.AsyncCall(&NoArgsIntReturn::Method)
+        .Then(BindLambdaForTesting([&](int result) {
+          EXPECT_EQ(123, result);
+          loop.Quit();
+        }));
+    loop.Run();
+  }
+
+  {
+    RunLoop loop;
+    s.AsyncCall(&NoArgsIntReturn::ConstMethod)
+        .Then(BindLambdaForTesting([&](int result) {
+          EXPECT_EQ(456, result);
+          loop.Quit();
+        }));
+    loop.Run();
+  }
+}
+
+TYPED_TEST(SequenceBoundTest, AsyncCallWithArgsVoidThen) {
+  int method_called_with = 0;
+  int const_method_called_with = 0;
+  SEQUENCE_BOUND_T<IntArgVoidReturn> s(this->background_task_runner_,
+                                       &method_called_with,
+                                       &const_method_called_with);
+
+  {
+    RunLoop loop;
+    s.AsyncCall(&IntArgVoidReturn::Method)
+        .WithArgs(123)
+        .Then(BindLambdaForTesting([&] { loop.Quit(); }));
+    loop.Run();
+    EXPECT_EQ(123, method_called_with);
+  }
+
+  {
+    RunLoop loop;
+    s.AsyncCall(&IntArgVoidReturn::ConstMethod)
+        .WithArgs(456)
+        .Then(BindLambdaForTesting([&] { loop.Quit(); }));
+    loop.Run();
+    EXPECT_EQ(456, const_method_called_with);
+  }
+}
+
+TYPED_TEST(SequenceBoundTest, AsyncCallWithArgsIntThen) {
+  SEQUENCE_BOUND_T<IntArgIntReturn> s(this->background_task_runner_);
+
+  {
+    RunLoop loop;
+    s.AsyncCall(&IntArgIntReturn::Method)
+        .WithArgs(123)
+        .Then(BindLambdaForTesting([&](int result) {
+          EXPECT_EQ(-123, result);
+          loop.Quit();
+        }));
+    loop.Run();
+  }
+
+  {
+    RunLoop loop;
+    s.AsyncCall(&IntArgIntReturn::ConstMethod)
+        .WithArgs(456)
+        .Then(BindLambdaForTesting([&](int result) {
+          EXPECT_EQ(-456, result);
+          loop.Quit();
+        }));
+    loop.Run();
+  }
+}
+
+TYPED_TEST(SequenceBoundTest, AsyncCallIsConstQualified) {
+  // Tests that both const and non-const methods may be called through a
+  // const-qualified SequenceBound.
+  const SEQUENCE_BOUND_T<NoArgsVoidReturn> s(this->background_task_runner_);
+  s.AsyncCall(&NoArgsVoidReturn::ConstMethod);
+  s.AsyncCall(&NoArgsVoidReturn::Method);
+}
+
+class IgnoreResultTestHelperWithNoArgs {
+ public:
+  explicit IgnoreResultTestHelperWithNoArgs(RunLoop* loop, bool* called)
+      : loop_(loop), called_(called) {}
+
+  int ConstMethod() const {
+    if (loop_) {
+      loop_->Quit();
+      loop_ = nullptr;
+    }
+    if (called_) {
+      *called_ = true;
+      called_ = nullptr;
+    }
+    return 0;
+  }
+
+  int Method() {
+    if (loop_) {
+      loop_->Quit();
+      loop_ = nullptr;
+    }
+    if (called_) {
+      *called_ = true;
+      called_ = nullptr;
+    }
+    return 0;
+  }
+
+ private:
+  mutable raw_ptr<RunLoop> loop_ = nullptr;
+  mutable raw_ptr<bool> called_ = nullptr;
+};
+
+TYPED_TEST(SequenceBoundTest, AsyncCallIgnoreResultNoArgs) {
+  {
+    RunLoop loop;
+    SEQUENCE_BOUND_T<IgnoreResultTestHelperWithNoArgs> s(
+        this->background_task_runner_, &loop, nullptr);
+    s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::ConstMethod));
+    loop.Run();
+  }
+
+  {
+    RunLoop loop;
+    SEQUENCE_BOUND_T<IgnoreResultTestHelperWithNoArgs> s(
+        this->background_task_runner_, &loop, nullptr);
+    s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::Method));
+    loop.Run();
+  }
+}
+
+TYPED_TEST(SequenceBoundTest, AsyncCallIgnoreResultThen) {
+  {
+    RunLoop loop;
+    bool called = false;
+    SEQUENCE_BOUND_T<IgnoreResultTestHelperWithNoArgs> s(
+        this->background_task_runner_, nullptr, &called);
+    s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::ConstMethod))
+        .Then(BindLambdaForTesting([&] { loop.Quit(); }));
+    loop.Run();
+    EXPECT_TRUE(called);
+  }
+
+  {
+    RunLoop loop;
+    bool called = false;
+    SEQUENCE_BOUND_T<IgnoreResultTestHelperWithNoArgs> s(
+        this->background_task_runner_, nullptr, &called);
+    s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithNoArgs::Method))
+        .Then(BindLambdaForTesting([&] { loop.Quit(); }));
+    loop.Run();
+    EXPECT_TRUE(called);
+  }
+}
+
+class IgnoreResultTestHelperWithArgs {
+ public:
+  IgnoreResultTestHelperWithArgs(RunLoop* loop, int& value)
+      : loop_(loop), value_(&value) {}
+
+  int ConstMethod(int arg) const {
+    if (value_) {
+      *value_ = arg;
+      value_ = nullptr;
+    }
+    if (loop_) {
+      loop_->Quit();
+      loop_ = nullptr;
+    }
+    return arg;
+  }
+
+  int Method(int arg) {
+    if (value_) {
+      *value_ = arg;
+      value_ = nullptr;
+    }
+    if (loop_) {
+      loop_->Quit();
+      loop_ = nullptr;
+    }
+    return arg;
+  }
+
+ private:
+  mutable raw_ptr<RunLoop> loop_ = nullptr;
+  mutable raw_ptr<int> value_;
+};
+
+TYPED_TEST(SequenceBoundTest, AsyncCallIgnoreResultWithArgs) {
+  {
+    RunLoop loop;
+    int result = 0;
+    SEQUENCE_BOUND_T<IgnoreResultTestHelperWithArgs> s(
+        this->background_task_runner_, &loop, std::ref(result));
+    s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::ConstMethod))
+        .WithArgs(60);
+    loop.Run();
+    EXPECT_EQ(60, result);
+  }
+
+  {
+    RunLoop loop;
+    int result = 0;
+    SEQUENCE_BOUND_T<IgnoreResultTestHelperWithArgs> s(
+        this->background_task_runner_, &loop, std::ref(result));
+    s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::Method))
+        .WithArgs(06);
+    loop.Run();
+    EXPECT_EQ(06, result);
+  }
+}
+
+TYPED_TEST(SequenceBoundTest, AsyncCallIgnoreResultWithArgsThen) {
+  {
+    RunLoop loop;
+    int result = 0;
+    SEQUENCE_BOUND_T<IgnoreResultTestHelperWithArgs> s(
+        this->background_task_runner_, nullptr, std::ref(result));
+    s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::ConstMethod))
+        .WithArgs(60)
+        .Then(BindLambdaForTesting([&] { loop.Quit(); }));
+    loop.Run();
+    EXPECT_EQ(60, result);
+  }
+
+  {
+    RunLoop loop;
+    int result = 0;
+    SEQUENCE_BOUND_T<IgnoreResultTestHelperWithArgs> s(
+        this->background_task_runner_, nullptr, std::ref(result));
+    s.AsyncCall(IgnoreResult(&IgnoreResultTestHelperWithArgs::Method))
+        .WithArgs(06)
+        .Then(BindLambdaForTesting([&] { loop.Quit(); }));
+    loop.Run();
+    EXPECT_EQ(06, result);
+  }
+}
+
+// TODO(https://crbug.com/1382549): Maybe use the nocompile harness here instead
+// of being "clever"...
+TYPED_TEST(SequenceBoundTest, NoCompileTests) {
+  // TODO(https://crbug.com/1382549): Test calling WithArgs() on a method that
+  // takes no arguments.
+  //
+  // Given:
+  //   class C {
+  //     void F();
+  //   };
+  //
+  // Then:
+  //   SequenceBound<C> s(...);
+  //   s.AsyncCall(&C::F).WithArgs(...);
+  //
+  // should not compile.
+  //
+  // TODO(https://crbug.com/1382549): Test calling Then() before calling
+  // WithArgs().
+  //
+  // Given:
+  //   class C {
+  //     void F(int);
+  //   };
+  //
+  // Then:
+  //   SequenceBound<C> s(...);
+  //   s.AsyncCall(&C::F).Then(...).WithArgs(...);
+  //
+  // should not compile.
+  //
+  // TODO(https://crbug.com/1382549): Add no-compile tests for converting
+  // between SequenceBound<T> and SequenceBound<std::unique_ptr<T>>.
+}
+#undef SequenceBound
+
+class SequenceBoundDeathTest : public ::testing::Test {
+ protected:
+  void TearDown() override {
+    // Make sure that any objects owned by `SequenceBound` have been destroyed
+    // to avoid tripping leak detection.
+    RunLoop run_loop;
+    task_runner_->PostTask(FROM_HERE, run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  // Death tests use fork(), which can interact (very) poorly with threads.
+  test::SingleThreadTaskEnvironment task_environment_;
+  scoped_refptr<SequencedTaskRunner> task_runner_ =
+      SequencedTaskRunner::GetCurrentDefault();
+};
+
+TEST_F(SequenceBoundDeathTest, AsyncCallIntArgNoWithArgsShouldCheck) {
+  SequenceBound<IntArgIntReturn> s(task_runner_);
+  EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&IntArgIntReturn::Method), "");
+}
+
+TEST_F(SequenceBoundDeathTest, AsyncCallIntReturnNoThenShouldCheck) {
+  {
+    SequenceBound<NoArgsIntReturn> s(task_runner_);
+    EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&NoArgsIntReturn::Method), "");
+  }
+
+  {
+    SequenceBound<IntArgIntReturn> s(task_runner_);
+    EXPECT_DEATH_IF_SUPPORTED(s.AsyncCall(&IntArgIntReturn::Method).WithArgs(0),
+                              "");
+  }
+}
+
+}  // namespace
+
 }  // namespace base
diff --git a/base/threading/sequence_local_storage_map.cc b/base/threading/sequence_local_storage_map.cc
index 2837aa0..3dcb03d 100644
--- a/base/threading/sequence_local_storage_map.cc
+++ b/base/threading/sequence_local_storage_map.cc
@@ -1,50 +1,78 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/sequence_local_storage_map.h"
 
+#include <ostream>
 #include <utility>
 
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/threading/thread_local.h"
+#include "base/check_op.h"
+#include "third_party/abseil-cpp/absl/base/attributes.h"
+
+#if defined(STARBOARD)
+#include <pthread.h>
+
+#include "base/check_op.h"
+#include "starboard/thread.h"
+#endif
 
 namespace base {
 namespace internal {
 
 namespace {
-LazyInstance<ThreadLocalPointer<SequenceLocalStorageMap>>::Leaky
-    tls_current_sequence_local_storage = LAZY_INSTANCE_INITIALIZER;
+
+#if defined(STARBOARD)
+ABSL_CONST_INIT pthread_once_t s_once_flag = PTHREAD_ONCE_INIT;
+ABSL_CONST_INIT pthread_key_t s_thread_local_key = 0;
+
+void InitThreadLocalKey() {
+  int res = pthread_key_create(&s_thread_local_key , NULL);
+  DCHECK(res == 0);
+}
+
+void EnsureThreadLocalKeyInited() {
+  pthread_once(&s_once_flag, InitThreadLocalKey);
+}
+
+SequenceLocalStorageMap* GetCurrentSequenceLocalStorage() {
+  EnsureThreadLocalKeyInited();
+  return static_cast<SequenceLocalStorageMap*>(
+      pthread_getspecific(s_thread_local_key));
+}
+#else
+ABSL_CONST_INIT thread_local SequenceLocalStorageMap*
+    current_sequence_local_storage = nullptr;
+#endif
+
 }  // namespace
 
 SequenceLocalStorageMap::SequenceLocalStorageMap() = default;
 
 SequenceLocalStorageMap::~SequenceLocalStorageMap() = default;
 
-ScopedSetSequenceLocalStorageMapForCurrentThread::
-    ScopedSetSequenceLocalStorageMapForCurrentThread(
-        SequenceLocalStorageMap* sequence_local_storage) {
-  DCHECK(!tls_current_sequence_local_storage.Get().Get());
-  tls_current_sequence_local_storage.Get().Set(sequence_local_storage);
-}
-
-ScopedSetSequenceLocalStorageMapForCurrentThread::
-    ~ScopedSetSequenceLocalStorageMapForCurrentThread() {
-  tls_current_sequence_local_storage.Get().Set(nullptr);
-}
-
+// static
 SequenceLocalStorageMap& SequenceLocalStorageMap::GetForCurrentThread() {
-  SequenceLocalStorageMap* current_sequence_local_storage =
-      tls_current_sequence_local_storage.Get().Get();
-
-  DCHECK(current_sequence_local_storage)
+  DCHECK(IsSetForCurrentThread())
       << "SequenceLocalStorageSlot cannot be used because no "
          "SequenceLocalStorageMap was stored in TLS. Use "
          "ScopedSetSequenceLocalStorageMapForCurrentThread to store a "
          "SequenceLocalStorageMap object in TLS.";
 
+#if defined(STARBOARD)
+  return *GetCurrentSequenceLocalStorage();
+#else
   return *current_sequence_local_storage;
+#endif
+}
+
+// static
+bool SequenceLocalStorageMap::IsSetForCurrentThread() {
+#if defined(STARBOARD)
+  return GetCurrentSequenceLocalStorage() != nullptr;
+#else
+  return current_sequence_local_storage != nullptr;
+#endif
 }
 
 void* SequenceLocalStorageMap::Get(int slot_id) {
@@ -101,5 +129,30 @@
   return *this;
 }
 
+ScopedSetSequenceLocalStorageMapForCurrentThread::
+    ScopedSetSequenceLocalStorageMapForCurrentThread(
+        SequenceLocalStorageMap* sequence_local_storage)
+#if defined(STARBOARD)
+{
+  EnsureThreadLocalKeyInited();
+  pthread_setspecific(s_thread_local_key, sequence_local_storage);
+}
+#else
+    : resetter_(&current_sequence_local_storage,
+                sequence_local_storage,
+                nullptr) {}
+#endif
+
+#if defined(STARBOARD)
+ScopedSetSequenceLocalStorageMapForCurrentThread::
+    ~ScopedSetSequenceLocalStorageMapForCurrentThread() {
+  EnsureThreadLocalKeyInited();
+  pthread_setspecific(s_thread_local_key, nullptr);
+}
+#else
+ScopedSetSequenceLocalStorageMapForCurrentThread::
+    ~ScopedSetSequenceLocalStorageMapForCurrentThread() = default;
+#endif
+
 }  // namespace internal
 }  // namespace base
diff --git a/base/threading/sequence_local_storage_map.h b/base/threading/sequence_local_storage_map.h
index 8b9155c..64e1bf0 100644
--- a/base/threading/sequence_local_storage_map.h
+++ b/base/threading/sequence_local_storage_map.h
@@ -1,13 +1,14 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef BASE_THREADING_SEQUENCE_LOCAL_STORAGE_MAP_H_
 #define BASE_THREADING_SEQUENCE_LOCAL_STORAGE_MAP_H_
 
+#include "base/auto_reset.h"
 #include "base/base_export.h"
 #include "base/containers/flat_map.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr_exclusion.h"
 
 namespace base {
 namespace internal {
@@ -15,7 +16,7 @@
 // A SequenceLocalStorageMap holds (slot_id) -> (value, destructor) items for a
 // sequence. When a task runs, it is expected that a pointer to its sequence's
 // SequenceLocalStorageMap is set in TLS using
-// ScopedSetSequenceMapLocalStorageForCurrentThread. When a
+// ScopedSetSequenceLocalStorageMapForCurrentThread. When a
 // SequenceLocalStorageMap is destroyed, it invokes the destructors associated
 // with values stored within it.
 // The Get() and Set() methods should not be accessed directly.
@@ -24,6 +25,10 @@
 class BASE_EXPORT SequenceLocalStorageMap {
  public:
   SequenceLocalStorageMap();
+
+  SequenceLocalStorageMap(const SequenceLocalStorageMap&) = delete;
+  SequenceLocalStorageMap& operator=(const SequenceLocalStorageMap&) = delete;
+
   ~SequenceLocalStorageMap();
 
   // Returns the SequenceLocalStorage bound to the current thread. It is invalid
@@ -31,6 +36,11 @@
   // ScopedSetSequenceLocalStorageForCurrentThread.
   static SequenceLocalStorageMap& GetForCurrentThread();
 
+  // Indicates whether the current thread has a SequenceLocalStorageMap
+  // available and thus whether it can safely call GetForCurrentThread and
+  // dereference SequenceLocalStorageSlots.
+  static bool IsSetForCurrentThread();
+
   // Holds a pointer to a value alongside a destructor for this pointer.
   // Calls the destructor on the value upon destruction.
   class BASE_EXPORT ValueDestructorPair {
@@ -38,6 +48,10 @@
     using DestructorFunc = void(void*);
 
     ValueDestructorPair(void* value, DestructorFunc* destructor);
+
+    ValueDestructorPair(const ValueDestructorPair&) = delete;
+    ValueDestructorPair& operator=(const ValueDestructorPair&) = delete;
+
     ~ValueDestructorPair();
 
     ValueDestructorPair(ValueDestructorPair&& value_destructor_pair);
@@ -47,10 +61,10 @@
     void* value() const { return value_; }
 
    private:
-    void* value_;
-    DestructorFunc* destructor_;
-
-    DISALLOW_COPY_AND_ASSIGN(ValueDestructorPair);
+    // `value_` and `destructor_` are not a raw_ptr<...> for performance reasons
+    // (based on analysis of sampling profiler data and tab_search:top100:2020).
+    RAW_PTR_EXCLUSION void* value_;
+    RAW_PTR_EXCLUSION DestructorFunc* destructor_;
   };
 
   // Returns the value stored in |slot_id| or nullptr if no value was stored.
@@ -66,23 +80,30 @@
   // in the map. For low number of entries, flat_map is known to perform better
   // than other map implementations.
   base::flat_map<int, ValueDestructorPair> sls_map_;
-
-  DISALLOW_COPY_AND_ASSIGN(SequenceLocalStorageMap);
 };
 
 // Within the scope of this object,
 // SequenceLocalStorageMap::GetForCurrentThread() will return a reference to the
 // SequenceLocalStorageMap object passed to the constructor. There can be only
 // one ScopedSetSequenceLocalStorageMapForCurrentThread instance per scope.
-class BASE_EXPORT ScopedSetSequenceLocalStorageMapForCurrentThread {
+class BASE_EXPORT
+    [[maybe_unused,
+      nodiscard]] ScopedSetSequenceLocalStorageMapForCurrentThread {
  public:
   ScopedSetSequenceLocalStorageMapForCurrentThread(
       SequenceLocalStorageMap* sequence_local_storage);
 
+  ScopedSetSequenceLocalStorageMapForCurrentThread(
+      const ScopedSetSequenceLocalStorageMapForCurrentThread&) = delete;
+  ScopedSetSequenceLocalStorageMapForCurrentThread& operator=(
+      const ScopedSetSequenceLocalStorageMapForCurrentThread&) = delete;
+
   ~ScopedSetSequenceLocalStorageMapForCurrentThread();
 
+#if !defined(STARBOARD)
  private:
-  DISALLOW_COPY_AND_ASSIGN(ScopedSetSequenceLocalStorageMapForCurrentThread);
+  const base::AutoReset<SequenceLocalStorageMap*> resetter_;
+#endif
 };
 }  // namespace internal
 }  // namespace base
diff --git a/base/threading/sequence_local_storage_map_unittest.cc b/base/threading/sequence_local_storage_map_unittest.cc
index a45bbc3..4869427 100644
--- a/base/threading/sequence_local_storage_map_unittest.cc
+++ b/base/threading/sequence_local_storage_map_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/memory/raw_ptr.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -23,15 +24,17 @@
     DCHECK(was_destroyed_ptr_);
     DCHECK(!(*was_destroyed_ptr_));
   }
+
+  SetOnDestroy(const SetOnDestroy&) = delete;
+  SetOnDestroy& operator=(const SetOnDestroy&) = delete;
+
   ~SetOnDestroy() {
     DCHECK(!(*was_destroyed_ptr_));
     *was_destroyed_ptr_ = true;
   }
 
  private:
-  bool* const was_destroyed_ptr_;
-
-  DISALLOW_COPY_AND_ASSIGN(SetOnDestroy);
+  const raw_ptr<bool> was_destroyed_ptr_;
 };
 
 template <typename T, typename... Args>
diff --git a/base/threading/sequence_local_storage_slot.cc b/base/threading/sequence_local_storage_slot.cc
index b7db40b..8dc49c9 100644
--- a/base/threading/sequence_local_storage_slot.cc
+++ b/base/threading/sequence_local_storage_slot.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -7,7 +7,7 @@
 #include <limits>
 
 #include "base/atomic_sequence_num.h"
-#include "base/logging.h"
+#include "base/check_op.h"
 
 namespace base {
 namespace internal {
@@ -23,4 +23,5 @@
 }
 
 }  // namespace internal
+
 }  // namespace base
diff --git a/base/threading/sequence_local_storage_slot.h b/base/threading/sequence_local_storage_slot.h
index 315df7d..12c04bb 100644
--- a/base/threading/sequence_local_storage_slot.h
+++ b/base/threading/sequence_local_storage_slot.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "base/base_export.h"
+#include "base/template_util.h"
 #include "base/threading/sequence_local_storage_map.h"
 
 namespace base {
@@ -22,17 +23,18 @@
 //
 // Example usage:
 //
-// namespace {
-// base::LazyInstance<SequenceLocalStorageSlot<int>> sls_value;
+// int& GetSequenceLocalStorage()
+//     static base::NoDestructor<SequenceLocalStorageSlot<int>> sls_value;
+//     return sls_value->GetOrCreateValue();
 // }
 //
 // void Read() {
-//   int value = sls_value.Get().Get();
+//   int value = GetSequenceLocalStorage();
 //   ...
 // }
 //
 // void Write() {
-//   sls_value.Get().Set(42);
+//   GetSequenceLocalStorage() = 42;
 // }
 //
 // void PostTasks() {
@@ -46,36 +48,61 @@
 //
 // SequenceLocalStorageSlot must be used within the scope of a
 // ScopedSetSequenceLocalStorageMapForCurrentThread object.
-// Note: this is true on all TaskScheduler workers and on threads bound to a
+// Note: this is true on all ThreadPool workers and on threads bound to a
 // MessageLoop.
 template <typename T, typename Deleter = std::default_delete<T>>
 class SequenceLocalStorageSlot {
  public:
   SequenceLocalStorageSlot()
       : slot_id_(internal::GetNextSequenceLocalStorageSlotNumber()) {}
+
+  SequenceLocalStorageSlot(const SequenceLocalStorageSlot&) = delete;
+  SequenceLocalStorageSlot& operator=(const SequenceLocalStorageSlot&) = delete;
+
   ~SequenceLocalStorageSlot() = default;
 
-  // Get the sequence-local value stored in this slot. Returns a
-  // default-constructed value if no value was previously set.
-  T& Get() {
-    void* value =
-        internal::SequenceLocalStorageMap::GetForCurrentThread().Get(slot_id_);
+  operator bool() const { return GetValuePointer() != nullptr; }
 
-    // Sets and returns a default-constructed value if no value was previously
-    // set.
-    if (!value) {
-      Set(T());
-      return Get();
-    }
-    return *(static_cast<T*>(value));
+  // Default-constructs the value for the current sequence if not
+  // already constructed. Then, returns the value.
+  T& GetOrCreateValue() {
+    T* ptr = GetValuePointer();
+    if (!ptr)
+      ptr = emplace();
+    return *ptr;
   }
 
-  // Set this slot's sequence-local value to |value|.
-  // Note that if T is expensive to copy, it may be more appropriate to instead
-  // store a std::unique_ptr<T>. This is enforced by the
-  // DISALLOW_COPY_AND_ASSIGN style rather than directly by this class however.
-  void Set(T value) {
-    // Allocates the |value| with new rather than std::make_unique.
+  // Returns a pointer to the value for the current sequence. May be
+  // nullptr if the value was not constructed on the current sequence.
+  T* GetValuePointer() {
+    void* ptr =
+        internal::SequenceLocalStorageMap::GetForCurrentThread().Get(slot_id_);
+    return static_cast<T*>(ptr);
+  }
+  const T* GetValuePointer() const {
+    return const_cast<SequenceLocalStorageSlot*>(this)->GetValuePointer();
+  }
+
+  T* operator->() { return GetValuePointer(); }
+  const T* operator->() const { return GetValuePointer(); }
+
+  T& operator*() { return *GetValuePointer(); }
+  const T& operator*() const { return *GetValuePointer(); }
+
+  void reset() { Adopt(nullptr); }
+
+  // Constructs this slot's sequence-local value with |args...| and returns a
+  // pointer to the created object.
+  template <class... Args>
+  T* emplace(Args&&... args) {
+    T* value_ptr = new T(std::forward<Args>(args)...);
+    Adopt(value_ptr);
+    return value_ptr;
+  }
+
+ private:
+  // Takes ownership of |value_ptr|.
+  void Adopt(T* value_ptr) {
     // Since SequenceLocalStorageMap needs to store values of various types
     // within the same map, the type of value_destructor_pair.value is void*
     // (std::unique_ptr<void> is invalid). Memory is freed by calling
@@ -83,8 +110,6 @@
     // ValueDestructorPair which is invoked when the value is overwritten by
     // another call to SequenceLocalStorageMap::Set or when the
     // SequenceLocalStorageMap is deleted.
-    T* value_ptr = new T(std::move(value));
-
     internal::SequenceLocalStorageMap::ValueDestructorPair::DestructorFunc*
         destructor = [](void* ptr) { Deleter()(static_cast<T*>(ptr)); };
 
@@ -95,10 +120,8 @@
         slot_id_, std::move(value_destructor_pair));
   }
 
- private:
   // |slot_id_| is used as a key in SequenceLocalStorageMap
   const int slot_id_;
-  DISALLOW_COPY_AND_ASSIGN(SequenceLocalStorageSlot);
 };
 
 }  // namespace base
diff --git a/base/threading/sequence_local_storage_slot_unittest.cc b/base/threading/sequence_local_storage_slot_unittest.cc
index 4a9f6a9..982c59c 100644
--- a/base/threading/sequence_local_storage_slot_unittest.cc
+++ b/base/threading/sequence_local_storage_slot_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -6,7 +6,6 @@
 
 #include <utility>
 
-#include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/threading/sequence_local_storage_map.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -16,6 +15,11 @@
 namespace {
 
 class SequenceLocalStorageSlotTest : public testing::Test {
+ public:
+  SequenceLocalStorageSlotTest(const SequenceLocalStorageSlotTest&) = delete;
+  SequenceLocalStorageSlotTest& operator=(const SequenceLocalStorageSlotTest&) =
+      delete;
+
  protected:
   SequenceLocalStorageSlotTest()
       : scoped_sequence_local_storage_(&sequence_local_storage_) {}
@@ -23,77 +27,80 @@
   internal::SequenceLocalStorageMap sequence_local_storage_;
   internal::ScopedSetSequenceLocalStorageMapForCurrentThread
       scoped_sequence_local_storage_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SequenceLocalStorageSlotTest);
 };
 
 }  // namespace
 
 // Verify that a value stored with Set() can be retrieved with Get().
-TEST_F(SequenceLocalStorageSlotTest, GetSet) {
+TEST_F(SequenceLocalStorageSlotTest, GetEmplace) {
   SequenceLocalStorageSlot<int> slot;
-  slot.Set(5);
-  EXPECT_EQ(slot.Get(), 5);
+  slot.emplace(5);
+  EXPECT_EQ(*slot, 5);
 }
 
-// Verify that setting an object in a SequenceLocalStorageSlot creates a copy
+// Verify that inserting an object in a SequenceLocalStorageSlot creates a copy
 // of that object independent of the original one.
-TEST_F(SequenceLocalStorageSlotTest, SetObjectIsIndependent) {
+TEST_F(SequenceLocalStorageSlotTest, EmplaceObjectIsIndependent) {
   bool should_be_false = false;
 
   SequenceLocalStorageSlot<bool> slot;
 
-  slot.Set(should_be_false);
+  slot.emplace(should_be_false);
 
-  EXPECT_FALSE(slot.Get());
-  slot.Get() = true;
-  EXPECT_TRUE(slot.Get());
+  EXPECT_FALSE(*slot);
+  *slot = true;
+  EXPECT_TRUE(*slot);
 
-  EXPECT_NE(should_be_false, slot.Get());
+  EXPECT_NE(should_be_false, *slot);
 }
 
 // Verify that multiple slots work and that calling Get after overwriting
 // a value in a slot yields the new value.
-TEST_F(SequenceLocalStorageSlotTest, GetSetMultipleSlots) {
+TEST_F(SequenceLocalStorageSlotTest, GetEmplaceMultipleSlots) {
   SequenceLocalStorageSlot<int> slot1;
   SequenceLocalStorageSlot<int> slot2;
   SequenceLocalStorageSlot<int> slot3;
+  EXPECT_FALSE(slot1);
+  EXPECT_FALSE(slot2);
+  EXPECT_FALSE(slot3);
 
-  slot1.Set(1);
-  slot2.Set(2);
-  slot3.Set(3);
+  slot1.emplace(1);
+  slot2.emplace(2);
+  slot3.emplace(3);
 
-  EXPECT_EQ(slot1.Get(), 1);
-  EXPECT_EQ(slot2.Get(), 2);
-  EXPECT_EQ(slot3.Get(), 3);
+  EXPECT_TRUE(slot1);
+  EXPECT_TRUE(slot2);
+  EXPECT_TRUE(slot3);
+  EXPECT_EQ(*slot1, 1);
+  EXPECT_EQ(*slot2, 2);
+  EXPECT_EQ(*slot3, 3);
 
-  slot3.Set(4);
-  slot2.Set(5);
-  slot1.Set(6);
+  slot3.emplace(4);
+  slot2.emplace(5);
+  slot1.emplace(6);
 
-  EXPECT_EQ(slot3.Get(), 4);
-  EXPECT_EQ(slot2.Get(), 5);
-  EXPECT_EQ(slot1.Get(), 6);
+  EXPECT_EQ(*slot3, 4);
+  EXPECT_EQ(*slot2, 5);
+  EXPECT_EQ(*slot1, 6);
 }
 
-// Verify that changing the the value returned by Get() changes the value
+// Verify that changing the value returned by Get() changes the value
 // in sequence local storage.
 TEST_F(SequenceLocalStorageSlotTest, GetReferenceModifiable) {
   SequenceLocalStorageSlot<bool> slot;
-  slot.Set(false);
-  slot.Get() = true;
-  EXPECT_TRUE(slot.Get());
+  slot.emplace(false);
+  *slot = true;
+  EXPECT_TRUE(*slot);
 }
 
 // Verify that a move-only type can be stored in sequence local storage.
-TEST_F(SequenceLocalStorageSlotTest, SetGetWithMoveOnlyType) {
+TEST_F(SequenceLocalStorageSlotTest, EmplaceGetWithMoveOnlyType) {
   std::unique_ptr<int> int_unique_ptr = std::make_unique<int>(5);
 
   SequenceLocalStorageSlot<std::unique_ptr<int>> slot;
-  slot.Set(std::move(int_unique_ptr));
+  slot.emplace(std::move(int_unique_ptr));
 
-  EXPECT_EQ(*slot.Get(), 5);
+  EXPECT_EQ(*slot->get(), 5);
 }
 
 // Verify that a Get() without a previous Set() on a slot returns a
@@ -105,38 +112,38 @@
 
   SequenceLocalStorageSlot<DefaultConstructable> slot;
 
-  EXPECT_EQ(slot.Get().x, 0x12345678);
+  EXPECT_EQ(slot.GetOrCreateValue().x, 0x12345678);
 }
 
-// Verify that a Get() without a previous Set() on a slot with a POD-type
-// returns a default-constructed value.
+// Verify that a GetOrCreateValue() without a previous emplace() on a slot with
+// a POD-type returns a default-constructed value.
 // Note: this test could be flaky and give a false pass. If it's flaky, the test
 // might've "passed" because the memory for the slot happened to be zeroed.
 TEST_F(SequenceLocalStorageSlotTest, GetWithoutSetDefaultConstructsPOD) {
   SequenceLocalStorageSlot<void*> slot;
 
-  EXPECT_EQ(slot.Get(), nullptr);
+  EXPECT_EQ(slot.GetOrCreateValue(), nullptr);
 }
 
 // Verify that the value of a slot is specific to a SequenceLocalStorageMap
-TEST(SequenceLocalStorageSlotMultipleMapTest, SetGetMultipleMapsOneSlot) {
+TEST(SequenceLocalStorageSlotMultipleMapTest, EmplaceGetMultipleMapsOneSlot) {
   SequenceLocalStorageSlot<unsigned int> slot;
   internal::SequenceLocalStorageMap sequence_local_storage_maps[5];
 
   // Set the value of the slot to be the index of the current
   // SequenceLocalStorageMaps in the vector
-  for (unsigned int i = 0; i < arraysize(sequence_local_storage_maps); ++i) {
+  for (unsigned int i = 0; i < std::size(sequence_local_storage_maps); ++i) {
     internal::ScopedSetSequenceLocalStorageMapForCurrentThread
         scoped_sequence_local_storage(&sequence_local_storage_maps[i]);
 
-    slot.Set(i);
+    slot.emplace(i);
   }
 
-  for (unsigned int i = 0; i < arraysize(sequence_local_storage_maps); ++i) {
+  for (unsigned int i = 0; i < std::size(sequence_local_storage_maps); ++i) {
     internal::ScopedSetSequenceLocalStorageMapForCurrentThread
         scoped_sequence_local_storage(&sequence_local_storage_maps[i]);
 
-    EXPECT_EQ(slot.Get(), i);
+    EXPECT_EQ(*slot, i);
   }
 }
 
diff --git a/base/threading/sequenced_task_runner_handle.cc b/base/threading/sequenced_task_runner_handle.cc
deleted file mode 100644
index e6920f5..0000000
--- a/base/threading/sequenced_task_runner_handle.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2015 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 "base/threading/sequenced_task_runner_handle.h"
-
-#include <utility>
-
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/threading/thread_local.h"
-#include "base/threading/thread_task_runner_handle.h"
-
-namespace base {
-
-namespace {
-
-LazyInstance<ThreadLocalPointer<SequencedTaskRunnerHandle>>::Leaky
-    sequenced_task_runner_tls = LAZY_INSTANCE_INITIALIZER;
-
-}  // namespace
-
-// static
-scoped_refptr<SequencedTaskRunner> SequencedTaskRunnerHandle::Get() {
-  // Return the registered SequencedTaskRunner, if any.
-  const SequencedTaskRunnerHandle* handle =
-      sequenced_task_runner_tls.Pointer()->Get();
-  if (handle)
-    return handle->task_runner_;
-
-  // Note if you hit this: the problem is the lack of a sequenced context. The
-  // ThreadTaskRunnerHandle is just the last attempt at finding such a context.
-  CHECK(ThreadTaskRunnerHandle::IsSet())
-      << "Error: This caller requires a sequenced context (i.e. the "
-         "current task needs to run from a SequencedTaskRunner).";
-  return ThreadTaskRunnerHandle::Get();
-}
-
-// static
-bool SequencedTaskRunnerHandle::IsSet() {
-  return sequenced_task_runner_tls.Pointer()->Get() ||
-         ThreadTaskRunnerHandle::IsSet();
-}
-
-SequencedTaskRunnerHandle::SequencedTaskRunnerHandle(
-    scoped_refptr<SequencedTaskRunner> task_runner)
-    : task_runner_(std::move(task_runner)) {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(!SequencedTaskRunnerHandle::IsSet());
-  sequenced_task_runner_tls.Pointer()->Set(this);
-}
-
-SequencedTaskRunnerHandle::~SequencedTaskRunnerHandle() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  DCHECK_EQ(sequenced_task_runner_tls.Pointer()->Get(), this);
-  sequenced_task_runner_tls.Pointer()->Set(nullptr);
-}
-
-}  // namespace base
diff --git a/base/threading/sequenced_task_runner_handle.h b/base/threading/sequenced_task_runner_handle.h
deleted file mode 100644
index f55cee5..0000000
--- a/base/threading/sequenced_task_runner_handle.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2015 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 BASE_THREADING_SEQUENCED_TASK_RUNNER_HANDLE_H_
-#define BASE_THREADING_SEQUENCED_TASK_RUNNER_HANDLE_H_
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
-
-namespace base {
-
-class BASE_EXPORT SequencedTaskRunnerHandle {
- public:
-  // Returns a SequencedTaskRunner which guarantees that posted tasks will only
-  // run after the current task is finished and will satisfy a SequenceChecker.
-  // It should only be called if IsSet() returns true (see the comment there for
-  // the requirements).
-  static scoped_refptr<SequencedTaskRunner> Get();
-
-  // Returns true if one of the following conditions is fulfilled:
-  // a) A SequencedTaskRunner has been assigned to the current thread by
-  //    instantiating a SequencedTaskRunnerHandle.
-  // b) The current thread has a ThreadTaskRunnerHandle (which includes any
-  //    thread that has a MessageLoop associated with it).
-  static bool IsSet();
-
-  // Binds |task_runner| to the current thread.
-  explicit SequencedTaskRunnerHandle(
-      scoped_refptr<SequencedTaskRunner> task_runner);
-  ~SequencedTaskRunnerHandle();
-
- private:
-  scoped_refptr<SequencedTaskRunner> task_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(SequencedTaskRunnerHandle);
-};
-
-}  // namespace base
-
-#endif  // BASE_THREADING_SEQUENCED_TASK_RUNNER_HANDLE_H_
diff --git a/base/threading/sequenced_task_runner_handle_unittest.cc b/base/threading/sequenced_task_runner_handle_unittest.cc
deleted file mode 100644
index b55e1e7..0000000
--- a/base/threading/sequenced_task_runner_handle_unittest.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2015 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 "base/threading/sequenced_task_runner_handle.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/location.h"
-#include "base/memory/ref_counted.h"
-#include "base/metrics/statistics_recorder.h"
-#include "base/run_loop.h"
-#include "base/sequence_checker_impl.h"
-#include "base/sequenced_task_runner.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/task/post_task.h"
-#include "base/test/scoped_task_environment.h"
-#include "base/test/test_simple_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace {
-
-class SequencedTaskRunnerHandleTest : public ::testing::Test {
- protected:
-  SequencedTaskRunnerHandleTest()
-      : recorder_for_testing_(StatisticsRecorder::CreateTemporaryForTesting()) {
-  }
-  // Verifies that the context it runs on has a SequencedTaskRunnerHandle
-  // and that posting to it results in the posted task running in that same
-  // context (sequence).
-  static void VerifyCurrentSequencedTaskRunner() {
-    ASSERT_TRUE(SequencedTaskRunnerHandle::IsSet());
-    scoped_refptr<SequencedTaskRunner> task_runner =
-        SequencedTaskRunnerHandle::Get();
-    ASSERT_TRUE(task_runner);
-
-    // Use SequenceCheckerImpl to make sure it's not a no-op in Release builds.
-    std::unique_ptr<SequenceCheckerImpl> sequence_checker(
-        new SequenceCheckerImpl);
-    task_runner->PostTask(
-        FROM_HERE,
-        base::BindOnce(&SequencedTaskRunnerHandleTest::CheckValidSequence,
-                       std::move(sequence_checker)));
-  }
-
-  static void CheckValidSequence(
-      std::unique_ptr<SequenceCheckerImpl> sequence_checker) {
-    EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
-  }
-
-  std::unique_ptr<StatisticsRecorder> recorder_for_testing_;
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
-};
-
-TEST_F(SequencedTaskRunnerHandleTest, FromMessageLoop) {
-  VerifyCurrentSequencedTaskRunner();
-  RunLoop().RunUntilIdle();
-}
-
-TEST_F(SequencedTaskRunnerHandleTest, FromTaskSchedulerSequencedTask) {
-  base::CreateSequencedTaskRunnerWithTraits({})->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          &SequencedTaskRunnerHandleTest::VerifyCurrentSequencedTaskRunner));
-  scoped_task_environment_.RunUntilIdle();
-}
-
-TEST_F(SequencedTaskRunnerHandleTest, NoHandleFromUnsequencedTask) {
-  base::PostTask(FROM_HERE, base::BindOnce([]() {
-                   EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet());
-                 }));
-  scoped_task_environment_.RunUntilIdle();
-}
-
-TEST(SequencedTaskRunnerHandleTestWithoutMessageLoop, FromHandleInScope) {
-  scoped_refptr<SequencedTaskRunner> test_task_runner(new TestSimpleTaskRunner);
-  EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet());
-  EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet());
-  {
-    SequencedTaskRunnerHandle handle(test_task_runner);
-    EXPECT_TRUE(SequencedTaskRunnerHandle::IsSet());
-    EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet());
-    EXPECT_EQ(test_task_runner, SequencedTaskRunnerHandle::Get());
-  }
-  EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet());
-  EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet());
-}
-
-}  // namespace
-}  // namespace base
diff --git a/base/threading/simple_thread.cc b/base/threading/simple_thread.cc
index 4b26062..579431f 100644
--- a/base/threading/simple_thread.cc
+++ b/base/threading/simple_thread.cc
@@ -1,22 +1,24 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright 2010 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/simple_thread.h"
 
-#include "base/logging.h"
+#include <ostream>
+
+#include "base/check.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread_restrictions.h"
 
 namespace base {
 
-SimpleThread::SimpleThread(const std::string& name_prefix)
-    : SimpleThread(name_prefix, Options()) {}
+SimpleThread::SimpleThread(const std::string& name)
+    : SimpleThread(name, Options()) {}
 
-SimpleThread::SimpleThread(const std::string& name_prefix,
-                           const Options& options)
-    : name_prefix_(name_prefix),
+SimpleThread::SimpleThread(const std::string& name, const Options& options)
+    : name_(name),
       options_(options),
       event_(WaitableEvent::ResetPolicy::MANUAL,
              WaitableEvent::InitialState::NOT_SIGNALED) {}
@@ -29,7 +31,7 @@
 
 void SimpleThread::Start() {
   StartAsync();
-  ThreadRestrictions::ScopedAllowWait allow_wait;
+  ScopedAllowBaseSyncPrimitives allow_wait;
   event_.Wait();  // Wait for the thread to complete initialization.
 }
 
@@ -49,10 +51,10 @@
   BeforeStart();
   bool success =
       options_.joinable
-          ? PlatformThread::CreateWithPriority(options_.stack_size, this,
-                                               &thread_, options_.priority)
-          : PlatformThread::CreateNonJoinableWithPriority(
-                options_.stack_size, this, options_.priority);
+          ? PlatformThread::CreateWithType(options_.stack_size, this, &thread_,
+                                           options_.thread_type)
+          : PlatformThread::CreateNonJoinableWithType(options_.stack_size, this,
+                                                      options_.thread_type);
   CHECK(success);
 }
 
@@ -62,17 +64,12 @@
 }
 
 bool SimpleThread::HasBeenStarted() {
-  ThreadRestrictions::ScopedAllowWait allow_wait;
   return event_.IsSignaled();
 }
 
 void SimpleThread::ThreadMain() {
   tid_ = PlatformThread::CurrentId();
-  // Construct our full name of the form "name_prefix_/TID".
-  std::string name(name_prefix_);
-  name.push_back('/');
-  name.append(IntToString(tid_));
-  PlatformThread::SetName(name);
+  PlatformThread::SetName(name_);
 
   // We've initialized our new thread, signal that we're done to Start().
   event_.Signal();
@@ -82,14 +79,13 @@
 }
 
 DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate,
-                                           const std::string& name_prefix)
-    : DelegateSimpleThread(delegate, name_prefix, Options()) {}
+                                           const std::string& name)
+    : DelegateSimpleThread(delegate, name, Options()) {}
 
 DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate,
-                                           const std::string& name_prefix,
+                                           const std::string& name,
                                            const Options& options)
-    : SimpleThread(name_prefix, options),
-      delegate_(delegate) {
+    : SimpleThread(name, options), delegate_(delegate) {
   DCHECK(delegate_);
 }
 
@@ -107,7 +103,7 @@
 
 DelegateSimpleThreadPool::DelegateSimpleThreadPool(
     const std::string& name_prefix,
-    int num_threads)
+    size_t num_threads)
     : name_prefix_(name_prefix),
       num_threads_(num_threads),
       dry_(WaitableEvent::ResetPolicy::MANUAL,
@@ -121,8 +117,11 @@
 
 void DelegateSimpleThreadPool::Start() {
   DCHECK(threads_.empty()) << "Start() called with outstanding threads.";
-  for (int i = 0; i < num_threads_; ++i) {
-    DelegateSimpleThread* thread = new DelegateSimpleThread(this, name_prefix_);
+  for (size_t i = 0; i < num_threads_; ++i) {
+    std::string name(name_prefix_);
+    name.push_back('/');
+    name.append(NumberToString(i));
+    DelegateSimpleThread* thread = new DelegateSimpleThread(this, name);
     thread->Start();
     threads_.push_back(thread);
   }
@@ -135,7 +134,7 @@
   AddWork(nullptr, num_threads_);
 
   // Join and destroy all the worker threads.
-  for (int i = 0; i < num_threads_; ++i) {
+  for (size_t i = 0; i < num_threads_; ++i) {
     threads_[i]->Join();
     delete threads_[i];
   }
@@ -143,9 +142,10 @@
   DCHECK(delegates_.empty());
 }
 
-void DelegateSimpleThreadPool::AddWork(Delegate* delegate, int repeat_count) {
+void DelegateSimpleThreadPool::AddWork(Delegate* delegate,
+                                       size_t repeat_count) {
   AutoLock locked(lock_);
-  for (int i = 0; i < repeat_count; ++i)
+  for (size_t i = 0; i < repeat_count; ++i)
     delegates_.push(delegate);
   // If we were empty, signal that we have work now.
   if (!dry_.IsSignaled())
diff --git a/base/threading/simple_thread.h b/base/threading/simple_thread.h
index c4ef5cc..ac7bc01 100644
--- a/base/threading/simple_thread.h
+++ b/base/threading/simple_thread.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -40,28 +40,31 @@
 #ifndef BASE_THREADING_SIMPLE_THREAD_H_
 #define BASE_THREADING_SIMPLE_THREAD_H_
 
+#include <stddef.h>
+
 #include <string>
 #include <vector>
 
 #include "base/base_export.h"
 #include "base/compiler_specific.h"
 #include "base/containers/queue.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread.h"
-#include "starboard/types.h"
 
 namespace base {
 
 // This is the base SimpleThread.  You can derive from it and implement the
 // virtual Run method, or you can use the DelegateSimpleThread interface.
+// SimpleThread should not be used to run a MessagePump, `base::Thread` must be
+// used for that.
 class BASE_EXPORT SimpleThread : public PlatformThread::Delegate {
  public:
   struct BASE_EXPORT Options {
    public:
     Options() = default;
-    explicit Options(ThreadPriority priority_in) : priority(priority_in) {}
+    explicit Options(ThreadType thread_type) : thread_type(thread_type) {}
     ~Options() = default;
 
     // Allow copies.
@@ -71,7 +74,7 @@
     // A custom stack size, or 0 for the system default.
     size_t stack_size = 0;
 
-    ThreadPriority priority = ThreadPriority::NORMAL;
+    ThreadType thread_type = ThreadType::kDefault;
 
     // If false, the underlying thread's PlatformThreadHandle will not be kept
     // around and as such the SimpleThread instance will not be Join()able and
@@ -80,12 +83,15 @@
     bool joinable = true;
   };
 
-  // Create a SimpleThread.  |options| should be used to manage any specific
+  // Creates a SimpleThread. |options| should be used to manage any specific
   // configuration involving the thread creation and management.
-  // Every thread has a name, in the form of |name_prefix|/TID, for example
-  // "my_thread/321".  The thread will not be created until Start() is called.
-  explicit SimpleThread(const std::string& name_prefix);
-  SimpleThread(const std::string& name_prefix, const Options& options);
+  // Every thread has a name, which is a display string to identify the thread.
+  // The thread will not be created until Start() is called.
+  explicit SimpleThread(const std::string& name);
+  SimpleThread(const std::string& name, const Options& options);
+
+  SimpleThread(const SimpleThread&) = delete;
+  SimpleThread& operator=(const SimpleThread&) = delete;
 
   ~SimpleThread() override;
 
@@ -118,7 +124,7 @@
   bool HasBeenStarted();
 
   // Returns True if Join() has ever been called.
-  bool HasBeenJoined() { return joined_; }
+  bool HasBeenJoined() const { return joined_; }
 
   // Returns true if Start() or StartAsync() has been called.
   bool HasStartBeenAttempted() { return start_called_; }
@@ -139,8 +145,7 @@
   // has been initialized before this is called.
   virtual void BeforeJoin() {}
 
-  const std::string name_prefix_;
-  std::string name_;
+  const std::string name_;
   const Options options_;
   PlatformThreadHandle thread_;  // PlatformThread handle, reset after Join.
   WaitableEvent event_;          // Signaled if Start() was ever called.
@@ -148,8 +153,6 @@
   bool joined_ = false;                      // True if Join has been called.
   // Set to true when the platform-thread creation has started.
   bool start_called_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(SimpleThread);
 };
 
 // A SimpleThread which delegates Run() to its Delegate. Non-joinable
@@ -171,13 +174,14 @@
                        const std::string& name_prefix,
                        const Options& options);
 
+  DelegateSimpleThread(const DelegateSimpleThread&) = delete;
+  DelegateSimpleThread& operator=(const DelegateSimpleThread&) = delete;
+
   ~DelegateSimpleThread() override;
   void Run() override;
 
  private:
-  Delegate* delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(DelegateSimpleThread);
+  raw_ptr<Delegate> delegate_;
 };
 
 // DelegateSimpleThreadPool allows you to start up a fixed number of threads,
@@ -194,7 +198,11 @@
  public:
   typedef DelegateSimpleThread::Delegate Delegate;
 
-  DelegateSimpleThreadPool(const std::string& name_prefix, int num_threads);
+  DelegateSimpleThreadPool(const std::string& name_prefix, size_t num_threads);
+
+  DelegateSimpleThreadPool(const DelegateSimpleThreadPool&) = delete;
+  DelegateSimpleThreadPool& operator=(const DelegateSimpleThreadPool&) = delete;
+
   ~DelegateSimpleThreadPool() override;
 
   // Start up all of the underlying threads, and start processing work if we
@@ -207,23 +215,18 @@
 
   // It is safe to AddWork() any time, before or after Start().
   // Delegate* should always be a valid pointer, NULL is reserved internally.
-  void AddWork(Delegate* work, int repeat_count);
-  void AddWork(Delegate* work) {
-    AddWork(work, 1);
-  }
+  void AddWork(Delegate* work, size_t repeat_count = 1);
 
   // We implement the Delegate interface, for running our internal threads.
   void Run() override;
 
  private:
   const std::string name_prefix_;
-  int num_threads_;
+  size_t num_threads_;
   std::vector<DelegateSimpleThread*> threads_;
   base::queue<Delegate*> delegates_;
   base::Lock lock_;            // Locks delegates_
   WaitableEvent dry_;    // Not signaled when there is no work to do.
-
-  DISALLOW_COPY_AND_ASSIGN(DelegateSimpleThreadPool);
 };
 
 }  // namespace base
diff --git a/base/threading/simple_thread_unittest.cc b/base/threading/simple_thread_unittest.cc
index 4e618f9..ead6f8d 100644
--- a/base/threading/simple_thread_unittest.cc
+++ b/base/threading/simple_thread_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -6,6 +6,7 @@
 
 #include "base/atomic_sequence_num.h"
 #include "base/memory/ptr_util.h"
+#include "base/memory/raw_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/gtest_util.h"
@@ -19,15 +20,17 @@
 class SetIntRunner : public DelegateSimpleThread::Delegate {
  public:
   SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { }
+
+  SetIntRunner(const SetIntRunner&) = delete;
+  SetIntRunner& operator=(const SetIntRunner&) = delete;
+
   ~SetIntRunner() override = default;
 
  private:
   void Run() override { *ptr_ = val_; }
 
-  int* ptr_;
+  raw_ptr<int> ptr_;
   int val_;
-
-  DISALLOW_COPY_AND_ASSIGN(SetIntRunner);
 };
 
 // Signals |started_| when Run() is invoked and waits until |released_| is
@@ -43,6 +46,9 @@
         done_(WaitableEvent::ResetPolicy::MANUAL,
               WaitableEvent::InitialState::NOT_SIGNALED) {}
 
+  ControlledRunner(const ControlledRunner&) = delete;
+  ControlledRunner& operator=(const ControlledRunner&) = delete;
+
   ~ControlledRunner() override { ReleaseAndWaitUntilDone(); }
 
   void WaitUntilStarted() { started_.Wait(); }
@@ -62,13 +68,15 @@
   WaitableEvent started_;
   WaitableEvent released_;
   WaitableEvent done_;
-
-  DISALLOW_COPY_AND_ASSIGN(ControlledRunner);
 };
 
 class WaitEventRunner : public DelegateSimpleThread::Delegate {
  public:
   explicit WaitEventRunner(WaitableEvent* event) : event_(event) { }
+
+  WaitEventRunner(const WaitEventRunner&) = delete;
+  WaitEventRunner& operator=(const WaitEventRunner&) = delete;
+
   ~WaitEventRunner() override = default;
 
  private:
@@ -78,21 +86,20 @@
     EXPECT_TRUE(event_->IsSignaled());
   }
 
-  WaitableEvent* event_;
-
-  DISALLOW_COPY_AND_ASSIGN(WaitEventRunner);
+  raw_ptr<WaitableEvent> event_;
 };
 
 class SeqRunner : public DelegateSimpleThread::Delegate {
  public:
   explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { }
 
+  SeqRunner(const SeqRunner&) = delete;
+  SeqRunner& operator=(const SeqRunner&) = delete;
+
  private:
   void Run() override { seq_->GetNext(); }
 
-  AtomicSequenceNumber* seq_;
-
-  DISALLOW_COPY_AND_ASSIGN(SeqRunner);
+  raw_ptr<AtomicSequenceNumber> seq_;
 };
 
 // We count up on a sequence number, firing on the event when we've hit our
@@ -104,6 +111,9 @@
                    int total, WaitableEvent* event)
       : seq_(seq), total_(total), event_(event) { }
 
+  VerifyPoolRunner(const VerifyPoolRunner&) = delete;
+  VerifyPoolRunner& operator=(const VerifyPoolRunner&) = delete;
+
  private:
   void Run() override {
     if (seq_->GetNext() == total_) {
@@ -113,11 +123,9 @@
     }
   }
 
-  AtomicSequenceNumber* seq_;
+  raw_ptr<AtomicSequenceNumber> seq_;
   int total_;
-  WaitableEvent* event_;
-
-  DISALLOW_COPY_AND_ASSIGN(VerifyPoolRunner);
+  raw_ptr<WaitableEvent> event_;
 };
 
 }  // namespace
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
index bbaabea..716a2a4 100644
--- a/base/threading/thread.cc
+++ b/base/threading/thread.cc
@@ -1,39 +1,172 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/thread.h"
 
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/lazy_instance.h"
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "base/dcheck_is_on.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/message_loop/message_pump.h"
 #include "base/run_loop.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/task/sequence_manager/sequence_manager.h"
+#include "base/task/current_thread.h"
+#include "base/task/sequence_manager/sequence_manager_impl.h"
+#include "base/task/sequence_manager/task_queue.h"
+#include "base/task/single_thread_task_runner.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "base/threading/thread_id_name_manager.h"
-#include "base/threading/thread_local.h"
 #include "base/threading/thread_restrictions.h"
+#include "base/types/pass_key.h"
 #include "build/build_config.h"
+#include "third_party/abseil-cpp/absl/base/attributes.h"
 
-#if defined(OS_POSIX) && !defined(OS_NACL)
+#if defined(STARBOARD)
+#include <pthread.h>
+
+#include "base/check_op.h"
+#include "starboard/thread.h"
+#else
+#if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
 #include "base/files/file_descriptor_watcher_posix.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #endif
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include "base/win/scoped_com_initializer.h"
 #endif
+#endif
 
 namespace base {
 
+#if DCHECK_IS_ON()
+namespace {
+
+#if defined(STARBOARD)
+ABSL_CONST_INIT pthread_once_t s_once_flag = PTHREAD_ONCE_INIT;
+ABSL_CONST_INIT pthread_key_t s_thread_local_key = 0;
+
+void InitThreadLocalKey() {
+  int res = pthread_key_create(&s_thread_local_key , NULL);
+  DCHECK(res == 0);
+}
+
+void EnsureThreadLocalKeyInited() {
+  pthread_once(&s_once_flag, InitThreadLocalKey);
+}
+
+bool GetWasQuitProperly() {
+  EnsureThreadLocalKeyInited();
+  void* was_quit_properly = pthread_getspecific(s_thread_local_key);
+  return !!was_quit_properly ? reinterpret_cast<intptr_t>(was_quit_properly) != 0 : false;
+}
+#else
+// We use this thread-local variable to record whether or not a thread exited
+// because its Stop method was called.  This allows us to catch cases where
+// MessageLoop::QuitWhenIdle() is called directly, which is unexpected when
+// using a Thread to setup and run a MessageLoop.
+ABSL_CONST_INIT thread_local bool was_quit_properly = false;
+#endif
+
+}  // namespace
+#endif
+
+namespace internal {
+
+class SequenceManagerThreadDelegate : public Thread::Delegate {
+ public:
+  explicit SequenceManagerThreadDelegate(
+      MessagePumpType message_pump_type,
+      OnceCallback<std::unique_ptr<MessagePump>()> message_pump_factory)
+      : sequence_manager_(
+            sequence_manager::internal::CreateUnboundSequenceManagerImpl(
+                PassKey<base::internal::SequenceManagerThreadDelegate>(),
+                sequence_manager::SequenceManager::Settings::Builder()
+                    .SetMessagePumpType(message_pump_type)
+                    .Build())),
+        default_task_queue_(sequence_manager_->CreateTaskQueue(
+            sequence_manager::TaskQueue::Spec(
+                sequence_manager::QueueName::DEFAULT_TQ))),
+        message_pump_factory_(std::move(message_pump_factory)) {
+    sequence_manager_->SetDefaultTaskRunner(default_task_queue_->task_runner());
+  }
+
+  ~SequenceManagerThreadDelegate() override = default;
+
+  scoped_refptr<SingleThreadTaskRunner> GetDefaultTaskRunner() override {
+    // Surprisingly this might not be default_task_queue_->task_runner() which
+    // we set in the constructor. The Thread::Init() method could create a
+    // SequenceManager on top of the current one and call
+    // SequenceManager::SetDefaultTaskRunner which would propagate the new
+    // TaskRunner down to our SequenceManager. Turns out, code actually relies
+    // on this and somehow relies on
+    // SequenceManagerThreadDelegate::GetDefaultTaskRunner returning this new
+    // TaskRunner. So instead of returning default_task_queue_->task_runner() we
+    // need to query the SequenceManager for it.
+    // The underlying problem here is that Subclasses of Thread can do crazy
+    // stuff in Init() but they are not really in control of what happens in the
+    // Thread::Delegate, as this is passed in on calling StartWithOptions which
+    // could happen far away from where the Thread is created. We should
+    // consider getting rid of StartWithOptions, and pass them as a constructor
+    // argument instead.
+    return sequence_manager_->GetTaskRunner();
+  }
+
+  void BindToCurrentThread(TimerSlack timer_slack) override {
+    sequence_manager_->BindToMessagePump(
+        std::move(message_pump_factory_).Run());
+    sequence_manager_->SetTimerSlack(timer_slack);
+  }
+
+ private:
+  std::unique_ptr<sequence_manager::internal::SequenceManagerImpl>
+      sequence_manager_;
+  scoped_refptr<sequence_manager::TaskQueue> default_task_queue_;
+  OnceCallback<std::unique_ptr<MessagePump>()> message_pump_factory_;
+};
+
+}  // namespace internal
+
 Thread::Options::Options() = default;
 
-Thread::Options::Options(MessageLoop::Type type, size_t size)
-    : message_loop_type(type), stack_size(size) {}
+Thread::Options::Options(MessagePumpType type, size_t size)
+    : message_pump_type(type), stack_size(size) {}
 
-Thread::Options::Options(const Options& other) = default;
+Thread::Options::Options(ThreadType thread_type) : thread_type(thread_type) {}
+
+Thread::Options::Options(Options&& other)
+    : message_pump_type(std::move(other.message_pump_type)),
+      delegate(std::move(other.delegate)),
+      timer_slack(std::move(other.timer_slack)),
+      message_pump_factory(std::move(other.message_pump_factory)),
+      stack_size(std::move(other.stack_size)),
+      thread_type(std::move(other.thread_type)),
+      joinable(std::move(other.joinable)) {
+  other.moved_from = true;
+}
+
+Thread::Options& Thread::Options::operator=(Thread::Options&& other) {
+  DCHECK_NE(this, &other);
+
+  message_pump_type = std::move(other.message_pump_type);
+  delegate = std::move(other.delegate);
+  timer_slack = std::move(other.timer_slack);
+  message_pump_factory = std::move(other.message_pump_factory);
+  stack_size = std::move(other.stack_size);
+  thread_type = std::move(other.thread_type);
+  joinable = std::move(other.joinable);
+  other.moved_from = true;
+
+  return *this;
+}
 
 Thread::Options::~Options() = default;
 
@@ -41,9 +174,6 @@
     : id_event_(WaitableEvent::ResetPolicy::MANUAL,
                 WaitableEvent::InitialState::NOT_SIGNALED),
       name_(name),
-#ifndef NDEBUG
-      was_quit_properly_(false),
-#endif
       start_event_(WaitableEvent::ResetPolicy::MANUAL,
                    WaitableEvent::InitialState::NOT_SIGNALED) {
   // Only bind the sequence on Start(): the state is constant between
@@ -61,22 +191,23 @@
   DCHECK(owning_sequence_checker_.CalledOnValidSequence());
 
   Options options;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   if (com_status_ == STA)
-    options.message_loop_type = MessageLoop::TYPE_UI;
+    options.message_pump_type = MessagePumpType::UI;
 #endif
-  return StartWithOptions(options);
+  return StartWithOptions(std::move(options));
 }
 
-bool Thread::StartWithOptions(const Options& options) {
+bool Thread::StartWithOptions(Options options) {
+  DCHECK(options.IsValid());
   DCHECK(owning_sequence_checker_.CalledOnValidSequence());
-  DCHECK(!message_loop_);
+  DCHECK(!delegate_);
   DCHECK(!IsRunning());
   DCHECK(!stopping_) << "Starting a non-joinable thread a second time? That's "
                      << "not allowed!";
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   DCHECK((com_status_ != STA) ||
-      (options.message_loop_type == MessageLoop::TYPE_UI));
+         (options.message_pump_type == MessagePumpType::UI));
 #endif
 
   // Reset |id_| here to support restarting the thread.
@@ -85,47 +216,43 @@
 
   SetThreadWasQuitProperly(false);
 
-  MessageLoop::Type type = options.message_loop_type;
-  if (!options.message_pump_factory.is_null())
-    type = MessageLoop::TYPE_CUSTOM;
+  timer_slack_ = options.timer_slack;
 
-  message_loop_timer_slack_ = options.timer_slack;
-  std::unique_ptr<MessageLoop> message_loop_owned =
-      MessageLoop::CreateUnbound(type, options.message_pump_factory);
-  message_loop_ = message_loop_owned.get();
-  start_event_.Reset();
-
-  if (options.on_sequence_manager_created) {
-    sequence_manager_ =
-        sequence_manager::CreateUnboundSequenceManager(message_loop_);
-    options.on_sequence_manager_created.Run(sequence_manager_.get());
+  if (options.delegate) {
+    DCHECK(!options.message_pump_factory);
+    delegate_ = std::move(options.delegate);
+  } else if (options.message_pump_factory) {
+    delegate_ = std::make_unique<internal::SequenceManagerThreadDelegate>(
+        MessagePumpType::CUSTOM, options.message_pump_factory);
+  } else {
+    delegate_ = std::make_unique<internal::SequenceManagerThreadDelegate>(
+        options.message_pump_type,
+        BindOnce([](MessagePumpType type) { return MessagePump::Create(type); },
+                 options.message_pump_type));
   }
 
+  start_event_.Reset();
+
   // Hold |thread_lock_| while starting the new thread to synchronize with
   // Stop() while it's not guaranteed to be sequenced (until crbug/629139 is
   // fixed).
   {
     AutoLock lock(thread_lock_);
-    bool success =
-        options.joinable
-            ? PlatformThread::CreateWithPriority(options.stack_size, this,
-                                                 &thread_, options.priority)
-            : PlatformThread::CreateNonJoinableWithPriority(
-                  options.stack_size, this, options.priority);
+    bool success = options.joinable
+                       ? PlatformThread::CreateWithType(
+                             options.stack_size, this, &thread_,
+                             options.thread_type, options.message_pump_type)
+                       : PlatformThread::CreateNonJoinableWithType(
+                             options.stack_size, this, options.thread_type,
+                             options.message_pump_type);
     if (!success) {
       DLOG(ERROR) << "failed to create thread";
-      message_loop_ = nullptr;
       return false;
     }
   }
 
   joinable_ = options.joinable;
 
-  // The ownership of |message_loop_| is managed by the newly created thread
-  // within the ThreadMain.
-  ignore_result(message_loop_owned.release());
-
-  DCHECK(message_loop_);
   return true;
 }
 
@@ -140,16 +267,17 @@
 
 bool Thread::WaitUntilThreadStarted() const {
   DCHECK(owning_sequence_checker_.CalledOnValidSequence());
-  if (!message_loop_)
+  if (!delegate_)
     return false;
-  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  // https://crbug.com/918039
+  base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
   start_event_.Wait();
   return true;
 }
 
 void Thread::FlushForTesting() {
   DCHECK(owning_sequence_checker_.CalledOnValidSequence());
-  if (!message_loop_)
+  if (!delegate_)
     return;
 
   WaitableEvent done(WaitableEvent::ResetPolicy::AUTOMATIC,
@@ -176,15 +304,14 @@
 
   // Wait for the thread to exit.
   //
-  // TODO(darin): Unfortunately, we need to keep |message_loop_| around until
-  // the thread exits.  Some consumers are abusing the API.  Make them stop.
-  //
+  // TODO(darin): Unfortunately, we need to keep |delegate_| around
+  // until the thread exits. Some consumers are abusing the API. Make them stop.
   PlatformThread::Join(thread_);
   thread_ = base::PlatformThreadHandle();
 
-  // The thread should nullify |message_loop_| on exit (note: Join() adds an
-  // implicit memory barrier and no lock is thus required for this check).
-  DCHECK(!message_loop_);
+  // The thread should release |delegate_| on exit (note: Join() adds
+  // an implicit memory barrier and no lock is thus required for this check).
+  DCHECK(!delegate_);
 
   stopping_ = false;
 }
@@ -194,20 +321,11 @@
   // enable this check.
   // DCHECK(owning_sequence_checker_.CalledOnValidSequence());
 
-  if (stopping_ || !message_loop_)
+  if (stopping_ || !delegate_)
     return;
 
   stopping_ = true;
 
-  if (using_external_message_loop_) {
-    // Setting |stopping_| to true above should have been sufficient for this
-    // thread to be considered "stopped" per it having never set its |running_|
-    // bit by lack of its own ThreadMain.
-    DCHECK(!IsRunning());
-    message_loop_ = nullptr;
-    return;
-  }
-
   task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&Thread::ThreadQuitHelper, Unretained(this)));
 }
@@ -218,27 +336,24 @@
 }
 
 PlatformThreadId Thread::GetThreadId() const {
-  // If the thread is created but not started yet, wait for |id_| being ready.
-  base::ThreadRestrictions::ScopedAllowWait allow_wait;
-  id_event_.Wait();
+  if (!id_event_.IsSignaled()) {
+    // If the thread is created but not started yet, wait for |id_| being ready.
+    base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
+    id_event_.Wait();
+  }
   return id_;
 }
 
-PlatformThreadHandle Thread::GetThreadHandle() const {
-  AutoLock lock(thread_lock_);
-  return thread_;
-}
-
 bool Thread::IsRunning() const {
   // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and
   // enable this check.
   // DCHECK(owning_sequence_checker_.CalledOnValidSequence());
 
-  // If the thread's already started (i.e. |message_loop_| is non-null) and not
-  // yet requested to stop (i.e. |stopping_| is false) we can just return true.
-  // (Note that |stopping_| is touched only on the same sequence that starts /
-  // started the new thread so we need no locking here.)
-  if (message_loop_ && !stopping_)
+  // If the thread's already started (i.e. |delegate_| is non-null) and
+  // not yet requested to stop (i.e. |stopping_| is false) we can just return
+  // true. (Note that |stopping_| is touched only on the same sequence that
+  // starts / started the new thread so we need no locking here.)
+  if (delegate_ && !stopping_)
     return true;
   // Otherwise check the |running_| flag, which is set to true by the new thread
   // only while it is inside Run().
@@ -256,33 +371,29 @@
 
 // static
 void Thread::SetThreadWasQuitProperly(bool flag) {
-#ifndef NDEBUG
-  was_quit_properly_ = flag;
+#if DCHECK_IS_ON()
+#if defined(STARBOARD)
+  EnsureThreadLocalKeyInited();
+  pthread_setspecific(s_thread_local_key, reinterpret_cast<void*>(static_cast<intptr_t>(flag)));
+#else
+  was_quit_properly = flag;
+#endif
 #endif
 }
 
 // static
 bool Thread::GetThreadWasQuitProperly() {
-#ifndef NDEBUG
-  return was_quit_properly_;
+#if DCHECK_IS_ON()
+#if defined(STARBOARD)
+  return GetWasQuitProperly();
+#else
+  return was_quit_properly;
+#endif
 #else
   return true;
 #endif
 }
 
-void Thread::SetMessageLoop(MessageLoop* message_loop) {
-  DCHECK(owning_sequence_checker_.CalledOnValidSequence());
-  DCHECK(message_loop);
-
-  // Setting |message_loop_| should suffice for this thread to be considered
-  // as "running", until Stop() is invoked.
-  DCHECK(!IsRunning());
-  message_loop_ = message_loop;
-  DCHECK(IsRunning());
-
-  using_external_message_loop_ = true;
-}
-
 void Thread::ThreadMain() {
   // First, make GetThreadId() available to avoid deadlocks. It could be called
   // any place in the following thread initialization code.
@@ -299,42 +410,32 @@
   PlatformThread::SetName(name_.c_str());
   ANNOTATE_THREAD_NAME(name_.c_str());  // Tell the name to race detector.
 
-  if (sequence_manager_) {
-    // Bind the SequenceManager before binding the MessageLoop, so that the
-    // TaskQueues are bound before the MessageLoop. This is required as one of
-    // the TaskQueues may have already replaced the MessageLoop's TaskRunner,
-    // and the MessageLoop's TaskRunner needs to be associated with this thread
-    // when we call MessageLoop::BindToCurrentThread().
-    sequence_manager_->BindToCurrentThread();
-  }
-
   // Lazily initialize the |message_loop| so that it can run on this thread.
-  DCHECK(message_loop_);
-  std::unique_ptr<MessageLoop> message_loop(message_loop_);
-  message_loop_->BindToCurrentThread();
-  message_loop_->SetTimerSlack(message_loop_timer_slack_);
-
-  if (sequence_manager_) {
-    sequence_manager_->CompleteInitializationOnBoundThread();
-  }
-
-#if defined(OS_POSIX) && !defined(OS_NACL)
+  DCHECK(delegate_);
+  // This binds CurrentThread and SingleThreadTaskRunner::CurrentDefaultHandle.
+  delegate_->BindToCurrentThread(timer_slack_);
+  DCHECK(CurrentThread::Get());
+  DCHECK(SingleThreadTaskRunner::HasCurrentDefault());
+#if !defined(STARBOARD)
+#if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
   // Allow threads running a MessageLoopForIO to use FileDescriptorWatcher API.
   std::unique_ptr<FileDescriptorWatcher> file_descriptor_watcher;
-  if (MessageLoopForIO::IsCurrent()) {
-    file_descriptor_watcher.reset(new FileDescriptorWatcher(
-        static_cast<MessageLoopForIO*>(message_loop_)));
+  if (CurrentIOThread::IsSet()) {
+    file_descriptor_watcher = std::make_unique<FileDescriptorWatcher>(
+        delegate_->GetDefaultTaskRunner());
   }
-#endif
+#endif  // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)) || BUILDFLAG(IS_FUCHSIA)
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   std::unique_ptr<win::ScopedCOMInitializer> com_initializer;
   if (com_status_ != NONE) {
-    com_initializer.reset((com_status_ == STA) ?
-        new win::ScopedCOMInitializer() :
-        new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
+    com_initializer.reset(
+        (com_status_ == STA)
+            ? new win::ScopedCOMInitializer()
+            : new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
   }
 #endif
+#endif
 
   // Let the thread do extra initialization.
   Init();
@@ -358,22 +459,15 @@
   // Let the thread do extra cleanup.
   CleanUp();
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   com_initializer.reset();
 #endif
 
-  sequence_manager_.reset();
-
-  if (message_loop->type() != MessageLoop::TYPE_CUSTOM) {
-    // Assert that RunLoop::QuitWhenIdle was called by ThreadQuitHelper. Don't
-    // check for custom message pumps, because their shutdown might not allow
-    // this.
-    DCHECK(GetThreadWasQuitProperly());
-  }
+  DCHECK(GetThreadWasQuitProperly());
 
   // We can't receive messages anymore.
   // (The message loop is destructed at the end of this block)
-  message_loop_ = nullptr;
+  delegate_.reset();
   run_loop_ = nullptr;
 }
 
diff --git a/base/threading/thread.h b/base/threading/thread.h
index a27dc2d..06dd702 100644
--- a/base/threading/thread.h
+++ b/base/threading/thread.h
@@ -1,42 +1,36 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef BASE_THREADING_THREAD_H_
 #define BASE_THREADING_THREAD_H_
 
+#include <stddef.h>
+
 #include <memory>
 #include <string>
 
 #include "base/base_export.h"
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/check.h"
+#include "base/functional/callback.h"
+#include "base/memory/raw_ptr_exclusion.h"
+#include "base/message_loop/message_pump_type.h"
 #include "base/message_loop/timer_slack.h"
 #include "base/sequence_checker.h"
-#include "base/single_thread_task_runner.h"
 #include "base/synchronization/atomic_flag.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/task/single_thread_task_runner.h"
 #include "base/threading/platform_thread.h"
 #include "build/build_config.h"
-#include "starboard/types.h"
 
 namespace base {
 
 class MessagePump;
 class RunLoop;
 
-#if defined(STARBOARD)
-const size_t kUnitTestStackSize = 1024 * 1024;
-#endif
-
-namespace sequence_manager {
-class SequenceManager;
-}  // namespace sequence_manager
-
 // IMPORTANT: Instead of creating a base::Thread, consider using
-// base::Create(Sequenced|SingleThread)TaskRunnerWithTraits().
+// base::ThreadPool::Create(Sequenced|SingleThread)TaskRunner().
 //
 // A simple thread abstraction that establishes a MessageLoop on a new thread.
 // The consumer uses the MessageLoop of the thread to cause code to execute on
@@ -50,7 +44,7 @@
 //
 //  (1) Thread::CleanUp()
 //  (2) MessageLoop::~MessageLoop
-//  (3.b) MessageLoopCurrent::DestructionObserver::WillDestroyCurrentMessageLoop
+//  (3.b) CurrentThread::DestructionObserver::WillDestroyCurrentMessageLoop
 //
 // This API is not thread-safe: unless indicated otherwise its methods are only
 // valid from the owning sequence (which is the one from which Start() is
@@ -65,42 +59,54 @@
 // Thread object (including ~Thread()).
 class BASE_EXPORT Thread : PlatformThread::Delegate {
  public:
+  class BASE_EXPORT Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    virtual scoped_refptr<SingleThreadTaskRunner> GetDefaultTaskRunner() = 0;
+
+    // Binds a RunLoop::Delegate and task runner CurrentDefaultHandle to the
+    // thread. The underlying MessagePump will have its |timer_slack| set to the
+    // specified amount.
+    virtual void BindToCurrentThread(TimerSlack timer_slack) = 0;
+  };
+
   struct BASE_EXPORT Options {
-    typedef Callback<std::unique_ptr<MessagePump>()> MessagePumpFactory;
-    using SequenceManagerCreatedCallback =
-        RepeatingCallback<void(sequence_manager::SequenceManager*)>;
+    using MessagePumpFactory =
+        RepeatingCallback<std::unique_ptr<MessagePump>()>;
 
     Options();
-    Options(MessageLoop::Type type, size_t size);
-    Options(const Options& other);
+    Options(MessagePumpType type, size_t size);
+    explicit Options(ThreadType thread_type);
+    Options(Options&& other);
+    Options& operator=(Options&& other);
     ~Options();
 
-    // Specifies the type of message loop that will be allocated on the thread.
+    // Specifies the type of message pump that will be allocated on the thread.
     // This is ignored if message_pump_factory.is_null() is false.
-    MessageLoop::Type message_loop_type = MessageLoop::TYPE_DEFAULT;
+    MessagePumpType message_pump_type = MessagePumpType::DEFAULT;
+
+    // An unbound Delegate that will be bound to the thread. Ownership
+    // of |delegate| will be transferred to the thread.
+    std::unique_ptr<Delegate> delegate = nullptr;
 
     // Specifies timer slack for thread message loop.
     TimerSlack timer_slack = TIMER_SLACK_NONE;
 
     // Used to create the MessagePump for the MessageLoop. The callback is Run()
     // on the thread. If message_pump_factory.is_null(), then a MessagePump
-    // appropriate for |message_loop_type| is created. Setting this forces the
-    // MessageLoop::Type to TYPE_CUSTOM.
+    // appropriate for |message_pump_type| is created. Setting this forces the
+    // MessagePumpType to TYPE_CUSTOM. This is not compatible with a non-null
+    // |delegate|.
     MessagePumpFactory message_pump_factory;
 
-    // If set, the Thread will create a SequenceManager on the MessageLoop and
-    // execute the provided callback right after it was created. The callback
-    // will be executed on the creator thread before the new Thread is started.
-    // It is typically used to create TaskQueues for the SequenceManager.
-    SequenceManagerCreatedCallback on_sequence_manager_created;
-
     // Specifies the maximum stack size that the thread is allowed to use.
     // This does not necessarily correspond to the thread's initial stack size.
     // A value of 0 indicates that the default maximum should be used.
     size_t stack_size = 0;
 
-    // Specifies the initial thread priority.
-    ThreadPriority priority = ThreadPriority::NORMAL;
+    // Specifies the initial thread type.
+    ThreadType thread_type = ThreadType::kDefault;
 
     // If false, the thread will not be joined on destruction. This is intended
     // for threads that want TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN
@@ -109,20 +115,21 @@
     // TODO(gab): allow non-joinable instances to be deleted without causing
     // user-after-frees (proposal @ https://crbug.com/629139#c14)
     bool joinable = true;
+
+    bool IsValid() const { return !moved_from; }
+
+   private:
+    // Set to true when the object is moved into another. Use to prevent reuse
+    // of a moved-from object.
+    bool moved_from = false;
   };
 
   // Constructor.
   // name is a display string to identify the thread.
   explicit Thread(const std::string& name);
 
-#if !defined(BASE_DONT_ENFORCE_THREAD_NAME_LENGTH)
-  // Constructor, checks length of name literal at compile-time
-  template <size_t N>
-  explicit Thread(char const (&name)[N]) : Thread(std::string(name)) {
-    // 16 is common to Linux and other Starboard platforms
-    static_assert(N <= 16, "Thread name too long, max 16");
-  }
-#endif
+  Thread(const Thread&) = delete;
+  Thread& operator=(const Thread&) = delete;
 
   // Destroys the thread, stopping it if necessary.
   //
@@ -134,14 +141,14 @@
   // before it is destructed.
   ~Thread() override;
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   // Causes the thread to initialize COM.  This must be called before calling
   // Start() or StartWithOptions().  If |use_mta| is false, the thread is also
   // started with a TYPE_UI message loop.  It is an error to call
   // init_com_with_mta(false) and then StartWithOptions() with any message loop
   // type other than TYPE_UI.
   void init_com_with_mta(bool use_mta) {
-    DCHECK(!message_loop_);
+    DCHECK(!delegate_);
     com_status_ = use_mta ? MTA : STA;
   }
 #endif
@@ -161,7 +168,7 @@
   // Note: This function can't be called on Windows with the loader lock held;
   // i.e. during a DllMain, global object construction or destruction, atexit()
   // callback.
-  bool StartWithOptions(const Options& options);
+  bool StartWithOptions(Options options);
 
   // Starts the thread and wait for the thread to start and run initialization
   // before returning. It's same as calling Start() and then
@@ -213,34 +220,6 @@
   // relationship with this one.
   void DetachFromSequence();
 
-  // Returns the message loop for this thread.  Use the MessageLoop's
-  // PostTask methods to execute code on the thread.  This only returns
-  // non-null after a successful call to Start.  After Stop has been called,
-  // this will return nullptr.
-  //
-  // NOTE: You must not call this MessageLoop's Quit method directly.  Use
-  // the Thread's Stop method instead.
-  //
-  // In addition to this Thread's owning sequence, this can also safely be
-  // called from the underlying thread itself.
-  MessageLoop* message_loop() const {
-    // This class doesn't provide synchronization around |message_loop_| and as
-    // such only the owner should access it (and the underlying thread which
-    // never sees it before it's set). In practice, many callers are coming from
-    // unrelated threads but provide their own implicit (e.g. memory barriers
-    // from task posting) or explicit (e.g. locks) synchronization making the
-    // access of |message_loop_| safe... Changing all of those callers is
-    // unfeasible; instead verify that they can reliably see
-    // |message_loop_ != nullptr| without synchronization as a proof that their
-    // external synchronization catches the unsynchronized effects of Start().
-    // TODO(gab): Despite all of the above this test has to be disabled for now
-    // per crbug.com/629139#c6.
-    // DCHECK(owning_sequence_checker_.CalledOnValidSequence() ||
-    //        (id_event_.IsSignaled() && id_ == PlatformThread::CurrentId()) ||
-    //        message_loop_);
-    return message_loop_;
-  }
-
   // Returns a TaskRunner for this thread. Use the TaskRunner's PostTask
   // methods to execute code on the thread. Returns nullptr if the thread is not
   // running (e.g. before Start or after Stop have been called). Callers can
@@ -250,11 +229,20 @@
   // In addition to this Thread's owning sequence, this can also safely be
   // called from the underlying thread itself.
   scoped_refptr<SingleThreadTaskRunner> task_runner() const {
-    // Refer to the DCHECK and comment inside |message_loop()|.
+    // This class doesn't provide synchronization around |message_loop_base_|
+    // and as such only the owner should access it (and the underlying thread
+    // which never sees it before it's set). In practice, many callers are
+    // coming from unrelated threads but provide their own implicit (e.g. memory
+    // barriers from task posting) or explicit (e.g. locks) synchronization
+    // making the access of |message_loop_base_| safe... Changing all of those
+    // callers is unfeasible; instead verify that they can reliably see
+    // |message_loop_base_ != nullptr| without synchronization as a proof that
+    // their external synchronization catches the unsynchronized effects of
+    // Start().
     DCHECK(owning_sequence_checker_.CalledOnValidSequence() ||
            (id_event_.IsSignaled() && id_ == PlatformThread::CurrentId()) ||
-           message_loop_);
-    return message_loop_ ? message_loop_->task_runner() : nullptr;
+           delegate_);
+    return delegate_ ? delegate_->GetDefaultTaskRunner() : nullptr;
   }
 
   // Returns the name of this thread (for display in debugger too).
@@ -269,15 +257,6 @@
   // This method is thread-safe.
   PlatformThreadId GetThreadId() const;
 
-  // Returns the current thread handle. If called before Start*() returns or
-  // after Stop() returns, an empty thread handle will be returned.
-  //
-  // This method is thread-safe.
-  //
-  // TODO(robliao): Remove this when it no longer needs to be temporarily
-  // exposed for http://crbug.com/717380.
-  PlatformThreadHandle GetThreadHandle() const;
-
   // Returns true if the thread has been started, and not yet stopped.
   bool IsRunning() const;
 
@@ -291,21 +270,15 @@
   // Called just after the message loop ends
   virtual void CleanUp() {}
 
-  void SetThreadWasQuitProperly(bool flag);
-  bool GetThreadWasQuitProperly();
-
-  // Bind this Thread to an existing MessageLoop instead of starting a new one.
-  // TODO(gab): Remove this after ios/ has undergone the same surgery as
-  // BrowserThreadImpl (ref.
-  // https://chromium-review.googlesource.com/c/chromium/src/+/969104).
-  void SetMessageLoop(MessageLoop* message_loop);
-
-  bool using_external_message_loop() const {
-    return using_external_message_loop_;
-  }
+  static void SetThreadWasQuitProperly(bool flag);
+  static bool GetThreadWasQuitProperly();
 
  private:
-#if defined(OS_WIN)
+  // Friends for message_loop() access:
+  friend class MessageLoopTaskRunnerTest;
+  friend class ScheduleWorkTest;
+
+#if BUILDFLAG(IS_WIN)
   enum ComStatus {
     NONE,
     STA,
@@ -318,7 +291,7 @@
 
   void ThreadQuitHelper();
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   // Whether this thread needs to initialize COM, and if so, in what mode.
   ComStatus com_status_ = NONE;
 #endif
@@ -346,44 +319,26 @@
   // Protects |id_| which must only be read while it's signaled.
   mutable WaitableEvent id_event_;
 
-  // The thread's MessageLoop and RunLoop. Valid only while the thread is alive.
-  // Set by the created thread.
-  MessageLoop* message_loop_ = nullptr;
-  RunLoop* run_loop_ = nullptr;
+  // The thread's Delegate and RunLoop are valid only while the thread is
+  // alive. Set by the created thread.
+  std::unique_ptr<Delegate> delegate_;
+  // This field is not a raw_ptr<> because it was filtered by the rewriter for:
+  // #union
+  RAW_PTR_EXCLUSION RunLoop* run_loop_ = nullptr;
 
-  // True only if |message_loop_| was externally provided by |SetMessageLoop()|
-  // in which case this Thread has no underlying |thread_| and should merely
-  // drop |message_loop_| on Stop(). In that event, this remains true after
-  // Stop() was invoked so that subclasses can use this state to build their own
-  // cleanup logic as required.
-  bool using_external_message_loop_ = false;
-
-  // Optionally stores a SequenceManager that manages Tasks on the MessageLoop.
-  std::unique_ptr<sequence_manager::SequenceManager> sequence_manager_;
-
-  // Stores Options::timer_slack_ until the message loop has been bound to
+  // Stores Options::timer_slack_ until the sequence manager has been bound to
   // a thread.
-  TimerSlack message_loop_timer_slack_ = TIMER_SLACK_NONE;
+  TimerSlack timer_slack_ = TIMER_SLACK_NONE;
 
   // The name of the thread.  Used for debugging purposes.
   const std::string name_;
 
-#ifndef NDEBUG
-  // We use this member variable to record whether or not a thread exited
-  // because its Stop method was called.  This allows us to catch cases where
-  // MessageLoop::QuitWhenIdle() is called directly, which is unexpected when
-  // using a Thread to setup and run a MessageLoop.
-  bool was_quit_properly_;
-#endif
-
   // Signaled when the created thread gets ready to use the message loop.
   mutable WaitableEvent start_event_;
 
   // This class is not thread-safe, use this to verify access from the owning
   // sequence of the Thread.
   SequenceChecker owning_sequence_checker_;
-
-  DISALLOW_COPY_AND_ASSIGN(Thread);
 };
 
 }  // namespace base
diff --git a/base/threading/thread_checker.cc b/base/threading/thread_checker.cc
new file mode 100644
index 0000000..4baec82
--- /dev/null
+++ b/base/threading/thread_checker.cc
@@ -0,0 +1,39 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_checker.h"
+
+#if DCHECK_IS_ON()
+#include <memory>
+#include <ostream>
+
+#include "base/check.h"
+#include "base/debug/stack_trace.h"
+#endif
+
+namespace base {
+
+#if DCHECK_IS_ON()
+ScopedValidateThreadChecker::ScopedValidateThreadChecker(
+    const ThreadChecker& checker) {
+  std::unique_ptr<debug::StackTrace> bound_at;
+  DCHECK(checker.CalledOnValidThread(&bound_at))
+      << (bound_at ? "\nWas attached to thread at:\n" + bound_at->ToString()
+                   : "");
+}
+
+ScopedValidateThreadChecker::ScopedValidateThreadChecker(
+    const ThreadChecker& checker,
+    const StringPiece& msg) {
+  std::unique_ptr<debug::StackTrace> bound_at;
+  DCHECK(checker.CalledOnValidThread(&bound_at))
+      << msg
+      << (bound_at ? "\nWas attached to thread at:\n" + bound_at->ToString()
+                   : "");
+}
+
+ScopedValidateThreadChecker::~ScopedValidateThreadChecker() = default;
+#endif  // DCHECK_IS_ON()
+
+}  // namespace base
diff --git a/base/threading/thread_checker.h b/base/threading/thread_checker.h
index 6799e25..3c1ff49 100644
--- a/base/threading/thread_checker.h
+++ b/base/threading/thread_checker.h
@@ -1,16 +1,19 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef BASE_THREADING_THREAD_CHECKER_H_
 #define BASE_THREADING_THREAD_CHECKER_H_
 
-#include "base/compiler_specific.h"
-#include "base/logging.h"
+#include "base/base_export.h"
+#include "base/dcheck_is_on.h"
+#include "base/strings/string_piece.h"
+#include "base/thread_annotations.h"
 #include "base/threading/thread_checker_impl.h"
 
 // ThreadChecker is a helper class used to help verify that some methods of a
-// class are called from the same thread (for thread-affinity).
+// class are called from the same thread (for thread-affinity).  It supports
+// thread safety annotations (see base/thread_annotations.h).
 //
 // Use the macros below instead of the ThreadChecker directly so that the unused
 // member doesn't result in an extra byte (four when padded) per instance in
@@ -31,6 +34,12 @@
 // SequencedTaskRunner for ease of scheduling as well as minimizes side-effects
 // if that change is made.
 //
+// Debugging:
+//   If ThreadChecker::EnableStackLogging() is called beforehand, then when
+//   ThreadChecker fails, in addition to crashing with a stack trace of where
+//   the violation occurred, it will also dump a stack trace of where the
+//   checker was bound to a thread.
+//
 // Usage:
 //   class MyClass {
 //    public:
@@ -38,7 +47,7 @@
 //       // It's sometimes useful to detach on construction for objects that are
 //       // constructed in one place and forever after used from another
 //       // thread.
-//       DETACH_FROM_THREAD(my_thread_checker_);
+//       DETACH_FROM_THREAD(thread_checker_);
 //     }
 //
 //     ~MyClass() {
@@ -48,25 +57,40 @@
 //       // knows usage on the associated thread is done. If you're not
 //       // detaching in the constructor, you probably want to explicitly check
 //       // in the destructor.
-//       DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_);
+//       DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 //     }
 //
 //     void MyMethod() {
-//       DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_);
+//       DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 //       ... (do stuff) ...
 //     }
 //
+//     void MyOtherMethod()
+//         VALID_CONTEXT_REQUIRED(thread_checker_) {
+//       foo_ = 42;
+//     }
+//
 //    private:
-//     THREAD_CHECKER(my_thread_checker_);
+//     int foo_ GUARDED_BY_CONTEXT(thread_checker_);
+//
+//     THREAD_CHECKER(thread_checker_);
 //   }
 
+#define THREAD_CHECKER_INTERNAL_CONCAT2(a, b) a##b
+#define THREAD_CHECKER_INTERNAL_CONCAT(a, b) \
+  THREAD_CHECKER_INTERNAL_CONCAT2(a, b)
+#define THREAD_CHECKER_INTERNAL_UID(prefix) \
+  THREAD_CHECKER_INTERNAL_CONCAT(prefix, __LINE__)
+
 #if DCHECK_IS_ON()
 #define THREAD_CHECKER(name) base::ThreadChecker name
-#define DCHECK_CALLED_ON_VALID_THREAD(name) DCHECK((name).CalledOnValidThread())
+#define DCHECK_CALLED_ON_VALID_THREAD(name, ...)                 \
+  base::ScopedValidateThreadChecker THREAD_CHECKER_INTERNAL_UID( \
+      scoped_validate_thread_checker_)(name, ##__VA_ARGS__);
 #define DETACH_FROM_THREAD(name) (name).DetachFromThread()
 #else  // DCHECK_IS_ON()
-#define THREAD_CHECKER(name)
-#define DCHECK_CALLED_ON_VALID_THREAD(name) EAT_STREAM_PARAMETERS
+#define THREAD_CHECKER(name) static_assert(true, "")
+#define DCHECK_CALLED_ON_VALID_THREAD(name, ...) EAT_CHECK_STREAM_PARAMS()
 #define DETACH_FROM_THREAD(name)
 #endif  // DCHECK_IS_ON()
 
@@ -76,20 +100,33 @@
 //
 // Note: You should almost always use the ThreadChecker class (through the above
 // macros) to get the right version for your build configuration.
-class ThreadCheckerDoNothing {
+// Note: This is only a check, not a "lock". It is marked "LOCKABLE" only in
+// order to support thread_annotations.h.
+class LOCKABLE ThreadCheckerDoNothing {
  public:
-  ThreadCheckerDoNothing() = default;
-  bool CalledOnValidThread() const WARN_UNUSED_RESULT { return true; }
-  void DetachFromThread() {}
+  static void EnableStackLogging() {}
 
- private:
-  DISALLOW_COPY_AND_ASSIGN(ThreadCheckerDoNothing);
+  ThreadCheckerDoNothing() = default;
+
+  ThreadCheckerDoNothing(const ThreadCheckerDoNothing&) = delete;
+  ThreadCheckerDoNothing& operator=(const ThreadCheckerDoNothing&) = delete;
+
+  // Moving between matching threads is allowed to help classes with
+  // ThreadCheckers that want a default move-construct/assign.
+  ThreadCheckerDoNothing(ThreadCheckerDoNothing&& other) = default;
+  ThreadCheckerDoNothing& operator=(ThreadCheckerDoNothing&& other) = default;
+
+  [[nodiscard]] bool CalledOnValidThread(
+      std::unique_ptr<void*> = nullptr) const {
+    return true;
+  }
+  void DetachFromThread() {}
 };
 
 // Note that ThreadCheckerImpl::CalledOnValidThread() returns false when called
 // from tasks posted to SingleThreadTaskRunners bound to different sequences,
 // even if the tasks happen to run on the same thread (e.g. two independent
-// SingleThreadTaskRunners on the TaskScheduler that happen to share a thread).
+// SingleThreadTaskRunners on the ThreadPool that happen to share a thread).
 #if DCHECK_IS_ON()
 class ThreadChecker : public ThreadCheckerImpl {
 };
@@ -98,6 +135,23 @@
 };
 #endif  // DCHECK_IS_ON()
 
+#if DCHECK_IS_ON()
+class BASE_EXPORT SCOPED_LOCKABLE ScopedValidateThreadChecker {
+ public:
+  explicit ScopedValidateThreadChecker(const ThreadChecker& checker)
+      EXCLUSIVE_LOCK_FUNCTION(checker);
+  ScopedValidateThreadChecker(const ThreadChecker& checker,
+                              const StringPiece& msg)
+      EXCLUSIVE_LOCK_FUNCTION(checker);
+
+  ScopedValidateThreadChecker(const ScopedValidateThreadChecker&) = delete;
+  ScopedValidateThreadChecker& operator=(const ScopedValidateThreadChecker&) =
+      delete;
+
+  ~ScopedValidateThreadChecker() UNLOCK_FUNCTION();
+};
+#endif
+
 }  // namespace base
 
 #endif  // BASE_THREADING_THREAD_CHECKER_H_
diff --git a/base/threading/thread_checker_impl.cc b/base/threading/thread_checker_impl.cc
index e3bc8be..1d59088 100644
--- a/base/threading/thread_checker_impl.cc
+++ b/base/threading/thread_checker_impl.cc
@@ -1,69 +1,146 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/thread_checker_impl.h"
 
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/check.h"
+#include "base/debug/stack_trace.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/thread_local.h"
+
+namespace {
+bool g_log_thread_and_sequence_checker_binding = false;
+}
 
 namespace base {
+
+// static
+void ThreadCheckerImpl::EnableStackLogging() {
+  g_log_thread_and_sequence_checker_binding = true;
+}
+
 ThreadCheckerImpl::ThreadCheckerImpl() {
-#if defined(STARBOARD)
-  starboard::ScopedSpinLock lock(&members_lock_);
-#else   // defined(STARBOARD)
   AutoLock auto_lock(lock_);
-#endif  // defined(STARBOARD)
   EnsureAssigned();
 }
 
 ThreadCheckerImpl::~ThreadCheckerImpl() = default;
 
-bool ThreadCheckerImpl::CalledOnValidThread() const {
-#if defined(STARBOARD)
-  starboard::ScopedSpinLock lock(&members_lock_);
-#else   // defined(STARBOARD)
+ThreadCheckerImpl::ThreadCheckerImpl(ThreadCheckerImpl&& other) {
+  // Verify that |other| is called on its associated thread and bind it now if
+  // it is currently detached (even if this isn't a DCHECK build).
+  const bool other_called_on_valid_thread = other.CalledOnValidThread();
+  DCHECK(other_called_on_valid_thread);
+
+  // Intentionally not using |other.lock_| to let TSAN catch racy construct from
+  // |other|.
+  bound_at_ = std::move(other.bound_at_);
+  thread_id_ = other.thread_id_;
+  task_token_ = other.task_token_;
+  sequence_token_ = other.sequence_token_;
+
+  // other.bound_at_ was moved from so it's null.
+  other.thread_id_ = PlatformThreadRef();
+  other.task_token_ = TaskToken();
+  other.sequence_token_ = SequenceToken();
+}
+
+ThreadCheckerImpl& ThreadCheckerImpl::operator=(ThreadCheckerImpl&& other) {
+  DCHECK(CalledOnValidThread());
+
+  // Verify that |other| is called on its associated thread and bind it now if
+  // it is currently detached (even if this isn't a DCHECK build).
+  const bool other_called_on_valid_thread = other.CalledOnValidThread();
+  DCHECK(other_called_on_valid_thread);
+
+  // Intentionally not using either |lock_| to let TSAN catch racy assign.
+  TS_UNCHECKED_READ(thread_id_) = TS_UNCHECKED_READ(other.thread_id_);
+  TS_UNCHECKED_READ(task_token_) = TS_UNCHECKED_READ(other.task_token_);
+  TS_UNCHECKED_READ(sequence_token_) = TS_UNCHECKED_READ(other.sequence_token_);
+
+  TS_UNCHECKED_READ(other.thread_id_) = PlatformThreadRef();
+  TS_UNCHECKED_READ(other.task_token_) = TaskToken();
+  TS_UNCHECKED_READ(other.sequence_token_) = SequenceToken();
+
+  return *this;
+}
+
+bool ThreadCheckerImpl::CalledOnValidThread(
+    std::unique_ptr<debug::StackTrace>* out_bound_at) const {
+  const bool has_thread_been_destroyed = ThreadLocalStorage::HasBeenDestroyed();
+
   AutoLock auto_lock(lock_);
-#endif  // defined(STARBOARD)
-  EnsureAssigned();
+  return CalledOnValidThreadInternal(out_bound_at, has_thread_been_destroyed);
+}
 
-  // Always return true when called from the task from which this
-  // ThreadCheckerImpl was assigned to a thread.
-  if (task_token_ == TaskToken::GetForCurrentThread())
+bool ThreadCheckerImpl::CalledOnValidThreadInternal(
+    std::unique_ptr<debug::StackTrace>* out_bound_at,
+    bool has_thread_been_destroyed) const {
+  // TaskToken/SequenceToken access thread-local storage. During destruction
+  // the state of thread-local storage is not guaranteed to be in a consistent
+  // state. Further, task-runner only installs the tokens when running a task.
+  if (!has_thread_been_destroyed) {
+    EnsureAssigned();
+
+    // Always return true when called from the task from which this
+    // ThreadCheckerImpl was assigned to a thread.
+    if (task_token_ == TaskToken::GetForCurrentThread())
+      return true;
+
+    // If this ThreadCheckerImpl is bound to a valid SequenceToken, it must be
+    // equal to the current SequenceToken and there must be a registered
+    // SingleThreadTaskRunner::CurrentDefaultHandle. Otherwise, the fact that
+    // the current task runs on the thread to which this ThreadCheckerImpl is
+    // bound is fortuitous.
+    if (sequence_token_.IsValid() &&
+        (sequence_token_ != SequenceToken::GetForCurrentThread() ||
+         !SingleThreadTaskRunner::HasCurrentDefault())) {
+      if (out_bound_at && bound_at_) {
+        *out_bound_at = std::make_unique<debug::StackTrace>(*bound_at_);
+      }
+      return false;
+    }
+  } else if (thread_id_.is_null()) {
+    // We're in tls destruction but the |thread_id_| hasn't been assigned yet.
+    // Assign it now. This doesn't call EnsureAssigned() as to do so while in
+    // tls destruction may result in the wrong TaskToken/SequenceToken.
+    if (g_log_thread_and_sequence_checker_binding)
+      bound_at_ = std::make_unique<debug::StackTrace>(size_t{10});
+    thread_id_ = PlatformThread::CurrentRef();
     return true;
-
-  // If this ThreadCheckerImpl is bound to a valid SequenceToken, it must be
-  // equal to the current SequenceToken and there must be a registered
-  // ThreadTaskRunnerHandle. Otherwise, the fact that the current task runs on
-  // the thread to which this ThreadCheckerImpl is bound is fortuitous.
-  if (sequence_token_.IsValid() &&
-      (sequence_token_ != SequenceToken::GetForCurrentThread() ||
-       !ThreadTaskRunnerHandle::IsSet())) {
-    return false;
   }
 
-  return thread_id_ == PlatformThread::CurrentRef();
+  if (thread_id_ != PlatformThread::CurrentRef()) {
+    if (out_bound_at && bound_at_) {
+      *out_bound_at = std::make_unique<debug::StackTrace>(*bound_at_);
+    }
+    return false;
+  }
+  return true;
 }
 
 void ThreadCheckerImpl::DetachFromThread() {
-#if defined(STARBOARD)
-  starboard::ScopedSpinLock lock(&members_lock_);
-#else   // defined(STARBOARD)
   AutoLock auto_lock(lock_);
-#endif  // defined(STARBOARD)
+  bound_at_ = nullptr;
   thread_id_ = PlatformThreadRef();
   task_token_ = TaskToken();
   sequence_token_ = SequenceToken();
 }
 
+std::unique_ptr<debug::StackTrace> ThreadCheckerImpl::GetBoundAt() const {
+  if (!bound_at_)
+    return nullptr;
+  return std::make_unique<debug::StackTrace>(*bound_at_);
+}
+
 void ThreadCheckerImpl::EnsureAssigned() const {
-#if defined(STARBOARD)
-  SB_DCHECK(members_lock_ == starboard::kSpinLockStateAcquired);
-#else   // defined(STARBOARD)
-  lock_.AssertAcquired();
-#endif  // defined(STARBOARD)
   if (!thread_id_.is_null())
     return;
-
+  if (g_log_thread_and_sequence_checker_binding)
+    bound_at_ = std::make_unique<debug::StackTrace>(size_t{10});
   thread_id_ = PlatformThread::CurrentRef();
   task_token_ = TaskToken::GetForCurrentThread();
   sequence_token_ = SequenceToken::GetForCurrentThread();
diff --git a/base/threading/thread_checker_impl.h b/base/threading/thread_checker_impl.h
index b871ad8..0d1d011 100644
--- a/base/threading/thread_checker_impl.h
+++ b/base/threading/thread_checker_impl.h
@@ -1,18 +1,24 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef BASE_THREADING_THREAD_CHECKER_IMPL_H_
 #define BASE_THREADING_THREAD_CHECKER_IMPL_H_
 
+#include <memory>
+
 #include "base/base_export.h"
-#include "base/compiler_specific.h"
 #include "base/sequence_token.h"
 #include "base/synchronization/lock.h"
-#include "base/threading/platform_thread.h"
-#include "starboard/common/spin_lock.h"
+#include "base/thread_annotations.h"
+#include "base/threading/platform_thread_ref.h"
 
 namespace base {
+namespace debug {
+class StackTrace;
+}
+
+class SequenceCheckerImpl;
 
 // Real implementation of ThreadChecker, for use in debug mode, or for temporary
 // use in release mode (e.g. to CHECK on a threading issue seen only in the
@@ -20,33 +26,64 @@
 //
 // Note: You should almost always use the ThreadChecker class to get the right
 // version for your build configuration.
-class BASE_EXPORT ThreadCheckerImpl {
+// Note: This is only a check, not a "lock". It is marked "LOCKABLE" only in
+// order to support thread_annotations.h.
+class LOCKABLE BASE_EXPORT ThreadCheckerImpl {
  public:
+  static void EnableStackLogging();
+
   ThreadCheckerImpl();
   ~ThreadCheckerImpl();
 
-  bool CalledOnValidThread() const WARN_UNUSED_RESULT;
+  // Allow move construct/assign. This must be called on |other|'s associated
+  // thread and assignment can only be made into a ThreadCheckerImpl which is
+  // detached or already associated with the current thread. This isn't
+  // thread-safe (|this| and |other| shouldn't be in use while this move is
+  // performed). If the assignment was legal, the resulting ThreadCheckerImpl
+  // will be bound to the current thread and |other| will be detached.
+  ThreadCheckerImpl(ThreadCheckerImpl&& other);
+  ThreadCheckerImpl& operator=(ThreadCheckerImpl&& other);
+
+  // On returning false, if logging is enabled with EnableStackLogging() and
+  // `out_bound_at` is not null, this method allocates a StackTrace and returns
+  // it in the out-parameter, storing inside it the stack from where the failing
+  // ThreadChecker was bound to its thread.
+  [[nodiscard]] bool CalledOnValidThread(
+      std::unique_ptr<debug::StackTrace>* out_bound_at = nullptr) const
+      LOCKS_EXCLUDED(lock_);
 
   // Changes the thread that is checked for in CalledOnValidThread.  This may
   // be useful when an object may be created on one thread and then used
   // exclusively on another thread.
-  void DetachFromThread();
+  void DetachFromThread() LOCKS_EXCLUDED(lock_);
 
  private:
-  void EnsureAssigned() const;
+  // This shares storage with SequenceCheckerImpl.
+  friend class SequenceCheckerImpl;
+
+  [[nodiscard]] bool CalledOnValidThreadInternal(
+      std::unique_ptr<debug::StackTrace>* out_bound_at,
+      bool has_thread_been_destroyed) const EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+  // Returns ownership of a pointer to StackTrace where the ThreadCheckerImpl
+  // was bound for debug logs, or nullptr if such logging was not enabled at
+  // the time.
+  std::unique_ptr<debug::StackTrace> GetBoundAt() const
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+  void EnsureAssigned() const EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   // Members are mutable so that CalledOnValidThread() can set them.
 
-#if defined(STARBOARD)
-  // Don't use a mutex since the number of mutexes is limited on some platforms.
-  mutable SbAtomic32 members_lock_ = starboard::kSpinLockStateReleased;
-#else   // defined(STARBOARD)
   // Synchronizes access to all members.
   mutable base::Lock lock_;
-#endif  // defined(STARBOARD)
+
+  // The location where the ThreadChecker was bound to the current
+  // thread/task/sequence. Default-initialized with 0 frames until bound.
+  mutable std::unique_ptr<debug::StackTrace> bound_at_ GUARDED_BY(lock_);
 
   // Thread on which CalledOnValidThread() may return true.
-  mutable PlatformThreadRef thread_id_;
+  mutable PlatformThreadRef thread_id_ GUARDED_BY(lock_);
 
   // TaskToken for which CalledOnValidThread() always returns true. This allows
   // CalledOnValidThread() to return true when called multiple times from the
@@ -54,13 +91,16 @@
   // (allowing usage of ThreadChecker objects on the stack in the scope of one-
   // off tasks). Note: CalledOnValidThread() may return true even if the current
   // TaskToken is not equal to this.
-  mutable TaskToken task_token_;
+  mutable TaskToken task_token_ GUARDED_BY(lock_);
 
   // SequenceToken for which CalledOnValidThread() may return true. Used to
-  // ensure that CalledOnValidThread() doesn't return true for TaskScheduler
+  // ensure that CalledOnValidThread() doesn't return true for ThreadPool
   // tasks that happen to run on the same thread but weren't posted to the same
   // SingleThreadTaskRunner.
-  mutable SequenceToken sequence_token_;
+  //
+  // Also used for SequenceCheckerImpl's CalledOnValidSequence(), as this shares
+  // storage. See SequenceCheckerImpl.
+  mutable SequenceToken sequence_token_ GUARDED_BY(lock_);
 };
 
 }  // namespace base
diff --git a/base/threading/thread_checker_unittest.cc b/base/threading/thread_checker_unittest.cc
index 5fbbc52..b405bd8 100644
--- a/base/threading/thread_checker_unittest.cc
+++ b/base/threading/thread_checker_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -6,15 +6,16 @@
 
 #include <memory>
 
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/macros.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
 #include "base/memory/ref_counted.h"
 #include "base/sequence_token.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/test/bind.h"
 #include "base/test/gtest_util.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/simple_thread.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/thread_local.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -23,21 +24,22 @@
 // A thread that runs a callback.
 class RunCallbackThread : public SimpleThread {
  public:
-  explicit RunCallbackThread(const Closure& callback)
-      : SimpleThread("RunCallbackThread"), callback_(callback) {}
+  explicit RunCallbackThread(OnceClosure callback)
+      : SimpleThread("RunCallbackThread"), callback_(std::move(callback)) {}
+
+  RunCallbackThread(const RunCallbackThread&) = delete;
+  RunCallbackThread& operator=(const RunCallbackThread&) = delete;
 
  private:
   // SimpleThread:
-  void Run() override { callback_.Run(); }
+  void Run() override { std::move(callback_).Run(); }
 
-  const Closure callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(RunCallbackThread);
+  OnceClosure callback_;
 };
 
 // Runs a callback on a new thread synchronously.
-void RunCallbackOnNewThreadSynchronously(const Closure& callback) {
-  RunCallbackThread run_callback_thread(callback);
+void RunCallbackOnNewThreadSynchronously(OnceClosure callback) {
+  RunCallbackThread run_callback_thread(std::move(callback));
   run_callback_thread.Start();
   run_callback_thread.Join();
 }
@@ -62,8 +64,9 @@
 void ExpectNotCalledOnValidThreadWithSequenceTokenAndThreadTaskRunnerHandle(
     ThreadCheckerImpl* thread_checker,
     SequenceToken sequence_token) {
-  ThreadTaskRunnerHandle thread_task_runner_handle(
-      MakeRefCounted<TestSimpleTaskRunner>());
+  SingleThreadTaskRunner::CurrentDefaultHandle
+      single_thread_task_runner_current_default_handle(
+          MakeRefCounted<TestSimpleTaskRunner>());
   ScopedSetSequenceTokenForCurrentThread
       scoped_set_sequence_token_for_current_thread(sequence_token);
   ExpectNotCalledOnValidThread(thread_checker);
@@ -78,8 +81,9 @@
 
 TEST(ThreadCheckerTest,
      AllowedSameThreadAndSequenceDifferentTasksWithThreadTaskRunnerHandle) {
-  ThreadTaskRunnerHandle thread_task_runner_handle(
-      MakeRefCounted<TestSimpleTaskRunner>());
+  SingleThreadTaskRunner::CurrentDefaultHandle
+      single_thread_task_runner_current_default_handle(
+          MakeRefCounted<TestSimpleTaskRunner>());
 
   std::unique_ptr<ThreadCheckerImpl> thread_checker;
   const SequenceToken sequence_token = SequenceToken::Create();
@@ -87,7 +91,7 @@
   {
     ScopedSetSequenceTokenForCurrentThread
         scoped_set_sequence_token_for_current_thread(sequence_token);
-    thread_checker.reset(new ThreadCheckerImpl);
+    thread_checker = std::make_unique<ThreadCheckerImpl>();
   }
 
   {
@@ -112,7 +116,7 @@
   {
     ScopedSetSequenceTokenForCurrentThread
         scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
-    thread_checker.reset(new ThreadCheckerImpl);
+    thread_checker = std::make_unique<ThreadCheckerImpl>();
   }
 
   {
@@ -125,12 +129,13 @@
 TEST(ThreadCheckerTest, DisallowedDifferentThreadsNoSequenceToken) {
   ThreadCheckerImpl thread_checker;
   RunCallbackOnNewThreadSynchronously(
-      Bind(&ExpectNotCalledOnValidThread, Unretained(&thread_checker)));
+      BindOnce(&ExpectNotCalledOnValidThread, Unretained(&thread_checker)));
 }
 
 TEST(ThreadCheckerTest, DisallowedDifferentThreadsSameSequence) {
-  ThreadTaskRunnerHandle thread_task_runner_handle(
-      MakeRefCounted<TestSimpleTaskRunner>());
+  SingleThreadTaskRunner::CurrentDefaultHandle
+      single_thread_task_runner_current_default_handle(
+          MakeRefCounted<TestSimpleTaskRunner>());
   const SequenceToken sequence_token(SequenceToken::Create());
 
   ScopedSetSequenceTokenForCurrentThread
@@ -138,7 +143,7 @@
   ThreadCheckerImpl thread_checker;
   EXPECT_TRUE(thread_checker.CalledOnValidThread());
 
-  RunCallbackOnNewThreadSynchronously(Bind(
+  RunCallbackOnNewThreadSynchronously(BindOnce(
       &ExpectNotCalledOnValidThreadWithSequenceTokenAndThreadTaskRunnerHandle,
       Unretained(&thread_checker), sequence_token));
 }
@@ -146,13 +151,14 @@
 TEST(ThreadCheckerTest, DisallowedSameThreadDifferentSequence) {
   std::unique_ptr<ThreadCheckerImpl> thread_checker;
 
-  ThreadTaskRunnerHandle thread_task_runner_handle(
-      MakeRefCounted<TestSimpleTaskRunner>());
+  SingleThreadTaskRunner::CurrentDefaultHandle
+      single_thread_task_runner_current_default_handle(
+          MakeRefCounted<TestSimpleTaskRunner>());
 
   {
     ScopedSetSequenceTokenForCurrentThread
         scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
-    thread_checker.reset(new ThreadCheckerImpl);
+    thread_checker = std::make_unique<ThreadCheckerImpl>();
   }
 
   {
@@ -173,14 +179,15 @@
   // Verify that CalledOnValidThread() returns true when called on a different
   // thread after a call to DetachFromThread().
   RunCallbackOnNewThreadSynchronously(
-      Bind(&ExpectCalledOnValidThread, Unretained(&thread_checker)));
+      BindOnce(&ExpectCalledOnValidThread, Unretained(&thread_checker)));
 
   EXPECT_FALSE(thread_checker.CalledOnValidThread());
 }
 
 TEST(ThreadCheckerTest, DetachFromThreadWithSequenceToken) {
-  ThreadTaskRunnerHandle thread_task_runner_handle(
-      MakeRefCounted<TestSimpleTaskRunner>());
+  SingleThreadTaskRunner::CurrentDefaultHandle
+      single_thread_task_runner_current_default_handle(
+          MakeRefCounted<TestSimpleTaskRunner>());
   ScopedSetSequenceTokenForCurrentThread
       scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
   ThreadCheckerImpl thread_checker;
@@ -189,11 +196,117 @@
   // Verify that CalledOnValidThread() returns true when called on a different
   // thread after a call to DetachFromThread().
   RunCallbackOnNewThreadSynchronously(
-      Bind(&ExpectCalledOnValidThread, Unretained(&thread_checker)));
+      BindOnce(&ExpectCalledOnValidThread, Unretained(&thread_checker)));
 
   EXPECT_FALSE(thread_checker.CalledOnValidThread());
 }
 
+// Owns a ThreadCheckerImpl and asserts that CalledOnValidThread() is valid
+// in ~ThreadCheckerOwner.
+class ThreadCheckerOwner {
+ public:
+  explicit ThreadCheckerOwner(bool detach_from_thread) {
+    if (detach_from_thread)
+      checker_.DetachFromThread();
+  }
+
+  ThreadCheckerOwner(const ThreadCheckerOwner&) = delete;
+  ThreadCheckerOwner& operator=(const ThreadCheckerOwner&) = delete;
+
+  ~ThreadCheckerOwner() { EXPECT_TRUE(checker_.CalledOnValidThread()); }
+
+ private:
+  ThreadCheckerImpl checker_;
+};
+
+// Verifies ThreadCheckerImpl::CalledOnValidThread() returns true if called
+// during thread destruction.
+TEST(ThreadCheckerTest, CalledOnValidThreadFromThreadDestruction) {
+  ThreadLocalOwnedPointer<ThreadCheckerOwner> thread_local_owner;
+  RunCallbackOnNewThreadSynchronously(BindLambdaForTesting([&]() {
+    thread_local_owner.Set(std::make_unique<ThreadCheckerOwner>(false));
+  }));
+}
+
+// Variant of CalledOnValidThreadFromThreadDestruction that calls
+// ThreadCheckerImpl::DetachFromThread().
+TEST(ThreadCheckerTest, CalledOnValidThreadFromThreadDestructionDetached) {
+  ThreadLocalOwnedPointer<ThreadCheckerOwner> thread_local_owner;
+  RunCallbackOnNewThreadSynchronously(BindLambdaForTesting([&]() {
+    thread_local_owner.Set(std::make_unique<ThreadCheckerOwner>(true));
+  }));
+}
+
+TEST(ThreadCheckerTest, Move) {
+  ThreadCheckerImpl initial;
+  EXPECT_TRUE(initial.CalledOnValidThread());
+
+  ThreadCheckerImpl move_constructed(std::move(initial));
+  EXPECT_TRUE(move_constructed.CalledOnValidThread());
+
+  ThreadCheckerImpl move_assigned;
+  move_assigned = std::move(move_constructed);
+  EXPECT_TRUE(move_assigned.CalledOnValidThread());
+
+  // The two ThreadCheckerImpls moved from should be able to rebind to another
+  // thread.
+  RunCallbackOnNewThreadSynchronously(
+      BindOnce(&ExpectCalledOnValidThread, Unretained(&initial)));
+  RunCallbackOnNewThreadSynchronously(
+      BindOnce(&ExpectCalledOnValidThread, Unretained(&move_constructed)));
+
+  // But the latest one shouldn't be able to run on another thread.
+  RunCallbackOnNewThreadSynchronously(
+      BindOnce(&ExpectNotCalledOnValidThread, Unretained(&move_assigned)));
+
+  EXPECT_TRUE(move_assigned.CalledOnValidThread());
+}
+
+TEST(ThreadCheckerTest, MoveAssignIntoDetached) {
+  ThreadCheckerImpl initial;
+
+  ThreadCheckerImpl move_assigned;
+  move_assigned.DetachFromThread();
+  move_assigned = std::move(initial);
+
+  // |initial| is detached after move.
+  RunCallbackOnNewThreadSynchronously(
+      BindOnce(&ExpectCalledOnValidThread, Unretained(&initial)));
+
+  // |move_assigned| should be associated with the main thread.
+  RunCallbackOnNewThreadSynchronously(
+      BindOnce(&ExpectNotCalledOnValidThread, Unretained(&move_assigned)));
+
+  EXPECT_TRUE(move_assigned.CalledOnValidThread());
+}
+
+TEST(ThreadCheckerTest, MoveFromDetachedRebinds) {
+  ThreadCheckerImpl initial;
+  initial.DetachFromThread();
+
+  ThreadCheckerImpl moved_into(std::move(initial));
+
+  // |initial| is still detached after move.
+  RunCallbackOnNewThreadSynchronously(
+      BindOnce(&ExpectCalledOnValidThread, Unretained(&initial)));
+
+  // |moved_into| is bound to the current thread as part of the move.
+  RunCallbackOnNewThreadSynchronously(
+      BindOnce(&ExpectNotCalledOnValidThread, Unretained(&moved_into)));
+  EXPECT_TRUE(moved_into.CalledOnValidThread());
+}
+
+TEST(ThreadCheckerTest, MoveOffThreadBanned) {
+  testing::GTEST_FLAG(death_test_style) = "threadsafe";
+
+  ThreadCheckerImpl other_thread;
+  other_thread.DetachFromThread();
+  RunCallbackOnNewThreadSynchronously(
+      BindOnce(&ExpectCalledOnValidThread, Unretained(&other_thread)));
+
+  EXPECT_DCHECK_DEATH(ThreadCheckerImpl main_thread(std::move(other_thread)));
+}
+
 namespace {
 
 // This fixture is a helper for unit testing the thread checker macros as it is
@@ -205,41 +318,41 @@
  public:
   ThreadCheckerMacroTest() = default;
 
+  ThreadCheckerMacroTest(const ThreadCheckerMacroTest&) = delete;
+  ThreadCheckerMacroTest& operator=(const ThreadCheckerMacroTest&) = delete;
+
   void ExpectDeathOnOtherThread() {
 #if DCHECK_IS_ON()
-    EXPECT_DCHECK_DEATH({ DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_); });
+    EXPECT_DCHECK_DEATH({ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); });
 #else
     // Happily no-ops on non-dcheck builds.
-    DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_);
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 #endif
   }
 
   void ExpectNoDeathOnOtherThreadAfterDetach() {
-    DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_);
-    DCHECK_CALLED_ON_VALID_THREAD(my_thread_checker_)
-        << "Make sure it compiles when DCHECK is off";
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   }
 
  protected:
-  THREAD_CHECKER(my_thread_checker_);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ThreadCheckerMacroTest);
+  THREAD_CHECKER(thread_checker_);
 };
 
 }  // namespace
 
 TEST_F(ThreadCheckerMacroTest, Macros) {
+  testing::GTEST_FLAG(death_test_style) = "threadsafe";
+
   THREAD_CHECKER(my_thread_checker);
 
-  RunCallbackOnNewThreadSynchronously(Bind(
+  RunCallbackOnNewThreadSynchronously(BindOnce(
       &ThreadCheckerMacroTest::ExpectDeathOnOtherThread, Unretained(this)));
 
-  DETACH_FROM_THREAD(my_thread_checker_);
+  DETACH_FROM_THREAD(thread_checker_);
 
   RunCallbackOnNewThreadSynchronously(
-      Bind(&ThreadCheckerMacroTest::ExpectNoDeathOnOtherThreadAfterDetach,
-           Unretained(this)));
+      BindOnce(&ThreadCheckerMacroTest::ExpectNoDeathOnOtherThreadAfterDetach,
+               Unretained(this)));
 }
 
 }  // namespace base
diff --git a/base/threading/thread_collision_warner.cc b/base/threading/thread_collision_warner.cc
index 547e11c..ee055c0 100644
--- a/base/threading/thread_collision_warner.cc
+++ b/base/threading/thread_collision_warner.cc
@@ -1,10 +1,12 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright 2010 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/thread_collision_warner.h"
 
-#include "base/logging.h"
+#include <ostream>
+
+#include "base/notreached.h"
 #include "base/threading/platform_thread.h"
 
 namespace base {
diff --git a/base/threading/thread_collision_warner.h b/base/threading/thread_collision_warner.h
index fcd1d71..a11ac77 100644
--- a/base/threading/thread_collision_warner.h
+++ b/base/threading/thread_collision_warner.h
@@ -1,16 +1,14 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef BASE_THREADING_THREAD_COLLISION_WARNER_H_
 #define BASE_THREADING_THREAD_COLLISION_WARNER_H_
 
-#include <memory>
-
 #include "base/atomicops.h"
 #include "base/base_export.h"
 #include "base/compiler_specific.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
 
 // A helper class alongside macros to be used to verify assumptions about thread
 // safety of a class.
@@ -20,7 +18,7 @@
 //
 //          In this case the macro DFAKE_SCOPED_LOCK has to be
 //          used, it checks that if a thread is inside the push/pop then
-//          no one else is still inside the pop/push
+//          noone else is still inside the pop/push
 //
 // class NonThreadSafeQueue {
 //  public:
@@ -39,7 +37,7 @@
 //
 //          In this case the macro DFAKE_SCOPED_RECURSIVE_LOCK
 //          has to be used, it checks that if a thread is inside the push/pop
-//          then no one else is still inside the pop/push
+//          then noone else is still inside the pop/push
 //
 // class NonThreadSafeQueue {
 //  public:
@@ -79,7 +77,7 @@
 // };
 //
 //
-// Example: Class that has to be constructed/destroyed on same thread, it has
+// Example: Class that has to be contructed/destroyed on same thread, it has
 //          a "shareable" method (with external synchronization) and a not
 //          shareable method (even with external synchronization).
 //
@@ -98,22 +96,30 @@
 //   DFAKE_MUTEX(shareable_section_);
 // };
 
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if !defined(NDEBUG)
+
+#define DFAKE_UNIQUE_VARIABLE_CONCAT(a, b) a##b
+// CONCAT1 provides extra level of indirection so that __LINE__ macro expands.
+#define DFAKE_UNIQUE_VARIABLE_CONCAT1(a, b) DFAKE_UNIQUE_VARIABLE_CONCAT(a, b)
+#define DFAKE_UNIQUE_VARIABLE_NAME(a) DFAKE_UNIQUE_VARIABLE_CONCAT1(a, __LINE__)
 
 // Defines a class member that acts like a mutex. It is used only as a
 // verification tool.
-#define DFAKE_MUTEX(obj) mutable base::ThreadCollisionWarner obj
+#define DFAKE_MUTEX(obj) \
+     mutable base::ThreadCollisionWarner obj
 // Asserts the call is never called simultaneously in two threads. Used at
 // member function scope.
-#define DFAKE_SCOPED_LOCK(obj) \
-  base::ThreadCollisionWarner::ScopedCheck s_check_##obj(&obj)
+#define DFAKE_SCOPED_LOCK(obj)                                         \
+  base::ThreadCollisionWarner::ScopedCheck DFAKE_UNIQUE_VARIABLE_NAME( \
+      s_check_)(&obj)
 // Asserts the call is never called simultaneously in two threads. Used at
 // member function scope. Same as DFAKE_SCOPED_LOCK but allows recursive locks.
-#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) \
-  base::ThreadCollisionWarner::ScopedRecursiveCheck sr_check_##obj(&obj)
+#define DFAKE_SCOPED_RECURSIVE_LOCK(obj)            \
+  base::ThreadCollisionWarner::ScopedRecursiveCheck \
+      DFAKE_UNIQUE_VARIABLE_NAME(sr_check)(&obj)
 // Asserts the code is always executed in the same thread.
 #define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) \
-  base::ThreadCollisionWarner::Check check_##obj(&obj)
+  base::ThreadCollisionWarner::Check DFAKE_UNIQUE_VARIABLE_NAME(check_)(&obj)
 
 #else
 
@@ -144,9 +150,14 @@
  public:
   // The parameter asserter is there only for test purpose
   explicit ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter())
-      : valid_thread_id_(0), counter_(0), asserter_(asserter) {}
+      : valid_thread_id_(0),
+        counter_(0),
+        asserter_(asserter) {}
 
-  ~ThreadCollisionWarner() { delete asserter_; }
+  ThreadCollisionWarner(const ThreadCollisionWarner&) = delete;
+  ThreadCollisionWarner& operator=(const ThreadCollisionWarner&) = delete;
+
+  ~ThreadCollisionWarner() { asserter_.ClearAndDelete(); }
 
   // This class is meant to be used through the macro
   // DFAKE_SCOPED_LOCK_THREAD_LOCKED
@@ -155,32 +166,38 @@
   // from one thread
   class BASE_EXPORT Check {
    public:
-    explicit Check(ThreadCollisionWarner* warner) : warner_(warner) {
+    explicit Check(ThreadCollisionWarner* warner)
+        : warner_(warner) {
       warner_->EnterSelf();
     }
 
+    Check(const Check&) = delete;
+    Check& operator=(const Check&) = delete;
+
     ~Check() = default;
 
    private:
-    ThreadCollisionWarner* warner_;
-
-    DISALLOW_COPY_AND_ASSIGN(Check);
+    raw_ptr<ThreadCollisionWarner> warner_;
   };
 
   // This class is meant to be used through the macro
   // DFAKE_SCOPED_LOCK
   class BASE_EXPORT ScopedCheck {
    public:
-    explicit ScopedCheck(ThreadCollisionWarner* warner) : warner_(warner) {
+    explicit ScopedCheck(ThreadCollisionWarner* warner)
+        : warner_(warner) {
       warner_->Enter();
     }
 
-    ~ScopedCheck() { warner_->Leave(); }
+    ScopedCheck(const ScopedCheck&) = delete;
+    ScopedCheck& operator=(const ScopedCheck&) = delete;
+
+    ~ScopedCheck() {
+      warner_->Leave();
+    }
 
    private:
-    ThreadCollisionWarner* warner_;
-
-    DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
+    raw_ptr<ThreadCollisionWarner> warner_;
   };
 
   // This class is meant to be used through the macro
@@ -192,12 +209,15 @@
       warner_->EnterSelf();
     }
 
-    ~ScopedRecursiveCheck() { warner_->Leave(); }
+    ScopedRecursiveCheck(const ScopedRecursiveCheck&) = delete;
+    ScopedRecursiveCheck& operator=(const ScopedRecursiveCheck&) = delete;
+
+    ~ScopedRecursiveCheck() {
+      warner_->Leave();
+    }
 
    private:
-    ThreadCollisionWarner* warner_;
-
-    DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck);
+    raw_ptr<ThreadCollisionWarner> warner_;
   };
 
  private:
@@ -223,9 +243,7 @@
 
   // Here only for class unit tests purpose, during the test I need to not
   // DCHECK but notify the collision with something else.
-  AsserterBase* asserter_;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner);
+  raw_ptr<AsserterBase> asserter_;
 };
 
 }  // namespace base
diff --git a/base/threading/thread_collision_warner_unittest.cc b/base/threading/thread_collision_warner_unittest.cc
index cd56768..ffd9c5a 100644
--- a/base/threading/thread_collision_warner_unittest.cc
+++ b/base/threading/thread_collision_warner_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -7,16 +7,12 @@
 #include <memory>
 
 #include "base/compiler_specific.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/simple_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-// '' : local class member function does not have a body
-MSVC_PUSH_DISABLE_WARNING(4822)
-
-
 #if defined(NDEBUG)
 
 // Would cause a memory leak otherwise.
@@ -132,6 +128,9 @@
         : push_pop_(asserter) {
     }
 
+    NonThreadSafeQueue(const NonThreadSafeQueue&) = delete;
+    NonThreadSafeQueue& operator=(const NonThreadSafeQueue&) = delete;
+
     void push(int value) {
       DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_);
     }
@@ -143,8 +142,6 @@
 
    private:
     DFAKE_MUTEX(push_pop_);
-
-    DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
   };
 
   class QueueUser : public base::DelegateSimpleThread::Delegate {
@@ -157,7 +154,7 @@
     }
 
    private:
-    NonThreadSafeQueue* queue_;
+    raw_ptr<NonThreadSafeQueue> queue_;
   };
 
   AssertReporter* local_reporter = new AssertReporter();
@@ -188,9 +185,12 @@
         : push_pop_(asserter) {
     }
 
+    NonThreadSafeQueue(const NonThreadSafeQueue&) = delete;
+    NonThreadSafeQueue& operator=(const NonThreadSafeQueue&) = delete;
+
     void push(int value) {
       DFAKE_SCOPED_LOCK(push_pop_);
-      base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(5));
+      base::PlatformThread::Sleep(base::Seconds(5));
     }
 
     int pop() {
@@ -200,8 +200,6 @@
 
    private:
     DFAKE_MUTEX(push_pop_);
-
-    DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
   };
 
   class QueueUser : public base::DelegateSimpleThread::Delegate {
@@ -214,7 +212,7 @@
     }
 
    private:
-    NonThreadSafeQueue* queue_;
+    raw_ptr<NonThreadSafeQueue> queue_;
   };
 
   AssertReporter* local_reporter = new AssertReporter();
@@ -245,9 +243,12 @@
         : push_pop_(asserter) {
     }
 
+    NonThreadSafeQueue(const NonThreadSafeQueue&) = delete;
+    NonThreadSafeQueue& operator=(const NonThreadSafeQueue&) = delete;
+
     void push(int value) {
       DFAKE_SCOPED_LOCK(push_pop_);
-      base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
+      base::PlatformThread::Sleep(base::Seconds(2));
     }
 
     int pop() {
@@ -257,8 +258,6 @@
 
    private:
     DFAKE_MUTEX(push_pop_);
-
-    DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
   };
 
   // This time the QueueUser class protects the non thread safe queue with
@@ -279,8 +278,8 @@
       }
     }
    private:
-    NonThreadSafeQueue* queue_;
-    base::Lock* lock_;
+    raw_ptr<NonThreadSafeQueue> queue_;
+    raw_ptr<base::Lock> lock_;
   };
 
   AssertReporter* local_reporter = new AssertReporter();
@@ -313,10 +312,13 @@
         : push_pop_(asserter) {
     }
 
+    NonThreadSafeQueue(const NonThreadSafeQueue&) = delete;
+    NonThreadSafeQueue& operator=(const NonThreadSafeQueue&) = delete;
+
     void push(int) {
       DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
       bar();
-      base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
+      base::PlatformThread::Sleep(base::Seconds(2));
     }
 
     int pop() {
@@ -330,8 +332,6 @@
 
    private:
     DFAKE_MUTEX(push_pop_);
-
-    DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
   };
 
   // This time the QueueUser class protects the non thread safe queue with
@@ -356,8 +356,8 @@
       }
     }
    private:
-    NonThreadSafeQueue* queue_;
-    base::Lock* lock_;
+    raw_ptr<NonThreadSafeQueue> queue_;
+    raw_ptr<base::Lock> lock_;
   };
 
   AssertReporter* local_reporter = new AssertReporter();
diff --git a/base/threading/thread_id_name_manager.cc b/base/threading/thread_id_name_manager.cc
index 46e1c56..7701cf0 100644
--- a/base/threading/thread_id_name_manager.cc
+++ b/base/threading/thread_id_name_manager.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -7,13 +7,20 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "base/logging.h"
+#include "base/check.h"
+#include "base/containers/contains.h"
+#include "base/containers/cxx20_erase.h"
 #include "base/memory/singleton.h"
-#include "base/no_destructor.h"
 #include "base/strings/string_util.h"
-#include "base/threading/thread_local.h"
-#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
-#include "starboard/types.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"  // no-presubmit-check
+#include "third_party/abseil-cpp/absl/base/attributes.h"
+
+#if defined(STARBOARD)
+#include <pthread.h>
+
+#include "base/check_op.h"
+#include "starboard/thread.h"
+#endif
 
 namespace base {
 namespace {
@@ -21,12 +28,32 @@
 static const char kDefaultName[] = "";
 static std::string* g_default_name;
 
-ThreadLocalStorage::Slot& GetThreadNameTLS() {
-  static base::NoDestructor<base::ThreadLocalStorage::Slot> thread_name_tls;
-  return *thread_name_tls;
+#if defined(STARBOARD)
+ABSL_CONST_INIT pthread_once_t s_once_flag = PTHREAD_ONCE_INIT;
+ABSL_CONST_INIT pthread_key_t s_thread_local_key = 0;
+
+void InitThreadLocalKey() {
+  int res = pthread_key_create(&s_thread_local_key , NULL);
+  DCHECK(res == 0);
 }
+
+void EnsureThreadLocalKeyInited() {
+  pthread_once(&s_once_flag, InitThreadLocalKey);
 }
 
+const char* GetThreadName() {
+  EnsureThreadLocalKeyInited();
+  const char* thread_name = static_cast<const char*>(
+      pthread_getspecific(s_thread_local_key));
+  return !!thread_name ? thread_name : kDefaultName;
+}
+#else
+ABSL_CONST_INIT thread_local const char* thread_name = kDefaultName;
+#endif
+}
+
+ThreadIdNameManager::Observer::~Observer() = default;
+
 ThreadIdNameManager::ThreadIdNameManager()
     : main_process_name_(nullptr), main_process_id_(kInvalidThreadId) {
   g_default_name = new std::string(kDefaultName);
@@ -54,9 +81,16 @@
       name_to_interned_name_[kDefaultName];
 }
 
-void ThreadIdNameManager::InstallSetNameCallback(SetNameCallback callback) {
+void ThreadIdNameManager::AddObserver(Observer* obs) {
   AutoLock locked(lock_);
-  set_name_callback_ = std::move(callback);
+  DCHECK(!base::Contains(observers_, obs));
+  observers_.push_back(obs);
+}
+
+void ThreadIdNameManager::RemoveObserver(Observer* obs) {
+  AutoLock locked(lock_);
+  DCHECK(base::Contains(observers_, obs));
+  base::Erase(observers_, obs);
 }
 
 void ThreadIdNameManager::SetName(const std::string& name) {
@@ -74,10 +108,14 @@
 
     auto id_to_handle_iter = thread_id_to_handle_.find(id);
 
-    GetThreadNameTLS().Set(const_cast<char*>(leaked_str->c_str()));
-    if (set_name_callback_) {
-      set_name_callback_.Run(leaked_str->c_str());
-    }
+#if defined(STARBOARD)
+    EnsureThreadLocalKeyInited();
+    pthread_setspecific(s_thread_local_key, const_cast<char*>(leaked_str->c_str()));
+#else
+    thread_name = leaked_str->c_str();
+#endif
+    for (Observer* obs : observers_)
+      obs->OnThreadNameChanged(leaked_str->c_str());
 
     // The main thread of a process will not be created as a Thread object which
     // means there is no PlatformThreadHandler registered.
@@ -114,8 +152,11 @@
 }
 
 const char* ThreadIdNameManager::GetNameForCurrentThread() {
-  const char* name = reinterpret_cast<const char*>(GetThreadNameTLS().Get());
-  return name ? name : kDefaultName;
+#if defined(STARBOARD)
+  return GetThreadName();
+#else
+  return thread_name;
+#endif
 }
 
 void ThreadIdNameManager::RemoveName(PlatformThreadHandle::Handle handle,
@@ -136,4 +177,15 @@
   thread_id_to_handle_.erase(id_to_handle_iter);
 }
 
+std::vector<PlatformThreadId> ThreadIdNameManager::GetIds() {
+  AutoLock locked(lock_);
+
+  std::vector<PlatformThreadId> ids;
+  ids.reserve(thread_id_to_handle_.size());
+  for (const auto& iter : thread_id_to_handle_)
+    ids.push_back(iter.first);
+
+  return ids;
+}
+
 }  // namespace base
diff --git a/base/threading/thread_id_name_manager.h b/base/threading/thread_id_name_manager.h
index f17dc1a..85063c8 100644
--- a/base/threading/thread_id_name_manager.h
+++ b/base/threading/thread_id_name_manager.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -7,10 +7,11 @@
 
 #include <map>
 #include <string>
+#include <vector>
 
 #include "base/base_export.h"
-#include "base/callback.h"
-#include "base/macros.h"
+#include "base/functional/callback.h"
+#include "base/memory/raw_ptr.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/platform_thread.h"
 
@@ -23,16 +24,29 @@
  public:
   static ThreadIdNameManager* GetInstance();
 
+  ThreadIdNameManager(const ThreadIdNameManager&) = delete;
+  ThreadIdNameManager& operator=(const ThreadIdNameManager&) = delete;
+
   static const char* GetDefaultInternedString();
 
+  class BASE_EXPORT Observer {
+   public:
+    virtual ~Observer();
+
+    // Called on the thread whose name is changing, immediately after the name
+    // is set. |name| is a pointer to a C string that is guaranteed to remain
+    // valid for the duration of the process.
+    //
+    // NOTE: Will be called while ThreadIdNameManager's lock is held, so don't
+    // call back into it.
+    virtual void OnThreadNameChanged(const char* name) = 0;
+  };
+
   // Register the mapping between a thread |id| and |handle|.
   void RegisterThread(PlatformThreadHandle::Handle handle, PlatformThreadId id);
 
-  // The callback is called on the thread, immediately after the name is set.
-  // |name| is a pointer to a C string that is guaranteed to remain valid for
-  // the duration of the process.
-  using SetNameCallback = base::RepeatingCallback<void(const char* name)>;
-  void InstallSetNameCallback(SetNameCallback callback);
+  void AddObserver(Observer*);
+  void RemoveObserver(Observer*);
 
   // Set the name for the current thread.
   void SetName(const std::string& name);
@@ -46,6 +60,10 @@
   // Remove the name for the given id.
   void RemoveName(PlatformThreadHandle::Handle handle, PlatformThreadId id);
 
+  // Return all registered thread ids (note that this doesn't include the main
+  // thread id).
+  std::vector<PlatformThreadId> GetIds();
+
  private:
   friend struct DefaultSingletonTraits<ThreadIdNameManager>;
 
@@ -67,12 +85,12 @@
   ThreadHandleToInternedNameMap thread_handle_to_interned_name_;
 
   // Treat the main process specially as there is no PlatformThreadHandle.
-  std::string* main_process_name_;
+  raw_ptr<std::string> main_process_name_;
   PlatformThreadId main_process_id_;
 
-  SetNameCallback set_name_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadIdNameManager);
+  // There's no point using a base::ObserverList behind a lock, so we just use
+  // an std::vector instead.
+  std::vector<Observer*> observers_;
 };
 
 }  // namespace base
diff --git a/base/threading/thread_id_name_manager_unittest.cc b/base/threading/thread_id_name_manager_unittest.cc
index 350dc0f..b61131e 100644
--- a/base/threading/thread_id_name_manager_unittest.cc
+++ b/base/threading/thread_id_name_manager_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
diff --git a/base/threading/thread_local.h b/base/threading/thread_local.h
index cad9add..a32e671 100644
--- a/base/threading/thread_local.h
+++ b/base/threading/thread_local.h
@@ -1,98 +1,70 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 // WARNING: Thread local storage is a bit tricky to get right. Please make sure
 // that this is really the proper solution for what you're trying to achieve.
 // Don't prematurely optimize, most likely you can just use a Lock.
-//
-// These classes implement a wrapper around ThreadLocalStorage::Slot. On
-// construction, they will allocate a TLS slot, and free the TLS slot on
-// destruction. No memory management (creation or destruction) is handled. This
-// means for uses of ThreadLocalPointer, you must correctly manage the memory
-// yourself, these classes will not destroy the pointer for you. There are no
-// at-thread-exit actions taken by these classes.
-//
-// ThreadLocalPointer<Type> wraps a Type*. It performs no creation or
-// destruction, so memory management must be handled elsewhere. The first call
-// to Get() on a thread will return NULL. You can update the pointer with a call
-// to Set().
-//
-// ThreadLocalBoolean wraps a bool. It will default to false if it has never
-// been set otherwise with Set().
-//
-// Thread Safety: An instance of ThreadLocalStorage is completely thread safe
-// once it has been created. If you want to dynamically create an instance, you
-// must of course properly deal with safety and race conditions. This means a
-// function-level static initializer is generally inappropiate.
-//
-// In Android, the system TLS is limited.
-//
-// Example usage:
-//   // My class is logically attached to a single thread. We cache a pointer
-//   // on the thread it was created on, so we can implement current().
-//   MyClass::MyClass() {
-//     DCHECK(Singleton<ThreadLocalPointer<MyClass> >::get()->Get() == NULL);
-//     Singleton<ThreadLocalPointer<MyClass> >::get()->Set(this);
-//   }
-//
-//   MyClass::~MyClass() {
-//     DCHECK(Singleton<ThreadLocalPointer<MyClass> >::get()->Get() != NULL);
-//     Singleton<ThreadLocalPointer<MyClass> >::get()->Set(NULL);
-//   }
-//
-//   // Return the current MyClass associated with the calling thread, can be
-//   // NULL if there isn't a MyClass associated.
-//   MyClass* MyClass::current() {
-//     return Singleton<ThreadLocalPointer<MyClass> >::get()->Get();
-//   }
 
 #ifndef BASE_THREADING_THREAD_LOCAL_H_
 #define BASE_THREADING_THREAD_LOCAL_H_
 
-#include "base/macros.h"
+#include <memory>
+
+#include "base/dcheck_is_on.h"
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread_local_internal.h"
 #include "base/threading/thread_local_storage.h"
 
 namespace base {
 
-template <typename Type>
-class ThreadLocalPointer {
+// `thread_local` is only allowed for trivially-destructible types (see
+// //styleguide/c++/c++.md#thread_local-variables). This class provides
+// thread-scoped management of non-trivially-destructible types. Pointers handed
+// to it are owned and automatically deleted during their associated thread's
+// exit phase (or when replaced if Set() is invoked multiple times on the same
+// thread).
+//
+// The ThreadLocalOwnedPointer instance itself can only be destroyed when no
+// threads, other than the one it is destroyed on, have remaining state set in
+// it. Typically this means that ThreadLocalOwnedPointer instances are held in
+// static storage or at the very least only recycled in the single-threaded
+// phase between tests in the same process.
+#if DCHECK_IS_ON()
+template <typename T>
+using ThreadLocalOwnedPointer = internal::CheckedThreadLocalOwnedPointer<T>;
+#else   // DCHECK_IS_ON()
+template <typename T>
+class ThreadLocalOwnedPointer {
  public:
-  ThreadLocalPointer() = default;
-  ~ThreadLocalPointer() = default;
+  ThreadLocalOwnedPointer() = default;
 
-  Type* Get() {
-    return static_cast<Type*>(slot_.Get());
+  ThreadLocalOwnedPointer(const ThreadLocalOwnedPointer&) = delete;
+  ThreadLocalOwnedPointer& operator=(const ThreadLocalOwnedPointer&) = delete;
+
+  ~ThreadLocalOwnedPointer() {
+    // Assume that this thread is the only one with potential state left. This
+    // is verified in ~CheckedThreadLocalOwnedPointer().
+    Set(nullptr);
   }
 
-  void Set(Type* ptr) {
-    slot_.Set(const_cast<void*>(static_cast<const void*>(ptr)));
+  T* Get() const { return static_cast<T*>(slot_.Get()); }
+
+  // Sets a new value, returns the old.
+  std::unique_ptr<T> Set(std::unique_ptr<T> ptr) {
+    auto existing = WrapUnique(Get());
+    slot_.Set(const_cast<void*>(static_cast<const void*>(ptr.release())));
+    return existing;
   }
 
+  T& operator*() { return *Get(); }
+
  private:
-  ThreadLocalStorage::Slot slot_;
+  static void DeleteTlsPtr(void* ptr) { delete static_cast<T*>(ptr); }
 
-  DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer<Type>);
+  ThreadLocalStorage::Slot slot_{&DeleteTlsPtr};
 };
-
-class ThreadLocalBoolean {
- public:
-  ThreadLocalBoolean() = default;
-  ~ThreadLocalBoolean() = default;
-
-  bool Get() {
-    return tlp_.Get() != nullptr;
-  }
-
-  void Set(bool val) {
-    tlp_.Set(val ? this : nullptr);
-  }
-
- private:
-  ThreadLocalPointer<void> tlp_;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadLocalBoolean);
-};
+#endif  // DCHECK_IS_ON()
 
 }  // namespace base
 
diff --git a/base/threading/thread_local_internal.h b/base/threading/thread_local_internal.h
new file mode 100644
index 0000000..ed99410
--- /dev/null
+++ b/base/threading/thread_local_internal.h
@@ -0,0 +1,97 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_LOCAL_INTERNAL_H_
+#define BASE_THREADING_THREAD_LOCAL_INTERNAL_H_
+
+#include "base/dcheck_is_on.h"
+
+#if DCHECK_IS_ON()
+
+#include <atomic>
+#include <memory>
+#include <ostream>
+
+#include "base/check_op.h"
+#include "base/memory/raw_ptr.h"
+#include "base/threading/thread_local_storage.h"
+
+namespace base {
+namespace internal {
+
+// A version of ThreadLocalOwnedPointer which verifies that it's only destroyed
+// when no threads, other than the one it is destroyed on, have remaining state
+// set in it. A ThreadLocalOwnedPointer instance being destroyed too early would
+// result in leaks per unregistering the TLS slot (and thus the DeleteTlsPtr
+// hook).
+template <typename T>
+class CheckedThreadLocalOwnedPointer {
+ public:
+  CheckedThreadLocalOwnedPointer() = default;
+
+  CheckedThreadLocalOwnedPointer<T>(const CheckedThreadLocalOwnedPointer<T>&) =
+      delete;
+  CheckedThreadLocalOwnedPointer<T>& operator=(
+      const CheckedThreadLocalOwnedPointer<T>&) = delete;
+
+  ~CheckedThreadLocalOwnedPointer() {
+    Set(nullptr);
+
+    DCHECK_EQ(num_assigned_threads_.load(std::memory_order_relaxed), 0)
+        << "Memory leak: Must join all threads or release all associated "
+           "thread-local slots before ~ThreadLocalOwnedPointer";
+  }
+
+  T* Get() const {
+    PtrTracker* const ptr_tracker = static_cast<PtrTracker*>(slot_.Get());
+    return ptr_tracker ? ptr_tracker->ptr_.get() : nullptr;
+  }
+
+  std::unique_ptr<T> Set(std::unique_ptr<T> ptr) {
+    std::unique_ptr<T> existing_ptr;
+    auto existing_tracker = static_cast<PtrTracker*>(slot_.Get());
+    if (existing_tracker) {
+      existing_ptr = std::move(existing_tracker->ptr_);
+      delete existing_tracker;
+    }
+
+    if (ptr)
+      slot_.Set(new PtrTracker(this, std::move(ptr)));
+    else
+      slot_.Set(nullptr);
+
+    return existing_ptr;
+  }
+
+  T& operator*() { return *Get(); }
+
+ private:
+  struct PtrTracker {
+   public:
+    PtrTracker(CheckedThreadLocalOwnedPointer<T>* outer, std::unique_ptr<T> ptr)
+        : outer_(outer), ptr_(std::move(ptr)) {
+      outer_->num_assigned_threads_.fetch_add(1, std::memory_order_relaxed);
+    }
+
+    ~PtrTracker() {
+      outer_->num_assigned_threads_.fetch_sub(1, std::memory_order_relaxed);
+    }
+
+    const raw_ptr<CheckedThreadLocalOwnedPointer<T>> outer_;
+    std::unique_ptr<T> ptr_;
+  };
+
+  static void DeleteTlsPtr(void* ptr) { delete static_cast<PtrTracker*>(ptr); }
+
+  ThreadLocalStorage::Slot slot_{&DeleteTlsPtr};
+
+  std::atomic_int num_assigned_threads_{0};
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // DCHECK_IS_ON()
+
+#endif  // BASE_THREADING_THREAD_LOCAL_INTERNAL_H_
diff --git a/base/threading/thread_local_storage.cc b/base/threading/thread_local_storage.cc
index f1d5324..a0ae20d 100644
--- a/base/threading/thread_local_storage.cc
+++ b/base/threading/thread_local_storage.cc
@@ -1,14 +1,24 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/thread_local_storage.h"
 
-#include "base/atomicops.h"
-#include "base/logging.h"
+#include <algorithm>
+#include <atomic>
+#include <cstring>
+
+#include "base/check_op.h"
+#include "base/compiler_specific.h"
+#include "base/memory/raw_ptr_exclusion.h"
+#include "base/notreached.h"
 #include "base/synchronization/lock.h"
 #include "build/build_config.h"
-#include "starboard/memory.h"
+
+#if BUILDFLAG(IS_MAC) && defined(ARCH_CPU_X86_64)
+#include <pthread.h>
+#include <type_traits>
+#endif
 
 using base::internal::PlatformThreadLocalStorage;
 
@@ -67,20 +77,21 @@
 // Chromium consumers.
 
 // g_native_tls_key is the one native TLS that we use. It stores our table.
-#if defined(STARBOARD)
-base::subtle::AtomicWord g_native_tls_key =
-    reinterpret_cast<base::subtle::AtomicWord>(
-        PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES);
-#else
-base::subtle::Atomic32 g_native_tls_key =
-    PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES;
-#endif
 
-// The OS TLS slot has three states:
+std::atomic<PlatformThreadLocalStorage::TLSKey> g_native_tls_key{
+    PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES};
+
+// The OS TLS slot has the following states. The TLS slot's lower 2 bits contain
+// the state, the upper bits the TlsVectorEntry*.
 //   * kUninitialized: Any call to Slot::Get()/Set() will create the base
-//     per-thread TLS state. On POSIX, kUninitialized must be 0.
-//   * [Memory Address]: Raw pointer to the base per-thread TLS state.
-//   * kDestroyed: The base per-thread TLS state has been freed.
+//     per-thread TLS state. kUninitialized must be null.
+//   * kInUse: value has been created and is in use.
+//   * kDestroying: Set when the thread is exiting prior to deleting any of the
+//     values stored in the TlsVectorEntry*. This state is necessary so that
+//     sequence/task checks won't be done while in the process of deleting the
+//     tls entries (see comments in SequenceCheckerImpl for more details).
+//   * kDestroyed: All of the values in the vector have been deallocated and
+//     the TlsVectorEntry has been deleted.
 //
 // Final States:
 //   * Windows: kDestroyed. Windows does not iterate through the OS TLS to clean
@@ -108,15 +119,32 @@
 //       through the 2-pass destruction system again. Everything should just
 //       work (TM).
 
-// The consumers of kUninitialized and kDestroyed expect void*, since that's
-// what the API exposes on both POSIX and Windows.
-void* const kUninitialized = nullptr;
+// The state of the tls-entry.
+enum class TlsVectorState {
+  kUninitialized = 0,
 
-// A sentinel value to indicate that the TLS system has been destroyed.
-void* const kDestroyed = reinterpret_cast<void*>(1);
+  // In the process of destroying the entries in the vector.
+  kDestroying,
+
+  // All of the entries and the vector has been destroyed.
+  kDestroyed,
+
+  // The vector has been initialized and is in use.
+  kInUse,
+
+  kMaxValue = kInUse
+};
+
+// Bit-mask used to store TlsVectorState.
+constexpr uintptr_t kVectorStateBitMask = 3;
+static_assert(static_cast<int>(TlsVectorState::kMaxValue) <=
+                  kVectorStateBitMask,
+              "number of states must fit in header");
+static_assert(static_cast<int>(TlsVectorState::kUninitialized) == 0,
+              "kUninitialized must be null");
 
 // The maximum number of slots in our thread local storage stack.
-constexpr int kThreadLocalStorageSize = 256;
+constexpr size_t kThreadLocalStorageSize = 256;
 
 enum TlsStatus {
   FREE,
@@ -126,11 +154,18 @@
 struct TlsMetadata {
   TlsStatus status;
   base::ThreadLocalStorage::TLSDestructorFunc destructor;
+  // Incremented every time a slot is reused. Used to detect reuse of slots.
   uint32_t version;
+  // Tracks slot creation order. Used to destroy slots in the reverse order:
+  // from last created to first created.
+  uint32_t sequence_num;
 };
 
 struct TlsVectorEntry {
-  void* data;
+  // `data` is not a raw_ptr<...> for performance reasons (based on analysis of
+  // sampling profiler data and tab_search:top100:2020).
+  RAW_PTR_EXCLUSION void* data;
+
   uint32_t version;
 };
 
@@ -142,10 +177,78 @@
 }
 TlsMetadata g_tls_metadata[kThreadLocalStorageSize];
 size_t g_last_assigned_slot = 0;
+uint32_t g_sequence_num = 0;
 
 // The maximum number of times to try to clear slots by calling destructors.
 // Use pthread naming convention for clarity.
-constexpr int kMaxDestructorIterations = kThreadLocalStorageSize;
+constexpr size_t kMaxDestructorIterations = kThreadLocalStorageSize;
+
+// Sets the value and state of the vector.
+void SetTlsVectorValue(PlatformThreadLocalStorage::TLSKey key,
+                       TlsVectorEntry* tls_data,
+                       TlsVectorState state) {
+  DCHECK(tls_data || (state == TlsVectorState::kUninitialized) ||
+         (state == TlsVectorState::kDestroyed));
+  PlatformThreadLocalStorage::SetTLSValue(
+      key, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(tls_data) |
+                                   static_cast<uintptr_t>(state)));
+}
+
+// Returns the tls vector and current state from the raw tls value.
+TlsVectorState GetTlsVectorStateAndValue(void* tls_value,
+                                         TlsVectorEntry** entry = nullptr) {
+  if (entry) {
+    *entry = reinterpret_cast<TlsVectorEntry*>(
+        reinterpret_cast<uintptr_t>(tls_value) & ~kVectorStateBitMask);
+  }
+  return static_cast<TlsVectorState>(reinterpret_cast<uintptr_t>(tls_value) &
+                                     kVectorStateBitMask);
+}
+
+// Returns the tls vector and state using the tls key.
+TlsVectorState GetTlsVectorStateAndValue(PlatformThreadLocalStorage::TLSKey key,
+                                         TlsVectorEntry** entry = nullptr) {
+// Only on x86_64, the implementation is not stable on ARM64. For instance, in
+// macOS 11, the TPIDRRO_EL0 registers holds the CPU index in the low bits,
+// which is not the case in macOS 12. See libsyscall/os/tsd.h in XNU
+// (_os_tsd_get_direct() is used by pthread_getspecific() internally).
+#if BUILDFLAG(IS_MAC) && defined(ARCH_CPU_X86_64)
+  // On macOS, pthread_getspecific() is in libSystem, so a call to it has to go
+  // through PLT. However, and contrary to some other platforms, *all* TLS keys
+  // are in a static array in the thread structure. So they are *always* at a
+  // fixed offset from the segment register holding the thread structure
+  // address.
+  //
+  // We could use _pthread_getspecific_direct(), but it is not
+  // exported. However, on all macOS versions we support, the TLS array is at
+  // %gs. This is used in V8 and PartitionAlloc, and can also be seen by looking
+  // at pthread_getspecific() disassembly:
+  //
+  // libsystem_pthread.dylib`pthread_getspecific:
+  // libsystem_pthread.dylib[0x7ff800316099] <+0>: movq   %gs:(,%rdi,8), %rax
+  // libsystem_pthread.dylib[0x7ff8003160a2] <+9>: retq
+  //
+  // This function is essentially inlining the content of pthread_getspecific()
+  // here.
+  //
+  // Note that this likely ends up being even faster than thread_local for
+  // typical Chromium builds where the code is in a dynamic library. For the
+  // static executable case, this is likely equivalent.
+  static_assert(
+      std::is_same<PlatformThreadLocalStorage::TLSKey, pthread_key_t>::value,
+      "The special-case below assumes that the platform TLS implementation is "
+      "pthread.");
+
+  intptr_t platform_tls_value;
+  asm("movq %%gs:(,%1,8), %0;" : "=r"(platform_tls_value) : "r"(key));
+
+  return GetTlsVectorStateAndValue(reinterpret_cast<void*>(platform_tls_value),
+                                   entry);
+#else
+  return GetTlsVectorStateAndValue(PlatformThreadLocalStorage::GetTLSValue(key),
+                                   entry);
+#endif
+}
 
 // This function is called to initialize our entire Chromium TLS system.
 // It may be called very early, and we need to complete most all of the setup
@@ -155,8 +258,7 @@
 // require memory allocations.
 TlsVectorEntry* ConstructTlsVector() {
   PlatformThreadLocalStorage::TLSKey key =
-      reinterpret_cast<PlatformThreadLocalStorage::TLSKey>(
-          base::subtle::NoBarrier_Load(&g_native_tls_key));
+      g_native_tls_key.load(std::memory_order_relaxed);
   if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES) {
     CHECK(PlatformThreadLocalStorage::AllocTLS(&key));
 
@@ -174,22 +276,19 @@
     // Atomically test-and-set the tls_key. If the key is
     // TLS_KEY_OUT_OF_INDEXES, go ahead and set it. Otherwise, do nothing, as
     // another thread already did our dirty work.
-    if (PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES !=
-        reinterpret_cast<PlatformThreadLocalStorage::TLSKey>(
-            base::subtle::NoBarrier_CompareAndSwap(
-                &g_native_tls_key,
-                reinterpret_cast<base::subtle::AtomicWord>(
-                    PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES),
-                reinterpret_cast<base::subtle::AtomicWord>(key)))) {
+    PlatformThreadLocalStorage::TLSKey old_key =
+        PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES;
+    if (!g_native_tls_key.compare_exchange_strong(old_key, key,
+                                                  std::memory_order_relaxed,
+                                                  std::memory_order_relaxed)) {
       // We've been shortcut. Another thread replaced g_native_tls_key first so
       // we need to destroy our index and use the one the other thread got
       // first.
       PlatformThreadLocalStorage::FreeTLS(key);
-      key = reinterpret_cast<PlatformThreadLocalStorage::TLSKey>(
-          base::subtle::NoBarrier_Load(&g_native_tls_key));
+      key = g_native_tls_key.load(std::memory_order_relaxed);
     }
   }
-  CHECK_EQ(PlatformThreadLocalStorage::GetTLSValue(key), kUninitialized);
+  CHECK_EQ(GetTlsVectorStateAndValue(key), TlsVectorState::kUninitialized);
 
   // Some allocators, such as TCMalloc, make use of thread local storage. As a
   // result, any attempt to call new (or malloc) will lazily cause such a system
@@ -202,28 +301,16 @@
   TlsVectorEntry stack_allocated_tls_data[kThreadLocalStorageSize];
   memset(stack_allocated_tls_data, 0, sizeof(stack_allocated_tls_data));
   // Ensure that any rentrant calls change the temp version.
-  PlatformThreadLocalStorage::SetTLSValue(key, stack_allocated_tls_data);
+  SetTlsVectorValue(key, stack_allocated_tls_data, TlsVectorState::kInUse);
 
   // Allocate an array to store our data.
   TlsVectorEntry* tls_data = new TlsVectorEntry[kThreadLocalStorageSize];
-  memcpy(tls_data, stack_allocated_tls_data,
-               sizeof(stack_allocated_tls_data));
-  PlatformThreadLocalStorage::SetTLSValue(key, tls_data);
+  memcpy(tls_data, stack_allocated_tls_data, sizeof(stack_allocated_tls_data));
+  SetTlsVectorValue(key, tls_data, TlsVectorState::kInUse);
   return tls_data;
 }
 
 void OnThreadExitInternal(TlsVectorEntry* tls_data) {
-  // This branch is for POSIX, where this function is called twice. The first
-  // pass calls dtors and sets state to kDestroyed. The second pass sets
-  // kDestroyed to kUninitialized.
-  if (tls_data == kDestroyed) {
-    PlatformThreadLocalStorage::TLSKey key =
-      reinterpret_cast<PlatformThreadLocalStorage::TLSKey>(
-          base::subtle::NoBarrier_Load(&g_native_tls_key));
-    PlatformThreadLocalStorage::SetTLSValue(key, kUninitialized);
-    return;
-  }
-
   DCHECK(tls_data);
   // Some allocators, such as TCMalloc, use TLS. As a result, when a thread
   // terminates, one of the destructor calls we make may be to shut down an
@@ -235,33 +322,51 @@
   // we have called all g_tls_metadata destructors. (i.e., don't even call
   // delete[] after we're done with destructors.)
   TlsVectorEntry stack_allocated_tls_data[kThreadLocalStorageSize];
-  memcpy(stack_allocated_tls_data, tls_data,
-               sizeof(stack_allocated_tls_data));
+  memcpy(stack_allocated_tls_data, tls_data, sizeof(stack_allocated_tls_data));
   // Ensure that any re-entrant calls change the temp version.
   PlatformThreadLocalStorage::TLSKey key =
-      reinterpret_cast<PlatformThreadLocalStorage::TLSKey>(
-          base::subtle::NoBarrier_Load(&g_native_tls_key));
-  PlatformThreadLocalStorage::SetTLSValue(key, stack_allocated_tls_data);
+      g_native_tls_key.load(std::memory_order_relaxed);
+  SetTlsVectorValue(key, stack_allocated_tls_data, TlsVectorState::kDestroying);
   delete[] tls_data;  // Our last dependence on an allocator.
 
-  // Snapshot the TLS Metadata so we don't have to lock on every access.
-  TlsMetadata tls_metadata[kThreadLocalStorageSize];
-  {
-    base::AutoLock auto_lock(*GetTLSMetadataLock());
-    memcpy(tls_metadata, g_tls_metadata, sizeof(g_tls_metadata));
-  }
-
-  int remaining_attempts = kMaxDestructorIterations;
+  size_t remaining_attempts = kMaxDestructorIterations + 1;
   bool need_to_scan_destructors = true;
   while (need_to_scan_destructors) {
     need_to_scan_destructors = false;
-    // Try to destroy the first-created-slot (which is slot 1) in our last
-    // destructor call. That user was able to function, and define a slot with
-    // no other services running, so perhaps it is a basic service (like an
-    // allocator) and should also be destroyed last. If we get the order wrong,
-    // then we'll iterate several more times, so it is really not that critical
-    // (but it might help).
-    for (int slot = 0; slot < kThreadLocalStorageSize ; ++slot) {
+
+    // Snapshot the TLS Metadata so we don't have to lock on every access.
+    TlsMetadata tls_metadata[kThreadLocalStorageSize];
+    {
+      base::AutoLock auto_lock(*GetTLSMetadataLock());
+      memcpy(tls_metadata, g_tls_metadata, sizeof(g_tls_metadata));
+    }
+
+    // We destroy slots in reverse order (i.e. destroy the first-created slot
+    // last), for the following reasons:
+    // 1) Slots that are created early belong to basic services (like an
+    // allocator) and might have to be recreated by destructors of other
+    // services. So we save iterations here by destroying them last.
+    // 2) Perfetto tracing service allocates a slot early and relies on it to
+    // keep emitting trace events while destructors of other slots are called,
+    // so it's important to keep it live to avoid use-after-free errors.
+    // To achieve this, we sort all slots in the order of decreasing sequence
+    // numbers.
+    struct OrderedSlot {
+      uint32_t sequence_num;
+      uint16_t slot;
+    } slot_destruction_order[kThreadLocalStorageSize];
+    for (uint16_t i = 0; i < kThreadLocalStorageSize; ++i) {
+      slot_destruction_order[i].sequence_num = tls_metadata[i].sequence_num;
+      slot_destruction_order[i].slot = i;
+    }
+    std::sort(std::begin(slot_destruction_order),
+              std::end(slot_destruction_order),
+              [](const OrderedSlot& s1, const OrderedSlot& s2) {
+                return s1.sequence_num > s2.sequence_num;
+              });
+
+    for (const auto& ordered_slot : slot_destruction_order) {
+      size_t slot = ordered_slot.slot;
       void* tls_value = stack_allocated_tls_data[slot].data;
       if (!tls_value || tls_metadata[slot].status == TlsStatus::FREE ||
           stack_allocated_tls_data[slot].version != tls_metadata[slot].version)
@@ -278,14 +383,15 @@
       // vector again. This is a pthread standard.
       need_to_scan_destructors = true;
     }
-    if (--remaining_attempts <= 0) {
+
+    if (--remaining_attempts == 0) {
       NOTREACHED();  // Destructors might not have been called.
       break;
     }
   }
 
   // Remove our stack allocated vector.
-  PlatformThreadLocalStorage::SetTLSValue(key, kDestroyed);
+  SetTlsVectorValue(key, nullptr, TlsVectorState::kDestroyed);
 }
 
 }  // namespace
@@ -294,58 +400,67 @@
 
 namespace internal {
 
-#if defined(STARBOARD)
-void PlatformThreadLocalStorage::OnThreadExit(void* value) {
-  OnThreadExitInternal(static_cast<TlsVectorEntry*>(value));
-}
-#else
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 void PlatformThreadLocalStorage::OnThreadExit() {
   PlatformThreadLocalStorage::TLSKey key =
-      base::subtle::NoBarrier_Load(&g_native_tls_key);
+      g_native_tls_key.load(std::memory_order_relaxed);
   if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES)
     return;
-  void *tls_data = GetTLSValue(key);
+  TlsVectorEntry* tls_vector = nullptr;
+  const TlsVectorState state = GetTlsVectorStateAndValue(key, &tls_vector);
 
   // On Windows, thread destruction callbacks are only invoked once per module,
   // so there should be no way that this could be invoked twice.
-  DCHECK_NE(tls_data, kDestroyed);
+  DCHECK_NE(state, TlsVectorState::kDestroyed);
 
   // Maybe we have never initialized TLS for this thread.
-  if (tls_data == kUninitialized)
+  if (state == TlsVectorState::kUninitialized)
     return;
-  OnThreadExitInternal(static_cast<TlsVectorEntry*>(tls_data));
+  OnThreadExitInternal(tls_vector);
 }
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || defined(STARBOARD)
 void PlatformThreadLocalStorage::OnThreadExit(void* value) {
-  OnThreadExitInternal(static_cast<TlsVectorEntry*>(value));
+  // On posix this function may be called twice. The first pass calls dtors and
+  // sets state to kDestroyed. The second pass sets kDestroyed to
+  // kUninitialized.
+  TlsVectorEntry* tls_vector = nullptr;
+  const TlsVectorState state = GetTlsVectorStateAndValue(value, &tls_vector);
+  if (state == TlsVectorState::kDestroyed) {
+    PlatformThreadLocalStorage::TLSKey key =
+        g_native_tls_key.load(std::memory_order_relaxed);
+    SetTlsVectorValue(key, nullptr, TlsVectorState::kUninitialized);
+    return;
+  }
+
+  OnThreadExitInternal(tls_vector);
 }
-#endif  // defined(OS_WIN)
-#endif
+#endif  // BUILDFLAG(IS_WIN)
+
 }  // namespace internal
 
+// static
 bool ThreadLocalStorage::HasBeenDestroyed() {
   PlatformThreadLocalStorage::TLSKey key =
-      reinterpret_cast<PlatformThreadLocalStorage::TLSKey>(
-      base::subtle::NoBarrier_Load(&g_native_tls_key));
+      g_native_tls_key.load(std::memory_order_relaxed);
   if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES)
     return false;
-  return PlatformThreadLocalStorage::GetTLSValue(key) == kDestroyed;
+  const TlsVectorState state = GetTlsVectorStateAndValue(key);
+  return state == TlsVectorState::kDestroying ||
+         state == TlsVectorState::kDestroyed;
 }
 
 void ThreadLocalStorage::Slot::Initialize(TLSDestructorFunc destructor) {
   PlatformThreadLocalStorage::TLSKey key =
-      reinterpret_cast<PlatformThreadLocalStorage::TLSKey>(
-          base::subtle::NoBarrier_Load(&g_native_tls_key));
+      g_native_tls_key.load(std::memory_order_relaxed);
   if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES ||
-      PlatformThreadLocalStorage::GetTLSValue(key) == kUninitialized) {
+      GetTlsVectorStateAndValue(key) == TlsVectorState::kUninitialized) {
     ConstructTlsVector();
   }
 
   // Grab a new slot.
   {
     base::AutoLock auto_lock(*GetTLSMetadataLock());
-    for (int i = 0; i < kThreadLocalStorageSize; ++i) {
+    for (size_t i = 0; i < kThreadLocalStorageSize; ++i) {
       // Tracking the last assigned slot is an attempt to find the next
       // available slot within one iteration. Under normal usage, slots remain
       // in use for the lifetime of the process (otherwise before we reclaimed
@@ -356,6 +471,7 @@
       if (g_tls_metadata[slot_candidate].status == TlsStatus::FREE) {
         g_tls_metadata[slot_candidate].status = TlsStatus::IN_USE;
         g_tls_metadata[slot_candidate].destructor = destructor;
+        g_tls_metadata[slot_candidate].sequence_num = ++g_sequence_num;
         g_last_assigned_slot = slot_candidate;
         DCHECK_EQ(kInvalidSlotValue, slot_);
         slot_ = slot_candidate;
@@ -364,12 +480,10 @@
       }
     }
   }
-  CHECK_NE(slot_, kInvalidSlotValue);
   CHECK_LT(slot_, kThreadLocalStorageSize);
 }
 
 void ThreadLocalStorage::Slot::Free() {
-  DCHECK_NE(slot_, kInvalidSlotValue);
   DCHECK_LT(slot_, kThreadLocalStorageSize);
   {
     base::AutoLock auto_lock(*GetTLSMetadataLock());
@@ -381,14 +495,12 @@
 }
 
 void* ThreadLocalStorage::Slot::Get() const {
-  TlsVectorEntry* tls_data = static_cast<TlsVectorEntry*>(
-      PlatformThreadLocalStorage::GetTLSValue(
-        reinterpret_cast<PlatformThreadLocalStorage::TLSKey>(
-          base::subtle::NoBarrier_Load(&g_native_tls_key))));
-  DCHECK_NE(tls_data, kDestroyed);
+  TlsVectorEntry* tls_data = nullptr;
+  const TlsVectorState state = GetTlsVectorStateAndValue(
+      g_native_tls_key.load(std::memory_order_relaxed), &tls_data);
+  DCHECK_NE(state, TlsVectorState::kDestroyed);
   if (!tls_data)
     return nullptr;
-  DCHECK_NE(slot_, kInvalidSlotValue);
   DCHECK_LT(slot_, kThreadLocalStorageSize);
   // Version mismatches means this slot was previously freed.
   if (tls_data[slot_].version != version_)
@@ -397,14 +509,15 @@
 }
 
 void ThreadLocalStorage::Slot::Set(void* value) {
-  TlsVectorEntry* tls_data = static_cast<TlsVectorEntry*>(
-      PlatformThreadLocalStorage::GetTLSValue(
-        reinterpret_cast<PlatformThreadLocalStorage::TLSKey>(
-          base::subtle::NoBarrier_Load(&g_native_tls_key))));
-  DCHECK_NE(tls_data, kDestroyed);
-  if (!tls_data)
+  TlsVectorEntry* tls_data = nullptr;
+  const TlsVectorState state = GetTlsVectorStateAndValue(
+      g_native_tls_key.load(std::memory_order_relaxed), &tls_data);
+  DCHECK_NE(state, TlsVectorState::kDestroyed);
+  if (UNLIKELY(!tls_data)) {
+    if (!value)
+      return;
     tls_data = ConstructTlsVector();
-  DCHECK_NE(slot_, kInvalidSlotValue);
+  }
   DCHECK_LT(slot_, kThreadLocalStorageSize);
   tls_data[slot_].data = value;
   tls_data[slot_].version = version_;
diff --git a/base/threading/thread_local_storage.h b/base/threading/thread_local_storage.h
index 128ffd3..dfe8383 100644
--- a/base/threading/thread_local_storage.h
+++ b/base/threading/thread_local_storage.h
@@ -1,38 +1,27 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef BASE_THREADING_THREAD_LOCAL_STORAGE_H_
 #define BASE_THREADING_THREAD_LOCAL_STORAGE_H_
 
-#include "base/atomicops.h"
+#include <stdint.h>
+
 #include "base/base_export.h"
-#include "base/macros.h"
 #include "build/build_config.h"
 
 #if defined(STARBOARD)
-#include "starboard/thread.h"
-#else
-#if defined(OS_WIN)
-#include "base/win/windows_types.h"
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
 #include <pthread.h>
-
-#include "starboard/types.h"
+#elif BUILDFLAG(IS_WIN)
+#include "base/win/windows_types.h"
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
+#include <pthread.h>
 #endif
-#endif
-
-namespace heap_profiling {
-class ScopedAllowAlloc;
-class ScopedAllowRealloc;
-}  // namespace heap_profiling
-
-namespace ui {
-class TLSDestructionCheckerForX11;
-}
 
 namespace base {
 
+class SamplingHeapProfiler;
+
 namespace debug {
 class GlobalActivityTracker;
 }  // namespace debug
@@ -48,21 +37,14 @@
 // WARNING: You should *NOT* use this class directly.
 // PlatformThreadLocalStorage is a low-level abstraction of the OS's TLS
 // interface. Instead, you should use one of the following:
-// * ThreadLocalBoolean (from thread_local.h) for booleans.
-// * ThreadLocalPointer (from thread_local.h) for pointers.
+// * ThreadLocalOwnedPointer (from thread_local.h) for unique_ptrs.
 // * ThreadLocalStorage::StaticSlot/Slot for more direct control of the slot.
 class BASE_EXPORT PlatformThreadLocalStorage {
  public:
-
-#if defined(STARBOARD)
-  typedef SbThreadLocalKey TLSKey;
-  static constexpr SbThreadLocalKey TLS_KEY_OUT_OF_INDEXES =
-      kSbThreadLocalKeyInvalid;
-#else
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN) && !defined(STARBOARD)
   typedef unsigned long TLSKey;
   enum : unsigned { TLS_KEY_OUT_OF_INDEXES = TLS_OUT_OF_INDEXES };
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || defined(STARBOARD)
   typedef pthread_key_t TLSKey;
   // The following is a "reserved key" which is used in our generic Chromium
   // ThreadLocalStorage implementation.  We expect that an OS will not return
@@ -70,7 +52,6 @@
   // will just request another key.
   enum { TLS_KEY_OUT_OF_INDEXES = 0x7FFFFFFF };
 #endif
-#endif
 
   // The following methods need to be supported on each OS platform, so that
   // the Chromium ThreadLocalStore functionality can be constructed.
@@ -86,14 +67,11 @@
   static void FreeTLS(TLSKey key);
   static void SetTLSValue(TLSKey key, void* value);
   static void* GetTLSValue(TLSKey key) {
-#if defined(STARBOARD)
-    return SbThreadGetLocalValue(key);
-#else
-#if defined(OS_WIN)
-    return TlsGetValue(key);
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
     return pthread_getspecific(key);
-#endif
+#if BUILDFLAG(IS_WIN) && !defined(STARBOARD)
+    return TlsGetValue(key);
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) || defined(STARBOARD)
+    return pthread_getspecific(key);
 #endif
   }
 
@@ -107,18 +85,16 @@
   // destroyed.
 #if defined(STARBOARD)
   static void OnThreadExit(void* value);
-#else
-#if defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
   // Since Windows which doesn't support TLS destructor, the implementation
   // should use GetTLSValue() to retrieve the value of TLS slot.
   static void OnThreadExit();
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   // |Value| is the data stored in TLS slot, The implementation can't use
   // GetTLSValue() to retrieve the value of slot as it has already been reset
   // in Posix.
   static void OnThreadExit(void* value);
 #endif
-#endif
 };
 
 }  // namespace internal
@@ -146,6 +122,10 @@
     // |destructor| is a pointer to a function to perform per-thread cleanup of
     // this object.  If set to nullptr, no cleanup is done for this TLS slot.
     explicit Slot(TLSDestructorFunc destructor = nullptr);
+
+    Slot(const Slot&) = delete;
+    Slot& operator=(const Slot&) = delete;
+
     // If a destructor was set for this slot, removes the destructor so that
     // remaining threads exiting will not free data.
     ~Slot();
@@ -162,31 +142,31 @@
     void Initialize(TLSDestructorFunc destructor);
     void Free();
 
-    static constexpr int kInvalidSlotValue = -1;
-    int slot_ = kInvalidSlotValue;
+    static constexpr size_t kInvalidSlotValue = static_cast<size_t>(-1);
+    size_t slot_ = kInvalidSlotValue;
     uint32_t version_ = 0;
-
-    DISALLOW_COPY_AND_ASSIGN(Slot);
   };
 
+  ThreadLocalStorage(const ThreadLocalStorage&) = delete;
+  ThreadLocalStorage& operator=(const ThreadLocalStorage&) = delete;
+
  private:
   // In most cases, most callers should not need access to HasBeenDestroyed().
   // If you are working in code that runs during thread destruction, contact the
   // base OWNERs for advice and then make a friend request.
   //
-  // Returns |true| if Chrome's implementation of TLS has been destroyed during
-  // thread destruction. Attempting to call Slot::Get() during destruction is
-  // disallowed and will hit a DCHECK. Any code that relies on TLS during thread
-  // destruction must first check this method before calling Slot::Get().
-  friend class base::internal::ThreadLocalStorageTestInternal;
-  friend class base::trace_event::MallocDumpProvider;
+  // Returns |true| if Chrome's implementation of TLS is being or has been
+  // destroyed during thread destruction. Attempting to call Slot::Get() during
+  // destruction is disallowed and will hit a DCHECK. Any code that relies on
+  // TLS during thread destruction must first check this method before calling
+  // Slot::Get().
+  friend class SequenceCheckerImpl;
+  friend class SamplingHeapProfiler;
+  friend class ThreadCheckerImpl;
+  friend class internal::ThreadLocalStorageTestInternal;
+  friend class trace_event::MallocDumpProvider;
   friend class debug::GlobalActivityTracker;
-  friend class heap_profiling::ScopedAllowAlloc;
-  friend class heap_profiling::ScopedAllowRealloc;
-  friend class ui::TLSDestructionCheckerForX11;
   static bool HasBeenDestroyed();
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorage);
 };
 
 }  // namespace base
diff --git a/base/threading/thread_local_storage_perftest.cc b/base/threading/thread_local_storage_perftest.cc
new file mode 100644
index 0000000..9f5d1c0
--- /dev/null
+++ b/base/threading/thread_local_storage_perftest.cc
@@ -0,0 +1,256 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <memory>
+#include <vector>
+
+#include "base/barrier_closure.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/functional/callback_helpers.h"
+#include "base/memory/raw_ptr.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/bind.h"
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread_local_storage.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_result_reporter.h"
+
+#if BUILDFLAG(IS_WIN)
+#include <windows.h>
+#include "base/win/windows_types.h"
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
+#include <pthread.h>
+#endif
+
+namespace base {
+namespace internal {
+
+namespace {
+
+constexpr size_t kCount = 5000000;
+
+constexpr char kMetricPrefixThreadLocalStorage[] = "ThreadLocalStorage.";
+constexpr char kMetricBaseRead[] = "read";
+constexpr char kMetricBaseWrite[] = "write";
+constexpr char kMetricBaseReadWrite[] = "read_write";
+constexpr char kMetricSuffixThroughput[] = "_throughput";
+constexpr char kMetricSuffixOperationTime[] = "_operation_time";
+constexpr char kStoryBaseTLS[] = "thread_local_storage";
+#if BUILDFLAG(IS_WIN)
+constexpr char kStoryBasePlatformFLS[] = "platform_fiber_local_storage";
+#endif  // BUILDFLAG(IS_WIN)
+constexpr char kStoryBasePlatformTLS[] = "platform_thread_local_storage";
+constexpr char kStoryBaseCPPTLS[] = "c++_platform_thread_local_storage";
+constexpr char kStorySuffixFourThreads[] = "_4_threads";
+
+perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
+  perf_test::PerfResultReporter reporter(kMetricPrefixThreadLocalStorage,
+                                         story_name);
+  reporter.RegisterImportantMetric(
+      std::string(kMetricBaseRead) + kMetricSuffixThroughput, "runs/s");
+  reporter.RegisterImportantMetric(
+      std::string(kMetricBaseRead) + kMetricSuffixOperationTime, "ns");
+  reporter.RegisterImportantMetric(
+      std::string(kMetricBaseWrite) + kMetricSuffixThroughput, "runs/s");
+  reporter.RegisterImportantMetric(
+      std::string(kMetricBaseWrite) + kMetricSuffixOperationTime, "ns");
+  reporter.RegisterImportantMetric(
+      std::string(kMetricBaseReadWrite) + kMetricSuffixThroughput, "runs/s");
+  reporter.RegisterImportantMetric(
+      std::string(kMetricBaseReadWrite) + kMetricSuffixOperationTime, "ns");
+  return reporter;
+}
+
+// A thread that waits for the caller to signal an event before proceeding to
+// call action.Run().
+class TLSThread : public SimpleThread {
+ public:
+  // Creates a PostingThread that waits on |start_event| before calling
+  // action.Run().
+  TLSThread(WaitableEvent* start_event,
+            base::OnceClosure action,
+            base::OnceClosure completion)
+      : SimpleThread("TLSThread"),
+        start_event_(start_event),
+        action_(std::move(action)),
+        completion_(std::move(completion)) {
+    Start();
+  }
+
+  TLSThread(const TLSThread&) = delete;
+  TLSThread& operator=(const TLSThread&) = delete;
+
+  void Run() override {
+    start_event_->Wait();
+    std::move(action_).Run();
+    std::move(completion_).Run();
+  }
+
+ private:
+  const raw_ptr<WaitableEvent> start_event_;
+  base::OnceClosure action_;
+  base::OnceClosure completion_;
+};
+
+class ThreadLocalStoragePerfTest : public testing::Test {
+ public:
+  ThreadLocalStoragePerfTest(const ThreadLocalStoragePerfTest&) = delete;
+  ThreadLocalStoragePerfTest& operator=(const ThreadLocalStoragePerfTest&) =
+      delete;
+
+ protected:
+  ThreadLocalStoragePerfTest() = default;
+  ~ThreadLocalStoragePerfTest() override = default;
+
+  template <class Read, class Write>
+  void Benchmark(const std::string& story_name,
+                 Read read,
+                 Write write,
+                 size_t num_operation,
+                 size_t num_threads) {
+    write(2);
+
+    BenchmarkImpl(kMetricBaseRead, story_name,
+                  base::BindLambdaForTesting([&]() {
+                    volatile intptr_t total = 0;
+                    for (size_t i = 0; i < num_operation; ++i)
+                      total = total + read();
+                  }),
+                  num_operation, num_threads);
+
+    BenchmarkImpl(kMetricBaseWrite, story_name,
+                  base::BindLambdaForTesting([&]() {
+                    for (size_t i = 0; i < num_operation; ++i)
+                      write(i);
+                  }),
+                  num_operation, num_threads);
+
+    BenchmarkImpl(kMetricBaseReadWrite, story_name,
+                  base::BindLambdaForTesting([&]() {
+                    for (size_t i = 0; i < num_operation; ++i)
+                      write(read() + 1);
+                  }),
+                  num_operation, num_threads);
+  }
+
+  void BenchmarkImpl(const std::string& metric_base,
+                     const std::string& story_name,
+                     base::RepeatingClosure action,
+                     size_t num_operation,
+                     size_t num_threads) {
+    WaitableEvent start_thread;
+    WaitableEvent complete_thread;
+
+    base::RepeatingClosure done = BarrierClosure(
+        num_threads,
+        base::BindLambdaForTesting([&]() { complete_thread.Signal(); }));
+
+    std::vector<std::unique_ptr<TLSThread>> threads;
+    for (size_t i = 0; i < num_threads; ++i) {
+      threads.emplace_back(
+          std::make_unique<TLSThread>(&start_thread, action, done));
+    }
+
+    TimeTicks operation_start = TimeTicks::Now();
+    start_thread.Signal();
+    complete_thread.Wait();
+    TimeDelta operation_duration = TimeTicks::Now() - operation_start;
+
+    for (auto& thread : threads)
+      thread->Join();
+
+    auto reporter = SetUpReporter(story_name);
+    reporter.AddResult(metric_base + kMetricSuffixThroughput,
+                       num_operation / operation_duration.InSecondsF());
+    size_t nanos_per_operation =
+        operation_duration.InNanoseconds() / num_operation;
+    reporter.AddResult(metric_base + kMetricSuffixOperationTime,
+                       nanos_per_operation);
+  }
+};
+
+}  // namespace
+
+TEST_F(ThreadLocalStoragePerfTest, ThreadLocalStorage) {
+  ThreadLocalStorage::Slot tls;
+  auto read = [&]() { return reinterpret_cast<intptr_t>(tls.Get()); };
+  auto write = [&](intptr_t value) { tls.Set(reinterpret_cast<void*>(value)); };
+
+  Benchmark(kStoryBaseTLS, read, write, 10000000, 1);
+  Benchmark(std::string(kStoryBaseTLS) + kStorySuffixFourThreads, read, write,
+            kCount, 4);
+}
+
+#if BUILDFLAG(IS_WIN)
+
+void WINAPI destroy(void*) {}
+
+TEST_F(ThreadLocalStoragePerfTest, PlatformFls) {
+  DWORD key = FlsAlloc(destroy);
+  ASSERT_NE(PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key);
+
+  auto read = [&]() { return reinterpret_cast<intptr_t>(FlsGetValue(key)); };
+  auto write = [&](intptr_t value) {
+    FlsSetValue(key, reinterpret_cast<void*>(value));
+  };
+
+  Benchmark(kStoryBasePlatformFLS, read, write, 10000000, 1);
+  Benchmark(std::string(kStoryBasePlatformFLS) + kStorySuffixFourThreads, read,
+            write, kCount, 4);
+}
+
+TEST_F(ThreadLocalStoragePerfTest, PlatformTls) {
+  DWORD key = TlsAlloc();
+  ASSERT_NE(PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key);
+
+  auto read = [&]() { return reinterpret_cast<intptr_t>(TlsGetValue(key)); };
+  auto write = [&](intptr_t value) {
+    TlsSetValue(key, reinterpret_cast<void*>(value));
+  };
+
+  Benchmark(kStoryBasePlatformTLS, read, write, 10000000, 1);
+  Benchmark(std::string(kStoryBasePlatformTLS) + kStorySuffixFourThreads, read,
+            write, kCount, 4);
+}
+
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
+
+TEST_F(ThreadLocalStoragePerfTest, PlatformTls) {
+  pthread_key_t key;
+  ASSERT_FALSE(pthread_key_create(&key, [](void*) {}));
+  ASSERT_NE(PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key);
+
+  auto read = [&]() {
+    return reinterpret_cast<intptr_t>(pthread_getspecific(key));
+  };
+  auto write = [&](intptr_t value) {
+    pthread_setspecific(key, reinterpret_cast<void*>(value));
+  };
+
+  Benchmark(kStoryBasePlatformTLS, read, write, 10000000, 1);
+  Benchmark(std::string(kStoryBasePlatformTLS) + kStorySuffixFourThreads, read,
+            write, kCount, 4);
+}
+
+#endif
+
+TEST_F(ThreadLocalStoragePerfTest, Cpp11Tls) {
+  thread_local intptr_t thread_local_variable;
+
+  auto read = [&]() { return thread_local_variable; };
+  auto write = [&](intptr_t value) {
+    reinterpret_cast<volatile intptr_t*>(&thread_local_variable)[0] = value;
+  };
+
+  Benchmark(kStoryBaseCPPTLS, read, write, 10000000, 1);
+  Benchmark(std::string(kStoryBaseCPPTLS) + kStorySuffixFourThreads, read,
+            write, kCount, 4);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/threading/thread_local_storage_posix.cc b/base/threading/thread_local_storage_posix.cc
index 89edeee..6469b10 100644
--- a/base/threading/thread_local_storage_posix.cc
+++ b/base/threading/thread_local_storage_posix.cc
@@ -1,10 +1,10 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/thread_local_storage.h"
 
-#include "base/logging.h"
+#include "base/check_op.h"
 
 namespace base {
 
diff --git a/base/threading/thread_local_storage_starboard.cc b/base/threading/thread_local_storage_starboard.cc
index 063b8ad..e9e65b2 100644
--- a/base/threading/thread_local_storage_starboard.cc
+++ b/base/threading/thread_local_storage_starboard.cc
@@ -14,7 +14,7 @@
 
 #include "base/threading/thread_local_storage.h"
 
-#include "base/logging.h"
+#include "base/notreached.h"
 
 namespace base {
 
@@ -22,9 +22,8 @@
 
 // static
 bool PlatformThreadLocalStorage::AllocTLS(TLSKey* key) {
-  *key = SbThreadCreateLocalKey(
-      base::internal::PlatformThreadLocalStorage::OnThreadExit);
-  if (!SbThreadIsValidLocalKey(*key)) {
+  int res = pthread_key_create(key, base::internal::PlatformThreadLocalStorage::OnThreadExit);
+  if (res != 0) {
     NOTREACHED();
     return false;
   }
@@ -34,12 +33,12 @@
 
 // static
 void PlatformThreadLocalStorage::FreeTLS(TLSKey key) {
-  SbThreadDestroyLocalKey(key);
+  pthread_key_delete(key);
 }
 
 // static
 void PlatformThreadLocalStorage::SetTLSValue(TLSKey key, void* value) {
-  if (!SbThreadSetLocalValue(key, value)) {
+  if (pthread_setspecific(key, value) != 0) {
     NOTREACHED();
   }
 }
diff --git a/base/threading/thread_local_storage_unittest.cc b/base/threading/thread_local_storage_unittest.cc
index e0b9794..b01ba4b 100644
--- a/base/threading/thread_local_storage_unittest.cc
+++ b/base/threading/thread_local_storage_unittest.cc
@@ -1,22 +1,19 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/thread_local_storage.h"
 
-#if defined(OS_WIN)
-#include <windows.h>
-#include <process.h>
-#endif
-
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
 #include "base/no_destructor.h"
 #include "base/threading/simple_thread.h"
 #include "build/build_config.h"
-#include "starboard/types.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
+#include <windows.h>
+
+#include <process.h>
 // Ignore warnings about ptr->int conversions that we use when
 // storing ints into ThreadLocalStorage.
 #pragma warning(disable : 4311 4312)
@@ -24,7 +21,7 @@
 
 namespace base {
 
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
 
 namespace internal {
 
@@ -38,7 +35,7 @@
 
 }  // namespace internal
 
-#endif  // defined(OS_POSIX)
+#endif  // BUILDFLAG(IS_POSIX)
 
 namespace {
 
@@ -60,6 +57,9 @@
   explicit ThreadLocalStorageRunner(int* tls_value_ptr)
       : tls_value_ptr_(tls_value_ptr) {}
 
+  ThreadLocalStorageRunner(const ThreadLocalStorageRunner&) = delete;
+  ThreadLocalStorageRunner& operator=(const ThreadLocalStorageRunner&) = delete;
+
   ~ThreadLocalStorageRunner() override = default;
 
   void Run() override {
@@ -79,15 +79,14 @@
   }
 
  private:
-  int* tls_value_ptr_;
-  DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorageRunner);
+  raw_ptr<int> tls_value_ptr_;
 };
 
 
 void ThreadLocalStorageCleanup(void *value) {
-  int *ptr = reinterpret_cast<int*>(value);
+  int *ptr = static_cast<int*>(value);
   // Destructors should never be called with a NULL.
-  ASSERT_NE(reinterpret_cast<int*>(NULL), ptr);
+  ASSERT_NE(nullptr, ptr);
   if (*ptr == kFinalTlsValue)
     return;  // We've been called enough times.
   ASSERT_LT(kFinalTlsValue, *ptr);
@@ -97,7 +96,7 @@
   TLSSlot().Set(value);
 }
 
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX) && !defined(STARBOARD)
 constexpr intptr_t kDummyValue = 0xABCD;
 constexpr size_t kKeyCount = 20;
 
@@ -108,6 +107,10 @@
  public:
   UseTLSDuringDestructionRunner() = default;
 
+  UseTLSDuringDestructionRunner(const UseTLSDuringDestructionRunner&) = delete;
+  UseTLSDuringDestructionRunner& operator=(
+      const UseTLSDuringDestructionRunner&) = delete;
+
   // The order in which pthread_key destructors are called is not well defined.
   // Hopefully, by creating 10 both before and after initializing TLS on the
   // thread, at least 1 will be called after TLS destruction.
@@ -135,7 +138,7 @@
  private:
   struct TLSState {
     pthread_key_t key;
-    bool* teardown_works_correctly;
+    raw_ptr<bool> teardown_works_correctly;
   };
 
   // The POSIX TLS destruction API takes as input a single C-function, which is
@@ -181,8 +184,6 @@
   static base::ThreadLocalStorage::Slot slot_;
   bool teardown_works_correctly_ = false;
   TLSState tls_states_[kKeyCount];
-
-  DISALLOW_COPY_AND_ASSIGN(UseTLSDuringDestructionRunner);
 };
 
 base::ThreadLocalStorage::Slot UseTLSDuringDestructionRunner::slot_;
@@ -194,7 +195,70 @@
   return nullptr;
 }
 
-#endif  // defined(OS_POSIX)
+#endif  // BUILDFLAG(IS_POSIX)
+
+class TlsDestructionOrderRunner : public DelegateSimpleThread::Delegate {
+ public:
+  // The runner creates |n_slots| static slots that will be destroyed at
+  // thread exit, with |spacing| empty slots between them. This allows us to
+  // test that the destruction order is correct regardless of the actual slot
+  // indices in the global array.
+  TlsDestructionOrderRunner(int n_slots, int spacing)
+      : n_slots_(n_slots), spacing_(spacing) {}
+
+  void Run() override {
+    destructor_calls.clear();
+    for (int slot = 1; slot < n_slots_ + 1; ++slot) {
+      for (int i = 0; i < spacing_; ++i) {
+        ThreadLocalStorage::Slot empty_slot(nullptr);
+      }
+      NewStaticTLSSlot(slot);
+    }
+  }
+
+  static std::vector<int> destructor_calls;
+
+ private:
+  ThreadLocalStorage::Slot& NewStaticTLSSlot(int n) {
+    NoDestructor<ThreadLocalStorage::Slot> slot(
+        &TlsDestructionOrderRunner::Destructor);
+    slot->Set(reinterpret_cast<void*>(n));
+    return *slot;
+  }
+
+  static void Destructor(void* value) {
+    int n = reinterpret_cast<intptr_t>(value);
+    destructor_calls.push_back(n);
+  }
+
+  int n_slots_;
+  int spacing_;
+};
+std::vector<int> TlsDestructionOrderRunner::destructor_calls;
+
+class CreateDuringDestructionRunner : public DelegateSimpleThread::Delegate {
+ public:
+  void Run() override {
+    second_destructor_called = false;
+    NoDestructor<ThreadLocalStorage::Slot> slot(
+        &CreateDuringDestructionRunner::FirstDestructor);
+    slot->Set(reinterpret_cast<void*>(123));
+  }
+
+  static bool second_destructor_called;
+
+ private:
+  // The first destructor allocates another TLS slot, which should also be
+  // destroyed eventually.
+  static void FirstDestructor(void*) {
+    NoDestructor<ThreadLocalStorage::Slot> slot(
+        &CreateDuringDestructionRunner::SecondDestructor);
+    slot->Set(reinterpret_cast<void*>(234));
+  }
+
+  static void SecondDestructor(void*) { second_destructor_called = true; }
+};
+bool CreateDuringDestructionRunner::second_destructor_called = false;
 
 }  // namespace
 
@@ -205,16 +269,12 @@
   EXPECT_EQ(value, 123);
 }
 
-#if defined(THREAD_SANITIZER) || \
-    (defined(OS_WIN) && defined(ARCH_CPU_X86_64) && !defined(NDEBUG))
+#if defined(THREAD_SANITIZER)
 // Do not run the test under ThreadSanitizer. Because this test iterates its
 // own TSD destructor for the maximum possible number of times, TSan can't jump
 // in after the last destructor invocation, therefore the destructor remains
 // unsynchronized with the following users of the same TSD slot. This results
 // in race reports between the destructor and functions in other tests.
-//
-// It is disabled on Win x64 with incremental linking (i.e. "Debug") pending
-// resolution of http://crbug.com/251251.
 #define MAYBE_TLSDestructors DISABLED_TLSDestructors
 #else
 #define MAYBE_TLSDestructors TLSDestructors
@@ -248,8 +308,6 @@
   }
 }
 
-// MSVC doesn't allow casting 32bit address to pointer.
-#if !SB_IS(COMPILER_MSVC)
 TEST(ThreadLocalStorageTest, TLSReclaim) {
   // Creates and destroys many TLS slots and ensures they all zero-inited.
   for (int i = 0; i < 1000; ++i) {
@@ -259,9 +317,8 @@
     EXPECT_EQ(reinterpret_cast<void*>(0xBAADF00D), slot.Get());
   }
 }
-#endif
 
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX) && !defined(STARBOARD)
 // Unlike POSIX, Windows does not iterate through the OS TLS to cleanup any
 // values there. Instead a per-module thread destruction function is called.
 // However, it is not possible to perform a check after this point (as the code
@@ -277,6 +334,33 @@
 
   EXPECT_TRUE(runner.teardown_works_correctly());
 }
-#endif  // defined(OS_POSIX)
+#endif  // BUILDFLAG(IS_POSIX)
+
+// Test that TLS slots are destroyed in the reverse order: the one that was
+// created first is destroyed last.
+TEST(ThreadLocalStorageTest, DestructionOrder) {
+  const size_t kNSlots = 5;
+  const size_t kSpacing = 100;
+  // The total number of slots is 256, so creating 5 slots with 100 space
+  // between them will place them in different parts of the slot array.
+  // This test checks that their destruction order depends only on their
+  // creation order and not on their index in the array.
+  TlsDestructionOrderRunner runner(kNSlots, kSpacing);
+  DelegateSimpleThread thread(&runner, "tls thread");
+  thread.Start();
+  thread.Join();
+  ASSERT_EQ(kNSlots, TlsDestructionOrderRunner::destructor_calls.size());
+  for (int call = 0, slot = kNSlots; slot > 0; --slot, ++call) {
+    EXPECT_EQ(slot, TlsDestructionOrderRunner::destructor_calls[call]);
+  }
+}
+
+TEST(ThreadLocalStorageTest, CreateDuringDestruction) {
+  CreateDuringDestructionRunner runner;
+  DelegateSimpleThread thread(&runner, "tls thread");
+  thread.Start();
+  thread.Join();
+  ASSERT_TRUE(CreateDuringDestructionRunner::second_destructor_called);
+}
 
 }  // namespace base
diff --git a/base/threading/thread_local_storage_win.cc b/base/threading/thread_local_storage_win.cc
index 4907624..f88f27f 100644
--- a/base/threading/thread_local_storage_win.cc
+++ b/base/threading/thread_local_storage_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -6,8 +6,7 @@
 
 #include <windows.h>
 
-#include "base/logging.h"
-#include "starboard/types.h"
+#include "base/check.h"
 
 namespace base {
 
diff --git a/base/threading/thread_local_unittest.cc b/base/threading/thread_local_unittest.cc
index 54f2ad2..e38a32a 100644
--- a/base/threading/thread_local_unittest.cc
+++ b/base/threading/thread_local_unittest.cc
@@ -1,164 +1,206 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/logging.h"
-#include "base/threading/simple_thread.h"
 #include "base/threading/thread_local.h"
+#include "base/check_op.h"
+#include "base/memory/raw_ptr.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/bind.h"
+#include "base/test/gtest_util.h"
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
 
 namespace {
 
-class ThreadLocalTesterBase : public base::DelegateSimpleThreadPool::Delegate {
+// A simple helper which sets the given boolean to true on destruction.
+class SetTrueOnDestruction {
  public:
-  typedef base::ThreadLocalPointer<char> TLPType;
-
-  ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done)
-      : tlp_(tlp),
-        done_(done) {
+  explicit SetTrueOnDestruction(bool* was_destroyed)
+      : was_destroyed_(was_destroyed) {
+    CHECK_NE(was_destroyed, nullptr);
   }
-  ~ThreadLocalTesterBase() override = default;
 
- protected:
-  TLPType* tlp_;
-  base::WaitableEvent* done_;
-};
+  SetTrueOnDestruction(const SetTrueOnDestruction&) = delete;
+  SetTrueOnDestruction& operator=(const SetTrueOnDestruction&) = delete;
 
-class SetThreadLocal : public ThreadLocalTesterBase {
- public:
-  SetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
-      : ThreadLocalTesterBase(tlp, done), val_(nullptr) {}
-  ~SetThreadLocal() override = default;
-
-  void set_value(char* val) { val_ = val; }
-
-  void Run() override {
-    DCHECK(!done_->IsSignaled());
-    tlp_->Set(val_);
-    done_->Signal();
+  ~SetTrueOnDestruction() {
+    EXPECT_FALSE(*was_destroyed_);
+    *was_destroyed_ = true;
   }
 
  private:
-  char* val_;
-};
-
-class GetThreadLocal : public ThreadLocalTesterBase {
- public:
-  GetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
-      : ThreadLocalTesterBase(tlp, done), ptr_(nullptr) {}
-  ~GetThreadLocal() override = default;
-
-  void set_ptr(char** ptr) { ptr_ = ptr; }
-
-  void Run() override {
-    DCHECK(!done_->IsSignaled());
-    *ptr_ = tlp_->Get();
-    done_->Signal();
-  }
-
- private:
-  char** ptr_;
+  const raw_ptr<bool> was_destroyed_;
 };
 
 }  // namespace
 
-// In this test, we start 2 threads which will access a ThreadLocalPointer.  We
-// make sure the default is NULL, and the pointers are unique to the threads.
-TEST(ThreadLocalTest, Pointer) {
-  base::DelegateSimpleThreadPool tp1("ThreadLocalTest tp1", 1);
-  base::DelegateSimpleThreadPool tp2("ThreadLocalTest tp1", 1);
-  tp1.Start();
-  tp2.Start();
+TEST(ThreadLocalTest, ThreadLocalOwnedPointerBasic) {
+  ThreadLocalOwnedPointer<SetTrueOnDestruction> tls_owned_pointer;
+  EXPECT_FALSE(tls_owned_pointer.Get());
 
-  base::ThreadLocalPointer<char> tlp;
+  bool was_destroyed1 = false;
+  tls_owned_pointer.Set(
+      std::make_unique<SetTrueOnDestruction>(&was_destroyed1));
+  EXPECT_FALSE(was_destroyed1);
+  EXPECT_TRUE(tls_owned_pointer.Get());
 
-  static char* const kBogusPointer = reinterpret_cast<char*>(0x1234);
+  bool was_destroyed2 = false;
+  tls_owned_pointer.Set(
+      std::make_unique<SetTrueOnDestruction>(&was_destroyed2));
+  EXPECT_TRUE(was_destroyed1);
+  EXPECT_FALSE(was_destroyed2);
+  EXPECT_TRUE(tls_owned_pointer.Get());
 
-  char* tls_val;
-  base::WaitableEvent done(WaitableEvent::ResetPolicy::MANUAL,
-                           WaitableEvent::InitialState::NOT_SIGNALED);
-
-  GetThreadLocal getter(&tlp, &done);
-  getter.set_ptr(&tls_val);
-
-  // Check that both threads defaulted to NULL.
-  tls_val = kBogusPointer;
-  done.Reset();
-  tp1.AddWork(&getter);
-  done.Wait();
-  EXPECT_EQ(static_cast<char*>(nullptr), tls_val);
-
-  tls_val = kBogusPointer;
-  done.Reset();
-  tp2.AddWork(&getter);
-  done.Wait();
-  EXPECT_EQ(static_cast<char*>(nullptr), tls_val);
-
-  SetThreadLocal setter(&tlp, &done);
-  setter.set_value(kBogusPointer);
-
-  // Have thread 1 set their pointer value to kBogusPointer.
-  done.Reset();
-  tp1.AddWork(&setter);
-  done.Wait();
-
-  tls_val = nullptr;
-  done.Reset();
-  tp1.AddWork(&getter);
-  done.Wait();
-  EXPECT_EQ(kBogusPointer, tls_val);
-
-  // Make sure thread 2 is still NULL
-  tls_val = kBogusPointer;
-  done.Reset();
-  tp2.AddWork(&getter);
-  done.Wait();
-  EXPECT_EQ(static_cast<char*>(nullptr), tls_val);
-
-  // Set thread 2 to kBogusPointer + 1.
-  setter.set_value(kBogusPointer + 1);
-
-  done.Reset();
-  tp2.AddWork(&setter);
-  done.Wait();
-
-  tls_val = nullptr;
-  done.Reset();
-  tp2.AddWork(&getter);
-  done.Wait();
-  EXPECT_EQ(kBogusPointer + 1, tls_val);
-
-  // Make sure thread 1 is still kBogusPointer.
-  tls_val = nullptr;
-  done.Reset();
-  tp1.AddWork(&getter);
-  done.Wait();
-  EXPECT_EQ(kBogusPointer, tls_val);
-
-  tp1.JoinAll();
-  tp2.JoinAll();
+  tls_owned_pointer.Set(nullptr);
+  EXPECT_TRUE(was_destroyed1);
+  EXPECT_TRUE(was_destroyed2);
+  EXPECT_FALSE(tls_owned_pointer.Get());
 }
 
-TEST(ThreadLocalTest, Boolean) {
-  {
-    base::ThreadLocalBoolean tlb;
-    EXPECT_FALSE(tlb.Get());
+TEST(ThreadLocalTest, ThreadLocalOwnedPointerFreedOnThreadExit) {
+  bool tls_was_destroyed = false;
+  ThreadLocalOwnedPointer<SetTrueOnDestruction> tls_owned_pointer;
 
-    tlb.Set(false);
-    EXPECT_FALSE(tlb.Get());
+  Thread thread("TestThread");
+  thread.Start();
 
-    tlb.Set(true);
-    EXPECT_TRUE(tlb.Get());
+  WaitableEvent tls_set;
+
+  thread.task_runner()->PostTask(
+      FROM_HERE, BindLambdaForTesting([&]() {
+        tls_owned_pointer.Set(
+            std::make_unique<SetTrueOnDestruction>(&tls_was_destroyed));
+        tls_set.Signal();
+      }));
+
+  tls_set.Wait();
+  EXPECT_FALSE(tls_was_destroyed);
+
+  thread.Stop();
+  EXPECT_TRUE(tls_was_destroyed);
+}
+
+TEST(ThreadLocalTest, ThreadLocalOwnedPointerCleansUpMainThreadOnDestruction) {
+  absl::optional<ThreadLocalOwnedPointer<SetTrueOnDestruction>>
+      tls_owned_pointer(absl::in_place);
+  bool tls_was_destroyed_other = false;
+
+  Thread thread("TestThread");
+  thread.Start();
+
+  WaitableEvent tls_set;
+
+  thread.task_runner()->PostTask(
+      FROM_HERE, BindLambdaForTesting([&]() {
+        tls_owned_pointer->Set(
+            std::make_unique<SetTrueOnDestruction>(&tls_was_destroyed_other));
+        tls_set.Signal();
+      }));
+
+  tls_set.Wait();
+
+  bool tls_was_destroyed_main = false;
+  tls_owned_pointer->Set(
+      std::make_unique<SetTrueOnDestruction>(&tls_was_destroyed_main));
+  EXPECT_FALSE(tls_was_destroyed_other);
+  EXPECT_FALSE(tls_was_destroyed_main);
+
+  // Stopping the thread relinquishes its TLS (as in
+  // ThreadLocalOwnedPointerFreedOnThreadExit).
+  thread.Stop();
+  EXPECT_TRUE(tls_was_destroyed_other);
+  EXPECT_FALSE(tls_was_destroyed_main);
+
+  // Deleting the ThreadLocalOwnedPointer instance on the main thread is allowed
+  // iff that's the only thread with remaining storage (ref. disallowed use case
+  // in ThreadLocalOwnedPointerDeathIfDestroyedWithActiveThread below). In that
+  // case, the storage on the main thread is freed before releasing the TLS
+  // slot.
+  tls_owned_pointer.reset();
+  EXPECT_TRUE(tls_was_destroyed_main);
+}
+
+TEST(ThreadLocalTest, ThreadLocalOwnedPointerDeathIfDestroyedWithActiveThread) {
+  testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  absl::optional<ThreadLocalOwnedPointer<int>> tls_owned_pointer(
+      absl::in_place);
+
+  Thread thread("TestThread");
+  thread.Start();
+
+  WaitableEvent tls_set;
+
+  thread.task_runner()->PostTask(
+      FROM_HERE, BindLambdaForTesting([&]() {
+        tls_owned_pointer->Set(std::make_unique<int>(1));
+        tls_set.Signal();
+      }));
+
+  tls_set.Wait();
+
+  EXPECT_DCHECK_DEATH({ tls_owned_pointer.reset(); });
+}
+
+TEST(ThreadLocalTest, ThreadLocalOwnedPointerMultiThreadedAndStaticStorage) {
+  constexpr int kNumThreads = 16;
+
+  static ThreadLocalOwnedPointer<SetTrueOnDestruction> tls_owned_pointer;
+
+  std::array<bool, kNumThreads> were_destroyed{};
+
+  std::array<std::unique_ptr<Thread>, kNumThreads> threads;
+
+  for (auto& thread : threads) {
+    thread = std::make_unique<Thread>("TestThread");
+    thread->Start();
   }
 
-  // Our slot should have been freed, we're all reset.
-  {
-    base::ThreadLocalBoolean tlb;
-    EXPECT_FALSE(tlb.Get());
+  for (const auto& thread : threads) {
+    // Waiting is unnecessary but enhances the likelihood of data races in the
+    // next steps.
+    thread->WaitUntilThreadStarted();
   }
+
+  for (const bool was_destroyed : were_destroyed) {
+    EXPECT_FALSE(was_destroyed);
+  }
+
+  for (int i = 0; i < kNumThreads; ++i) {
+    threads[i]->task_runner()->PostTask(
+        FROM_HERE,
+        BindOnce(
+            [](bool* was_destroyed) {
+              tls_owned_pointer.Set(
+                  std::make_unique<SetTrueOnDestruction>(was_destroyed));
+            },
+            &were_destroyed[i]));
+  }
+
+  static bool main_thread_was_destroyed = false;
+  // Even when the test is run multiple times in the same process: TLS should
+  // never be destroyed until static uninitialization.
+  EXPECT_FALSE(main_thread_was_destroyed);
+
+  tls_owned_pointer.Set(
+      std::make_unique<SetTrueOnDestruction>(&main_thread_was_destroyed));
+
+  for (const auto& thread : threads) {
+    thread->Stop();
+  }
+
+  for (const bool was_destroyed : were_destroyed) {
+    EXPECT_TRUE(was_destroyed);
+  }
+
+  // The main thread's TLS still wasn't destroyed (let the test unfold naturally
+  // through static uninitialization).
+  EXPECT_FALSE(main_thread_was_destroyed);
 }
 
 }  // namespace base
diff --git a/base/threading/thread_perftest.cc b/base/threading/thread_perftest.cc
index 9a3f92c..3c623f1 100644
--- a/base/threading/thread_perftest.cc
+++ b/base/threading/thread_perftest.cc
@@ -1,30 +1,30 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <stddef.h>
+
 #include <memory>
 #include <vector>
 
-#include "starboard/types.h"
-
 #include "base/base_switches.h"
-#include "base/bind.h"
 #include "base/command_line.h"
+#include "base/functional/bind.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/stringprintf.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/task/current_thread.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/task/task_observer.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/perf/perf_test.h"
+#include "testing/perf/perf_result_reporter.h"
 
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
 #include <pthread.h>
 #endif
 
@@ -34,6 +34,27 @@
 
 const int kNumRuns = 100000;
 
+constexpr char kMetricPrefixThread[] = "Thread.";
+constexpr char kMetricClockTimePerHop[] = "wall_time_per_hop";
+constexpr char kMetricCpuTimePerHop[] = "cpu_time_per_hop";
+constexpr char kStoryBaseTask[] = "task";
+constexpr char kStoryBaseTaskWithObserver[] = "task_with_observer";
+constexpr char kStoryBaseWaitableEvent[] = "waitable_event";
+constexpr char kStoryBaseCondVar[] = "condition_variable";
+constexpr char kStorySuffixOneThread[] = "_1_thread";
+constexpr char kStorySuffixFourThreads[] = "_4_threads";
+
+#if BUILDFLAG(IS_POSIX)
+constexpr char kStoryBasePthreadCondVar[] = "pthread_condition_variable";
+#endif  // BUILDFLAG(IS_POSIX)
+
+perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
+  perf_test::PerfResultReporter reporter(kMetricPrefixThread, story_name);
+  reporter.RegisterImportantMetric(kMetricClockTimePerHop, "us");
+  reporter.RegisterImportantMetric(kMetricCpuTimePerHop, "us");
+  return reporter;
+}
+
 // Base class for a threading perf-test. This sets up some threads for the
 // test and measures the clock-time in addition to time spent on each thread.
 class ThreadPerfTest : public testing::Test {
@@ -68,7 +89,7 @@
     return ticks;
   }
 
-  void RunPingPongTest(const std::string& name, unsigned num_threads) {
+  void RunPingPongTest(const std::string& story_name, unsigned num_threads) {
     // Create threads and collect starting cpu-time for each thread.
     std::vector<base::ThreadTicks> thread_starts;
     while (threads_.size() < num_threads) {
@@ -98,18 +119,16 @@
 
     Reset();
 
-    double num_runs = static_cast<double>(kNumRuns);
-    double us_per_task_clock = (end - start).InMicroseconds() / num_runs;
-    double us_per_task_cpu = thread_time.InMicroseconds() / num_runs;
+    double us_per_task_clock = (end - start).InMicrosecondsF() / kNumRuns;
+    double us_per_task_cpu = thread_time.InMicrosecondsF() / kNumRuns;
 
+    auto reporter = SetUpReporter(story_name);
     // Clock time per task.
-    perf_test::PrintResult(
-        "task", "", name + "_time ", us_per_task_clock, "us/hop", true);
+    reporter.AddResult(kMetricClockTimePerHop, us_per_task_clock);
 
     // Total utilization across threads if available (likely higher).
     if (base::ThreadTicks::IsSupported()) {
-      perf_test::PrintResult(
-          "task", "", name + "_cpu ", us_per_task_cpu, "us/hop", true);
+      reporter.AddResult(kMetricCpuTimePerHop, us_per_task_cpu);
     }
   }
 
@@ -144,15 +163,16 @@
 // used to ensure the threads do yeild (with just two it might be possible for
 // both threads to stay awake if they can signal each other fast enough).
 TEST_F(TaskPerfTest, TaskPingPong) {
-  RunPingPongTest("1_Task_Threads", 1);
-  RunPingPongTest("4_Task_Threads", 4);
+  RunPingPongTest(std::string(kStoryBaseTask) + kStorySuffixOneThread, 1);
+  RunPingPongTest(std::string(kStoryBaseTask) + kStorySuffixFourThreads, 4);
 }
 
 
 // Same as above, but add observers to test their perf impact.
-class MessageLoopObserver : public base::MessageLoop::TaskObserver {
+class MessageLoopObserver : public base::TaskObserver {
  public:
-  void WillProcessTask(const base::PendingTask& pending_task) override {}
+  void WillProcessTask(const base::PendingTask& pending_task,
+                       bool was_blocked_or_low_priority) override {}
   void DidProcessTask(const base::PendingTask& pending_task) override {}
 };
 MessageLoopObserver message_loop_observer;
@@ -161,18 +181,22 @@
  public:
   void Init() override {
     TaskPerfTest::Init();
-    for (size_t i = 0; i < threads_.size(); i++) {
-      threads_[i]->message_loop()->task_runner()->PostTask(
-          FROM_HERE, BindOnce(&MessageLoop::AddTaskObserver,
-                              Unretained(threads_[i]->message_loop()),
-                              Unretained(&message_loop_observer)));
+    for (auto& i : threads_) {
+      i->task_runner()->PostTask(
+          FROM_HERE, BindOnce(
+                         [](MessageLoopObserver* observer) {
+                           CurrentThread::Get()->AddTaskObserver(observer);
+                         },
+                         Unretained(&message_loop_observer)));
     }
   }
 };
 
 TEST_F(TaskObserverPerfTest, TaskPingPong) {
-  RunPingPongTest("1_Task_Threads_With_Observer", 1);
-  RunPingPongTest("4_Task_Threads_With_Observer", 4);
+  RunPingPongTest(
+      std::string(kStoryBaseTaskWithObserver) + kStorySuffixOneThread, 1);
+  RunPingPongTest(
+      std::string(kStoryBaseTaskWithObserver) + kStorySuffixFourThreads, 4);
 }
 
 // Class to test our WaitableEvent performance by signaling back and fort.
@@ -226,7 +250,8 @@
 // end up blocking because the event is already signalled).
 typedef EventPerfTest<base::WaitableEvent> WaitableEventThreadPerfTest;
 TEST_F(WaitableEventThreadPerfTest, EventPingPong) {
-  RunPingPongTest("4_WaitableEvent_Threads", 4);
+  RunPingPongTest(
+      std::string(kStoryBaseWaitableEvent) + kStorySuffixFourThreads, 4);
 }
 
 // Build a minimal event using ConditionVariable.
@@ -264,9 +289,9 @@
 // using our own base synchronization code.
 typedef EventPerfTest<ConditionVariableEvent> ConditionVariablePerfTest;
 TEST_F(ConditionVariablePerfTest, EventPingPong) {
-  RunPingPongTest("4_ConditionVariable_Threads", 4);
+  RunPingPongTest(std::string(kStoryBaseCondVar) + kStorySuffixFourThreads, 4);
 }
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
 
 // Absolutely 100% minimal posix waitable event. If there is a better/faster
 // way to force a context switch, we should use that instead.
@@ -311,7 +336,8 @@
 // If there is any faster way to do this we should substitute it in.
 typedef EventPerfTest<PthreadEvent> PthreadEventPerfTest;
 TEST_F(PthreadEventPerfTest, EventPingPong) {
-  RunPingPongTest("4_PthreadCondVar_Threads", 4);
+  RunPingPongTest(
+      std::string(kStoryBasePthreadCondVar) + kStorySuffixFourThreads, 4);
 }
 
 #endif
diff --git a/base/threading/thread_restrictions.cc b/base/threading/thread_restrictions.cc
index 3d91fe0..016841c 100644
--- a/base/threading/thread_restrictions.cc
+++ b/base/threading/thread_restrictions.cc
@@ -1,199 +1,330 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/thread_restrictions.h"
 
-#if DCHECK_IS_ON()
+#include "base/threading/hang_watcher.h"
+#include "base/trace_event/base_tracing.h"
+#include "build/build_config.h"
 
-#include "base/lazy_instance.h"
-#include "base/logging.h"
+#if DCHECK_IS_ON()
+#include "base/check_op.h"
+#include "base/no_destructor.h"
 #include "base/threading/thread_local.h"
 
+// NaCL doesn't support stack sampling and Android is slow at stack sampling and
+// this causes timeouts (crbug.com/959139).
+#if BUILDFLAG(IS_NACL) || BUILDFLAG(IS_ANDROID)
+constexpr bool kCaptureStackTraces = false;
+#else
+// Always disabled when !EXPENSIVE_DCHECKS_ARE_ON() because user-facing builds
+// typically drop log strings anyways.
+constexpr bool kCaptureStackTraces = EXPENSIVE_DCHECKS_ARE_ON();
+#endif
+
 namespace base {
 
+BooleanWithStack::BooleanWithStack(bool value) : value_(value) {
+  if (kCaptureStackTraces) {
+    stack_.emplace();
+  }
+}
+
+std::ostream& operator<<(std::ostream& out, const BooleanWithStack& bws) {
+  out << bws.value_;
+  if (kCaptureStackTraces) {
+    if (bws.stack_.has_value()) {
+      out << " set by\n" << bws.stack_.value();
+    } else {
+      out << " (value by default)";
+    }
+  }
+  return out;
+}
+
 namespace {
 
-LazyInstance<ThreadLocalBoolean>::Leaky g_blocking_disallowed =
-    LAZY_INSTANCE_INITIALIZER;
-
-LazyInstance<ThreadLocalBoolean>::Leaky
-    g_singleton_disallowed = LAZY_INSTANCE_INITIALIZER;
-
-LazyInstance<ThreadLocalBoolean>::Leaky g_base_sync_primitives_disallowed =
-    LAZY_INSTANCE_INITIALIZER;
-
-LazyInstance<ThreadLocalBoolean>::Leaky g_cpu_intensive_work_disallowed =
-    LAZY_INSTANCE_INITIALIZER;
+// TODO(crbug.com/1423437): Change these to directly-accessed, namespace-scope
+// `thread_local BooleanWithStack`s when doing so doesn't cause crashes.
+BooleanWithStack& GetBlockingDisallowedTls() {
+  static NoDestructor<ThreadLocalOwnedPointer<BooleanWithStack>> instance;
+  auto& tls = *instance;
+  if (!tls.Get()) {
+    tls.Set(std::make_unique<BooleanWithStack>());
+  }
+  return *tls;
+}
+BooleanWithStack& GetSingletonDisallowedTls() {
+  static NoDestructor<ThreadLocalOwnedPointer<BooleanWithStack>> instance;
+  auto& tls = *instance;
+  if (!tls.Get()) {
+    tls.Set(std::make_unique<BooleanWithStack>());
+  }
+  return *tls;
+}
+BooleanWithStack& GetBaseSyncPrimitivesDisallowedTls() {
+  static NoDestructor<ThreadLocalOwnedPointer<BooleanWithStack>> instance;
+  auto& tls = *instance;
+  if (!tls.Get()) {
+    tls.Set(std::make_unique<BooleanWithStack>());
+  }
+  return *tls;
+}
+BooleanWithStack& GetCPUIntensiveWorkDisallowedTls() {
+  static NoDestructor<ThreadLocalOwnedPointer<BooleanWithStack>> instance;
+  auto& tls = *instance;
+  if (!tls.Get()) {
+    tls.Set(std::make_unique<BooleanWithStack>());
+  }
+  return *tls;
+}
 
 }  // namespace
 
+namespace internal {
+
 void AssertBlockingAllowed() {
-  DCHECK(!g_blocking_disallowed.Get().Get())
+  DCHECK(!GetBlockingDisallowedTls())
       << "Function marked as blocking was called from a scope that disallows "
-         "blocking! If this task is running inside the TaskScheduler, it needs "
+         "blocking! If this task is running inside the ThreadPool, it needs "
          "to have MayBlock() in its TaskTraits. Otherwise, consider making "
          "this blocking work asynchronous or, as a last resort, you may use "
-         "ScopedAllowBlocking (see its documentation for best practices).";
+         "ScopedAllowBlocking (see its documentation for best practices).\n"
+      << "blocking_disallowed " << GetBlockingDisallowedTls();
 }
 
+void AssertBlockingDisallowedForTesting() {
+  DCHECK(GetBlockingDisallowedTls())
+      << "blocking_disallowed " << GetBlockingDisallowedTls();
+}
+
+}  // namespace internal
+
 void DisallowBlocking() {
-  g_blocking_disallowed.Get().Set(true);
+  GetBlockingDisallowedTls() = BooleanWithStack(true);
 }
 
 ScopedDisallowBlocking::ScopedDisallowBlocking()
-    : was_disallowed_(g_blocking_disallowed.Get().Get()) {
-  g_blocking_disallowed.Get().Set(true);
-}
+    : resetter_(&GetBlockingDisallowedTls(), BooleanWithStack(true)) {}
 
 ScopedDisallowBlocking::~ScopedDisallowBlocking() {
-  DCHECK(g_blocking_disallowed.Get().Get());
-  g_blocking_disallowed.Get().Set(was_disallowed_);
-}
-
-ScopedAllowBlocking::ScopedAllowBlocking()
-    : was_disallowed_(g_blocking_disallowed.Get().Get()) {
-  g_blocking_disallowed.Get().Set(false);
-}
-
-ScopedAllowBlocking::~ScopedAllowBlocking() {
-  DCHECK(!g_blocking_disallowed.Get().Get());
-  g_blocking_disallowed.Get().Set(was_disallowed_);
+  DCHECK(GetBlockingDisallowedTls())
+      << "~ScopedDisallowBlocking() running while surprisingly already no "
+         "longer disallowed.\n"
+      << "blocking_disallowed " << GetBlockingDisallowedTls();
 }
 
 void DisallowBaseSyncPrimitives() {
-  g_base_sync_primitives_disallowed.Get().Set(true);
+  GetBaseSyncPrimitivesDisallowedTls() = BooleanWithStack(true);
+}
+
+ScopedDisallowBaseSyncPrimitives::ScopedDisallowBaseSyncPrimitives()
+    : resetter_(&GetBaseSyncPrimitivesDisallowedTls(), BooleanWithStack(true)) {
+}
+
+ScopedDisallowBaseSyncPrimitives::~ScopedDisallowBaseSyncPrimitives() {
+  DCHECK(GetBaseSyncPrimitivesDisallowedTls())
+      << "~ScopedDisallowBaseSyncPrimitives() running while surprisingly "
+         "already no longer disallowed.\n"
+      << "base_sync_primitives_disallowed "
+      << GetBaseSyncPrimitivesDisallowedTls();
 }
 
 ScopedAllowBaseSyncPrimitives::ScopedAllowBaseSyncPrimitives()
-    : was_disallowed_(g_base_sync_primitives_disallowed.Get().Get()) {
-  DCHECK(!g_blocking_disallowed.Get().Get())
+    : resetter_(&GetBaseSyncPrimitivesDisallowedTls(),
+                BooleanWithStack(false)) {
+  DCHECK(!GetBlockingDisallowedTls())
       << "To allow //base sync primitives in a scope where blocking is "
-         "disallowed use ScopedAllowBaseSyncPrimitivesOutsideBlockingScope.";
-  g_base_sync_primitives_disallowed.Get().Set(false);
+         "disallowed use ScopedAllowBaseSyncPrimitivesOutsideBlockingScope.\n"
+      << "blocking_disallowed " << GetBlockingDisallowedTls();
 }
 
 ScopedAllowBaseSyncPrimitives::~ScopedAllowBaseSyncPrimitives() {
-  DCHECK(!g_base_sync_primitives_disallowed.Get().Get());
-  g_base_sync_primitives_disallowed.Get().Set(was_disallowed_);
-}
-
-ScopedAllowBaseSyncPrimitivesOutsideBlockingScope::
-    ScopedAllowBaseSyncPrimitivesOutsideBlockingScope()
-    : was_disallowed_(g_base_sync_primitives_disallowed.Get().Get()) {
-  g_base_sync_primitives_disallowed.Get().Set(false);
-}
-
-ScopedAllowBaseSyncPrimitivesOutsideBlockingScope::
-    ~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope() {
-  DCHECK(!g_base_sync_primitives_disallowed.Get().Get());
-  g_base_sync_primitives_disallowed.Get().Set(was_disallowed_);
+  DCHECK(!GetBaseSyncPrimitivesDisallowedTls())
+      << "~ScopedAllowBaseSyncPrimitives() running while surprisingly already "
+         "no longer allowed.\n"
+      << "base_sync_primitives_disallowed "
+      << GetBaseSyncPrimitivesDisallowedTls();
 }
 
 ScopedAllowBaseSyncPrimitivesForTesting::
     ScopedAllowBaseSyncPrimitivesForTesting()
-    : was_disallowed_(g_base_sync_primitives_disallowed.Get().Get()) {
-  g_base_sync_primitives_disallowed.Get().Set(false);
-}
+    : resetter_(&GetBaseSyncPrimitivesDisallowedTls(),
+                BooleanWithStack(false)) {}
 
 ScopedAllowBaseSyncPrimitivesForTesting::
     ~ScopedAllowBaseSyncPrimitivesForTesting() {
-  DCHECK(!g_base_sync_primitives_disallowed.Get().Get());
-  g_base_sync_primitives_disallowed.Get().Set(was_disallowed_);
+  DCHECK(!GetBaseSyncPrimitivesDisallowedTls())
+      << "~ScopedAllowBaseSyncPrimitivesForTesting() running while "  // IN-TEST
+         "surprisingly already no longer allowed.\n"
+      << "base_sync_primitives_disallowed "
+      << GetBaseSyncPrimitivesDisallowedTls();
+}
+
+ScopedAllowUnresponsiveTasksForTesting::ScopedAllowUnresponsiveTasksForTesting()
+    : base_sync_resetter_(&GetBaseSyncPrimitivesDisallowedTls(),
+                          BooleanWithStack(false)),
+      blocking_resetter_(&GetBlockingDisallowedTls(), BooleanWithStack(false)),
+      cpu_resetter_(&GetCPUIntensiveWorkDisallowedTls(),
+                    BooleanWithStack(false)) {}
+
+ScopedAllowUnresponsiveTasksForTesting::
+    ~ScopedAllowUnresponsiveTasksForTesting() {
+  DCHECK(!GetBaseSyncPrimitivesDisallowedTls())
+      << "~ScopedAllowUnresponsiveTasksForTesting() running while "  // IN-TEST
+         "surprisingly already no longer allowed.\n"
+      << "base_sync_primitives_disallowed "
+      << GetBaseSyncPrimitivesDisallowedTls();
+  DCHECK(!GetBlockingDisallowedTls())
+      << "~ScopedAllowUnresponsiveTasksForTesting() running while "  // IN-TEST
+         "surprisingly already no longer allowed.\n"
+      << "blocking_disallowed " << GetBlockingDisallowedTls();
+  DCHECK(!GetCPUIntensiveWorkDisallowedTls())
+      << "~ScopedAllowUnresponsiveTasksForTesting() running while "  // IN-TEST
+         "surprisingly already no longer allowed.\n"
+      << "cpu_intensive_work_disallowed " << GetCPUIntensiveWorkDisallowedTls();
 }
 
 namespace internal {
 
 void AssertBaseSyncPrimitivesAllowed() {
-  DCHECK(!g_base_sync_primitives_disallowed.Get().Get())
+  DCHECK(!GetBaseSyncPrimitivesDisallowedTls())
       << "Waiting on a //base sync primitive is not allowed on this thread to "
          "prevent jank and deadlock. If waiting on a //base sync primitive is "
          "unavoidable, do it within the scope of a "
-         "ScopedAllowBaseSyncPrimitives. If in a test, "
-         "use ScopedAllowBaseSyncPrimitivesForTesting.";
+         "ScopedAllowBaseSyncPrimitives. If in a test, use "
+         "ScopedAllowBaseSyncPrimitivesForTesting.\n"
+      << "base_sync_primitives_disallowed "
+      << GetBaseSyncPrimitivesDisallowedTls()
+      << "It can be useful to know that blocking_disallowed is "
+      << GetBlockingDisallowedTls();
 }
 
 void ResetThreadRestrictionsForTesting() {
-  g_blocking_disallowed.Get().Set(false);
-  g_singleton_disallowed.Get().Set(false);
-  g_base_sync_primitives_disallowed.Get().Set(false);
-  g_cpu_intensive_work_disallowed.Get().Set(false);
+  GetBlockingDisallowedTls() = BooleanWithStack(false);
+  GetSingletonDisallowedTls() = BooleanWithStack(false);
+  GetBaseSyncPrimitivesDisallowedTls() = BooleanWithStack(false);
+  GetCPUIntensiveWorkDisallowedTls() = BooleanWithStack(false);
+}
+
+void AssertSingletonAllowed() {
+  DCHECK(!GetSingletonDisallowedTls())
+      << "LazyInstance/Singleton is not allowed to be used on this thread. "
+         "Most likely it's because this thread is not joinable (or the current "
+         "task is running with TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN "
+         "semantics), so AtExitManager may have deleted the object on "
+         "shutdown, leading to a potential shutdown crash. If you need to use "
+         "the object from this context, it'll have to be updated to use Leaky "
+         "traits.\n"
+      << "singleton_disallowed " << GetSingletonDisallowedTls();
 }
 
 }  // namespace internal
 
+void DisallowSingleton() {
+  GetSingletonDisallowedTls() = BooleanWithStack(true);
+}
+
+#if defined(STARBOARD)
+bool GetSingletonAllowed() {
+  return !!GetSingletonDisallowedTls();
+}
+#endif
+
+ScopedDisallowSingleton::ScopedDisallowSingleton()
+    : resetter_(&GetSingletonDisallowedTls(), BooleanWithStack(true)) {}
+
+ScopedDisallowSingleton::~ScopedDisallowSingleton() {
+  DCHECK(GetSingletonDisallowedTls())
+      << "~ScopedDisallowSingleton() running while surprisingly already no "
+         "longer disallowed.\n"
+      << "singleton_disallowed " << GetSingletonDisallowedTls();
+}
+
 void AssertLongCPUWorkAllowed() {
-  DCHECK(!g_cpu_intensive_work_disallowed.Get().Get())
+  DCHECK(!GetCPUIntensiveWorkDisallowedTls())
       << "Function marked as CPU intensive was called from a scope that "
-         "disallows this kind of work! Consider making this work asynchronous.";
+         "disallows this kind of work! Consider making this work "
+         "asynchronous.\n"
+      << "cpu_intensive_work_disallowed " << GetCPUIntensiveWorkDisallowedTls();
 }
 
 void DisallowUnresponsiveTasks() {
   DisallowBlocking();
   DisallowBaseSyncPrimitives();
-  g_cpu_intensive_work_disallowed.Get().Set(true);
-}
-
-ThreadRestrictions::ScopedAllowIO::ScopedAllowIO()
-    : was_allowed_(SetIOAllowed(true)) {}
-
-ThreadRestrictions::ScopedAllowIO::~ScopedAllowIO() {
-  SetIOAllowed(was_allowed_);
+  GetCPUIntensiveWorkDisallowedTls() = BooleanWithStack(true);
 }
 
 // static
-bool ThreadRestrictions::SetIOAllowed(bool allowed) {
-  bool previous_disallowed = g_blocking_disallowed.Get().Get();
-  g_blocking_disallowed.Get().Set(!allowed);
-  return !previous_disallowed;
-}
-
-#if defined(STARBOARD)
-// static
-bool ThreadRestrictions::GetSingletonAllowed() {
-  return !g_singleton_disallowed.Get().Get();
-}
-#endif  // defined(STARBOARD)
-
-// static
-bool ThreadRestrictions::SetSingletonAllowed(bool allowed) {
-  bool previous_disallowed = g_singleton_disallowed.Get().Get();
-  g_singleton_disallowed.Get().Set(!allowed);
-  return !previous_disallowed;
+void PermanentThreadAllowance::AllowBlocking() {
+  GetBlockingDisallowedTls() = BooleanWithStack(false);
 }
 
 // static
-void ThreadRestrictions::AssertSingletonAllowed() {
-  if (g_singleton_disallowed.Get().Get()) {
-    NOTREACHED() << "LazyInstance/Singleton is not allowed to be used on this "
-                 << "thread.  Most likely it's because this thread is not "
-                 << "joinable (or the current task is running with "
-                 << "TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN semantics), so "
-                 << "AtExitManager may have deleted the object on shutdown, "
-                 << "leading to a potential shutdown crash. If you need to use "
-                 << "the object from this context, it'll have to be updated to "
-                 << "use Leaky traits.";
-  }
-}
-
-// static
-void ThreadRestrictions::DisallowWaiting() {
-  DisallowBaseSyncPrimitives();
-}
-
-bool ThreadRestrictions::SetWaitAllowed(bool allowed) {
-  bool previous_disallowed = g_base_sync_primitives_disallowed.Get().Get();
-  g_base_sync_primitives_disallowed.Get().Set(!allowed);
-  return !previous_disallowed;
-}
-
-ThreadRestrictions::ScopedAllowWait::ScopedAllowWait()
-    : was_allowed_(SetWaitAllowed(true)) {}
-
-ThreadRestrictions::ScopedAllowWait::~ScopedAllowWait() {
-  SetWaitAllowed(was_allowed_);
+void PermanentThreadAllowance::AllowBaseSyncPrimitives() {
+  GetBaseSyncPrimitivesDisallowedTls() = BooleanWithStack(false);
 }
 
 }  // namespace base
 
 #endif  // DCHECK_IS_ON()
+
+namespace base {
+
+ScopedAllowBlocking::ScopedAllowBlocking(const Location& from_here)
+#if DCHECK_IS_ON()
+    : resetter_(&GetBlockingDisallowedTls(), BooleanWithStack(false))
+#endif
+{
+  TRACE_EVENT_BEGIN(
+      "base", "ScopedAllowBlocking", [&](perfetto::EventContext ctx) {
+        ctx.event()->set_source_location_iid(
+            base::trace_event::InternedSourceLocation::Get(&ctx, from_here));
+      });
+}
+
+ScopedAllowBlocking::~ScopedAllowBlocking() {
+  TRACE_EVENT_END0("base", "ScopedAllowBlocking");
+
+#if DCHECK_IS_ON()
+  DCHECK(!GetBlockingDisallowedTls())
+      << "~ScopedAllowBlocking() running while surprisingly already no longer "
+         "allowed.\n"
+      << "blocking_disallowed " << GetBlockingDisallowedTls();
+#endif
+}
+
+ScopedAllowBaseSyncPrimitivesOutsideBlockingScope::
+    ScopedAllowBaseSyncPrimitivesOutsideBlockingScope(const Location& from_here)
+#if DCHECK_IS_ON()
+    : resetter_(&GetBaseSyncPrimitivesDisallowedTls(), BooleanWithStack(false))
+#endif
+{
+  TRACE_EVENT_BEGIN(
+      "base", "ScopedAllowBaseSyncPrimitivesOutsideBlockingScope",
+      [&](perfetto::EventContext ctx) {
+        ctx.event()->set_source_location_iid(
+            base::trace_event::InternedSourceLocation::Get(&ctx, from_here));
+      });
+
+  // Since this object is used to indicate that sync primitives will be used to
+  // wait for an event ignore the current operation for hang watching purposes
+  // since the wait time duration is unknown.
+  base::HangWatcher::InvalidateActiveExpectations();
+}
+
+ScopedAllowBaseSyncPrimitivesOutsideBlockingScope::
+    ~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope() {
+  TRACE_EVENT_END0("base", "ScopedAllowBaseSyncPrimitivesOutsideBlockingScope");
+
+#if DCHECK_IS_ON()
+  DCHECK(!GetBaseSyncPrimitivesDisallowedTls())
+      << "~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope() running while "
+         "surprisingly already no longer allowed.\n"
+      << "base_sync_primitives_disallowed "
+      << GetBaseSyncPrimitivesDisallowedTls();
+#endif
+}
+
+}  // namespace base
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index 603fed9..bb14c47 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -1,228 +1,106 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #ifndef BASE_THREADING_THREAD_RESTRICTIONS_H_
 #define BASE_THREADING_THREAD_RESTRICTIONS_H_
 
+#include "base/auto_reset.h"
 #include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/dcheck_is_on.h"
 #include "base/gtest_prod_util.h"
-#include "base/logging.h"
-#include "base/macros.h"
-
-class BrowserProcessImpl;
-class HistogramSynchronizer;
-class NativeBackendKWallet;
-class KeyStorageLinux;
-
-namespace android_webview {
-class AwFormDatabaseService;
-class CookieManager;
-class ScopedAllowInitGLBindings;
-}
-namespace audio {
-class OutputDevice;
-}
-namespace blink {
-class VideoFrameResourceProvider;
-}
-namespace cc {
-class CompletionEvent;
-class SingleThreadTaskGraphRunner;
-}
-namespace chromeos {
-class BlockingMethodCaller;
-namespace system {
-class StatisticsProviderImpl;
-}
-}
-namespace chrome_browser_net {
-class Predictor;
-}
-namespace content {
-class BrowserGpuChannelHostFactory;
-class BrowserMainLoop;
-class BrowserProcessSubThread;
-class BrowserShutdownProfileDumper;
-class BrowserTestBase;
-class CategorizedWorkerPool;
-class GpuProcessTransportFactory;
-class NestedMessagePumpAndroid;
-class ScopedAllowWaitForAndroidLayoutTests;
-class ScopedAllowWaitForDebugURL;
-class SessionStorageDatabase;
-class SoftwareOutputDeviceMus;
-class ServiceWorkerSubresourceLoader;
-class SynchronousCompositor;
-class SynchronousCompositorHost;
-class SynchronousCompositorSyncCallBridge;
-class TextInputClientMac;
-}  // namespace content
-namespace cronet {
-class CronetPrefsManager;
-class CronetURLRequestContext;
-}  // namespace cronet
-namespace dbus {
-class Bus;
-}
-namespace disk_cache {
-class BackendImpl;
-class InFlightIO;
-}
-namespace functions {
-class ExecScriptScopedAllowBaseSyncPrimitives;
-}
-namespace gpu {
-class GpuChannelHost;
-}
-namespace leveldb {
-class LevelDBMojoProxy;
-}
-namespace media {
-class AudioInputDevice;
-class BlockingUrlProtocol;
-}
-namespace midi {
-class TaskService;  // https://crbug.com/796830
-}
-namespace mojo {
-class CoreLibraryInitializer;
-class SyncCallRestrictions;
-namespace core {
-class ScopedIPCSupport;
-}
-}
-namespace rlz_lib {
-class FinancialPing;
-}
-namespace ui {
-class CommandBufferClientImpl;
-class CommandBufferLocal;
-class GpuState;
-class MaterialDesignController;
-}
-namespace net {
-class MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives;
-class NetworkChangeNotifierMac;
-namespace internal {
-class AddressTrackerLinux;
-}
-}
-
-namespace remoting {
-class AutoThread;
-}
-
-namespace resource_coordinator {
-class TabManagerDelegate;
-}
-
-namespace service_manager {
-class ServiceProcessLauncher;
-}
-
-namespace shell_integration_linux {
-class LaunchXdgUtilityScopedAllowBaseSyncPrimitives;
-}
-
-namespace ui {
-class WindowResizeHelperMac;
-}
-
-namespace viz {
-class HostGpuMemoryBufferManager;
-}
-
-namespace webrtc {
-class DesktopConfigurationMonitor;
-}
-
-namespace base {
-
-namespace android {
-class JavaHandlerThread;
-}
-
-namespace internal {
-class TaskTracker;
-}
-
-class AdjustOOMScoreHelper;
-class GetAppOutputScopedAllowBaseSyncPrimitives;
-class SimpleThread;
-class StackSamplingProfiler;
-class Thread;
-class ThreadTestHelper;
+#include "base/location.h"
+#include "build/build_config.h"
 
 #if DCHECK_IS_ON()
-#define INLINE_IF_DCHECK_IS_OFF BASE_EXPORT
-#define EMPTY_BODY_IF_DCHECK_IS_OFF
-#else
-#define INLINE_IF_DCHECK_IS_OFF inline
-#define EMPTY_BODY_IF_DCHECK_IS_OFF \
-  {}
+#include "base/debug/stack_trace.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #endif
 
-// A "blocking call" refers to any call that causes the calling thread to wait
-// off-CPU. It includes but is not limited to calls that wait on synchronous
-// file I/O operations: read or write a file from disk, interact with a pipe or
-// a socket, rename or delete a file, enumerate files in a directory, etc.
-// Acquiring a low contention lock is not considered a blocking call.
-
-// Asserts that blocking calls are allowed in the current scope. Prefer using
-// ScopedBlockingCall instead, which also serves as a precise annotation of the
-// scope that may/will block.
+// -----------------------------------------------------------------------------
+// Usage documentation
+// -----------------------------------------------------------------------------
 //
-// Style tip: It's best if you put AssertBlockingAllowed() checks as close to
-// the blocking call as possible. For example:
+// Overview:
+// This file exposes functions to ban and allow certain slow operations
+// on a per-thread basis. To annotate *usage* of such slow operations, refer to
+// scoped_blocking_call.h instead.
 //
-// void ReadFile() {
-//   PreWork();
+// Specific allowances that can be controlled in this file are:
 //
-//   base::AssertBlockingAllowed();
-//   fopen(...);
+// - Blocking call: Refers to any call that causes the calling thread to wait
+//   off-CPU. It includes but is not limited to calls that wait on synchronous
+//   file I/O operations: read or write a file from disk, interact with a pipe
+//   or a socket, rename or delete a file, enumerate files in a directory, etc.
+//   Acquiring a low contention lock is not considered a blocking call.
 //
-//   PostWork();
-// }
+//   Prefer to allow a blocking call by posting a task to
+//   base::ThreadPoolInstance with base::MayBlock().
 //
-// void Bar() {
-//   ReadFile();
-// }
+// - Waiting on a //base sync primitive: Refers to calling one of these methods:
+//   - base::WaitableEvent::*Wait*
+//   - base::ConditionVariable::*Wait*
+//   - base::Process::WaitForExit*
 //
-// void Foo() {
-//   Bar();
-// }
-INLINE_IF_DCHECK_IS_OFF void AssertBlockingAllowed()
-    EMPTY_BODY_IF_DCHECK_IS_OFF;
-
-// Disallows blocking on the current thread.
-INLINE_IF_DCHECK_IS_OFF void DisallowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
-
-// Disallows blocking calls within its scope.
-class BASE_EXPORT ScopedDisallowBlocking {
- public:
-  ScopedDisallowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
-  ~ScopedDisallowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
-
- private:
-#if DCHECK_IS_ON()
-  const bool was_disallowed_;
-#endif
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedDisallowBlocking);
-};
-
-// ScopedAllowBlocking(ForTesting) allow blocking calls within a scope where
-// they are normally disallowed.
+//   Prefer not to wait on //base sync primitives (see below for alternatives).
+//   When it is unavoidable, use ScopedAllowBaseSyncPrimitives in a task posted
+//   to base::ThreadPoolInstance with base::MayBlock().
 //
-// Avoid using this. Prefer making blocking calls from tasks posted to
-// base::TaskScheduler with base::MayBlock().
+// - Accessing singletons: Accessing global state (Singleton / LazyInstance) is
+//   problematic on threads whom aren't joined on shutdown as they can be using
+//   the state as it becomes invalid during tear down. base::NoDestructor is the
+//   preferred alternative for global state and doesn't have this restriction.
+//
+// - Long CPU work: Refers to any code that takes more than 100 ms to
+//   run when there is no CPU contention and no hard page faults and therefore,
+//   is not suitable to run on a thread required to keep the browser responsive
+//   (where jank could be visible to the user).
+//
+// The following disallowance functions are offered:
+//  - DisallowBlocking(): Disallows blocking calls on the current thread.
+//  - DisallowBaseSyncPrimitives(): Disallows waiting on a //base sync primitive
+//    on the current thread.
+//  - DisallowSingleton(): Disallows using singletons on the current thread.
+//  - DisallowUnresponsiveTasks(): Disallows blocking calls, waiting on a //base
+//    sync primitive, and long CPU work on the current thread.
+//
+// In addition, scoped-allowance mechanisms are offered to make an exception
+// within a scope for a behavior that is normally disallowed.
+//  - ScopedAllowBlocking: Allows blocking calls. Prefer to use base::MayBlock()
+//    instead.
+//  - ScopedAllowBaseSyncPrimitives: Allows waiting on a //base sync primitive.
+//    Must also be in a scope where blocking calls are allowed.
+//  - ScopedAllowBaseSyncPrimitivesOutsideBlockingScope: Allow waiting on a
+//    //base sync primitive, even in a scope where blocking calls are
+//    disallowed. Prefer to use a combination of base::MayBlock() and
+//    ScopedAllowBaseSyncPrimitives.
+//
+// Avoid using allowances outside of unit tests. In unit tests, use allowances
+// with the suffix "ForTesting":
+//  - ScopedAllowBlockingForTesting: Allows blocking calls in unit tests.
+//  - ScopedAllowBaseSyncPrimitivesForTesting: Allows waiting on a //base sync
+//    primitive in unit tests. For convenience this can be used in a scope
+//    where blocking calls are disallowed. Note that base::TestWaitableEvent can
+//    be used without this, also for convenience.
+//
+// Prefer making blocking calls from tasks posted to base::ThreadPoolInstance
+// with base::MayBlock().
+//
+// Instead of waiting on a WaitableEvent or a ConditionVariable, prefer putting
+// the work that should happen after the wait in a continuation callback and
+// post it from where the WaitableEvent or ConditionVariable would have been
+// signaled. If something needs to be scheduled after many tasks have executed,
+// use base::BarrierClosure.
+//
+// On Windows, join processes asynchronously using base::win::ObjectWatcher.
 //
 // Where unavoidable, put ScopedAllow* instances in the narrowest scope possible
-// in the caller making the blocking call but no further down. That is: if a
+// in the caller making the blocking call but no further down. For example: if a
 // Cleanup() method needs to do a blocking call, document Cleanup() as blocking
 // and add a ScopedAllowBlocking instance in callers that can't avoid making
 // this call from a context where blocking is banned, as such:
+//
 //   void Client::MyMethod() {
 //     (...)
 //     {
@@ -246,72 +124,609 @@
 // somehow knows that in practice this will not block), it might be okay to hide
 // the ScopedAllowBlocking instance in the impl with a comment explaining why
 // that's okay.
-class BASE_EXPORT ScopedAllowBlocking {
- private:
-  // This can only be instantiated by friends. Use ScopedAllowBlockingForTesting
-  // in unit tests to avoid the friend requirement.
-  FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest, ScopedAllowBlocking);
-  friend class AdjustOOMScoreHelper;
-  friend class android_webview::ScopedAllowInitGLBindings;
-  friend class audio::OutputDevice;
-  friend class content::BrowserProcessSubThread;
-  friend class content::GpuProcessTransportFactory;
-  friend class cronet::CronetPrefsManager;
-  friend class cronet::CronetURLRequestContext;
-  friend class media::AudioInputDevice;
-  friend class mojo::CoreLibraryInitializer;
-  friend class resource_coordinator::TabManagerDelegate;  // crbug.com/778703
-  friend class ui::MaterialDesignController;
-  friend class ScopedAllowBlockingForTesting;
-  friend class StackSamplingProfiler;
 
-  ScopedAllowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
-  ~ScopedAllowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
+class BrowserProcessImpl;
+class BrowserThemePack;
+class ChromeNSSCryptoModuleDelegate;
+class DesktopNotificationBalloon;
+class FirefoxProfileLock;
+class KeyStorageLinux;
+class NativeBackendKWallet;
+class NativeDesktopMediaList;
+class Profile;
+class ProfileImpl;
+class StartupTabProviderImpl;
+class GaiaConfig;
+class WebEngineBrowserMainParts;
+class ScopedAllowBlockingForProfile;
+
+namespace base {
+class File;
+class FilePath;
+}  // namespace base
+
+Profile* GetLastProfileMac();
+bool EnsureBrowserStateDirectoriesCreated(const base::FilePath&,
+                                          const base::FilePath&,
+                                          const base::FilePath&);
+
+namespace android_webview {
+class AwFormDatabaseService;
+class CookieManager;
+class JsSandboxIsolate;
+class ScopedAllowInitGLBindings;
+class VizCompositorThreadRunnerWebView;
+}  // namespace android_webview
+namespace ash {
+class MojoUtils;
+class BrowserDataBackMigrator;
+class LoginEventRecorder;
+class StartupCustomizationDocument;
+class StartupUtils;
+bool CameraAppUIShouldEnableLocalOverride(const std::string&);
+namespace system {
+class StatisticsProviderImpl;
+}  // namespace system
+}  // namespace ash
+namespace audio {
+class OutputDevice;
+}
+namespace blink {
+class DiskDataAllocator;
+class IdentifiabilityActiveSampler;
+class RTCVideoDecoderAdapter;
+class RTCVideoEncoder;
+class SourceStream;
+class VideoFrameResourceProvider;
+class WebRtcVideoFrameAdapter;
+class LegacyWebRtcVideoFrameAdapter;
+class VideoTrackRecorderImplContextProvider;
+class WorkerThread;
+namespace scheduler {
+class NonMainThreadImpl;
+}
+}  // namespace blink
+namespace cc {
+class CategorizedWorkerPoolImpl;
+class CategorizedWorkerPoolJob;
+class CategorizedWorkerPool;
+class CompletionEvent;
+class TileTaskManagerImpl;
+}  // namespace cc
+namespace chrome {
+bool PathProvider(int, base::FilePath*);
+void SessionEnding();
+}  // namespace chrome
+namespace chromecast {
+class CrashUtil;
+}
+namespace chromeos {
+class BlockingMethodCaller;
+namespace system {
+bool IsCoreSchedulingAvailable();
+int NumberOfPhysicalCores();
+}  // namespace system
+}  // namespace chromeos
+namespace chrome_cleaner {
+class ResetShortcutsComponent;
+class SystemReportComponent;
+}  // namespace chrome_cleaner
+namespace content {
+class BrowserGpuChannelHostFactory;
+class BrowserMainLoop;
+class BrowserProcessIOThread;
+class BrowserTestBase;
+#if BUILDFLAG(IS_IOS)
+class ContentMainRunnerImpl;
+#endif  // BUILDFLAG(IS_IOS)
+class DesktopCaptureDevice;
+class DWriteFontCollectionProxy;
+class DWriteFontProxyImpl;
+class EmergencyTraceFinalisationCoordinator;
+class InProcessUtilityThread;
+class NestedMessagePumpAndroid;
+class NetworkServiceInstancePrivate;
+class PepperPrintSettingsManagerImpl;
+class RenderProcessHostImpl;
+class RenderProcessHost;
+class RenderWidgetHostViewMac;
+class RendererBlinkPlatformImpl;
+class RTCVideoDecoder;
+class SandboxHostLinux;
+class ScopedAllowWaitForDebugURL;
+class ServiceWorkerContextClient;
+class ShellPathProvider;
+class SynchronousCompositor;
+class SynchronousCompositorHost;
+class SynchronousCompositorSyncCallBridge;
+class ScopedAllowBlockingForViewAura;
+class TextInputClientMac;
+class WebContentsImpl;
+class WebContentsViewMac;
+base::File CreateFileForDrop(base::FilePath*);
+}  // namespace content
+namespace cronet {
+class CronetPrefsManager;
+class CronetContext;
+}  // namespace cronet
+namespace crosapi {
+class LacrosThreadTypeDelegate;
+}  // namespace crosapi
+namespace crypto {
+class ScopedAllowBlockingForNSS;
+}
+namespace dbus {
+class Bus;
+}
+namespace drive {
+class FakeDriveService;
+}
+namespace device {
+class UsbContext;
+}
+namespace discardable_memory {
+class ClientDiscardableSharedMemoryManager;
+}
+namespace disk_cache {
+class BackendImpl;
+class InFlightIO;
+bool CleanupDirectorySync(const base::FilePath&);
+}  // namespace disk_cache
+namespace enterprise_connectors {
+class LinuxKeyRotationCommand;
+}  // namespace enterprise_connectors
+namespace extensions {
+class InstalledLoader;
+class UnpackedInstaller;
+}  // namespace extensions
+namespace font_service::internal {
+class MappedFontFile;
+}
+namespace functions {
+class ExecScriptScopedAllowBaseSyncPrimitives;
+}
+namespace gl {
+struct GLImplementationParts;
+namespace init {
+bool InitializeStaticGLBindings(GLImplementationParts);
+}
+}  // namespace gl
+namespace history_report {
+class HistoryReportJniBridge;
+}
+namespace ios_web_view {
+class WebViewBrowserState;
+}
+namespace io_thread {
+class IOSIOThread;
+}
+namespace leveldb::port {
+class CondVar;
+}  // namespace leveldb::port
+namespace nearby::chrome {
+class ScheduledExecutor;
+class SubmittableExecutor;
+}  // namespace nearby::chrome
+namespace media {
+class AudioInputDevice;
+class AudioOutputDevice;
+class BlockingUrlProtocol;
+class FileVideoCaptureDeviceFactory;
+class MojoVideoEncodeAccelerator;
+class PaintCanvasVideoRenderer;
+}  // namespace media
+namespace memory_instrumentation {
+class OSMetrics;
+}
+namespace memory_pressure {
+class UserLevelMemoryPressureSignalGenerator;
+}
+namespace metrics {
+class AndroidMetricsServiceClient;
+class CleanExitBeacon;
+}  // namespace metrics
+namespace midi {
+class TaskService;  // https://crbug.com/796830
+}
+namespace module_installer {
+class ScopedAllowModulePakLoad;
+}
+namespace mojo {
+class CoreLibraryInitializer;
+class SyncCallRestrictions;
+namespace core {
+class ScopedIPCSupport;
+namespace ipcz_driver {
+class MojoTrap;
+}
+}  // namespace core
+}  // namespace mojo
+namespace printing {
+class LocalPrinterHandlerDefault;
+#if BUILDFLAG(IS_MAC)
+class PrintBackendServiceImpl;
+#endif
+class PrintBackendServiceManager;
+class PrinterQuery;
+}  // namespace printing
+namespace rlz_lib {
+class FinancialPing;
+}
+namespace storage {
+class ObfuscatedFileUtil;
+}
+namespace syncer {
+class GetLocalChangesRequest;
+class HttpBridge;
+}  // namespace syncer
+namespace ui {
+class DrmThreadProxy;
+class DrmDisplayHostManager;
+class SelectFileDialogLinux;
+class ScopedAllowBlockingForGbmSurface;
+}  // namespace ui
+namespace weblayer {
+class BrowserContextImpl;
+class ContentBrowserClientImpl;
+class ProfileImpl;
+class WebLayerPathProvider;
+}  // namespace weblayer
+namespace net {
+class GSSAPISharedLibrary;
+class MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives;
+class MultiThreadedProxyResolverScopedAllowJoinOnIO;
+class NetworkChangeNotifierMac;
+class NetworkConfigWatcherMacThread;
+class ProxyConfigServiceWin;
+class ScopedAllowBlockingForSettingGetter;
+namespace internal {
+class AddressTrackerLinux;
+}
+}  // namespace net
+
+namespace proxy_resolver {
+class ScopedAllowThreadJoinForProxyResolverV8Tracing;
+}
+
+namespace remote_cocoa {
+class DroppedScreenShotCopierMac;
+class SelectFileDialogBridge;
+}  // namespace remote_cocoa
+
+namespace remoting {
+class AutoThread;
+class ScopedBypassIOThreadRestrictions;
+namespace protocol {
+class ScopedAllowSyncPrimitivesForWebRtcDataStreamAdapter;
+class ScopedAllowSyncPrimitivesForWebRtcTransport;
+class ScopedAllowThreadJoinForWebRtcTransport;
+}  // namespace protocol
+}  // namespace remoting
+
+namespace service_manager {
+class ServiceProcessLauncher;
+}
+
+namespace shell_integration_linux {
+class LaunchXdgUtilityScopedAllowBaseSyncPrimitives;
+}
+
+namespace tracing {
+class FuchsiaPerfettoProducerConnector;
+}
+
+namespace ui {
+class WindowResizeHelperMac;
+}
+
+namespace updater {
+class SystemctlLauncherScopedAllowBaseSyncPrimitives;
+}
+
+namespace viz {
+class HostGpuMemoryBufferManager;
+class ClientGpuMemoryBufferManager;
+}  // namespace viz
+
+namespace vr {
+class VrShell;
+}
+
+namespace web {
+class WebMainLoop;
+}  // namespace web
+
+namespace webrtc {
+class DesktopConfigurationMonitor;
+}
+
+namespace base {
+class Environment;
+}
+
+bool HasWaylandDisplay(base::Environment* env);
+
+namespace base {
+
+namespace sequence_manager::internal {
+class TaskQueueImpl;
+}  // namespace sequence_manager::internal
+
+namespace android {
+class JavaHandlerThread;
+class ScopedAllowBlockingForImportantFileWriter;
+}  // namespace android
+
+namespace internal {
+class GetAppOutputScopedAllowBaseSyncPrimitives;
+class JobTaskSource;
+class TaskTracker;
+bool ReadProcFile(const FilePath& file, std::string* buffer);
+}  // namespace internal
+
+namespace subtle {
+class PlatformSharedMemoryRegion;
+}
+
+namespace debug {
+class StackTrace;
+}
+
+namespace win {
+class OSInfo;
+class ScopedAllowBlockingForUserAccountControl;
+}  // namespace win
+
+class AdjustOOMScoreHelper;
+class ChromeOSVersionInfo;
+class FileDescriptorWatcher;
+class FilePath;
+class Process;
+class ScopedAllowBlockingForProc;
+class ScopedAllowBlockingForProcessMetrics;
+class ScopedAllowThreadRecallForStackSamplingProfiler;
+class SimpleThread;
+class StackSamplingProfiler;
+class TestCustomDisallow;
+class Thread;
+
+void GetNSExecutablePath(base::FilePath* path);
 
 #if DCHECK_IS_ON()
-  const bool was_disallowed_;
-#endif
+// NOT_TAIL_CALLED if dcheck-is-on so it's always evident who irrevocably
+// altered the allowance (dcheck-builds will provide the setter's stack on
+// assertion) or who made a failing Assert*() call.
+#define INLINE_OR_NOT_TAIL_CALLED NOT_TAIL_CALLED BASE_EXPORT
+#define EMPTY_BODY_IF_DCHECK_IS_OFF
+#define DEFAULT_IF_DCHECK_IS_OFF
 
-  DISALLOW_COPY_AND_ASSIGN(ScopedAllowBlocking);
+class BooleanWithStack {
+ public:
+  // Default value.
+  BooleanWithStack() = default;
+
+  // Value when explicitly set.
+  explicit BooleanWithStack(bool value);
+
+  explicit operator bool() const { return value_; }
+
+  friend std::ostream& operator<<(std::ostream& out,
+                                  const BooleanWithStack& bws);
+
+ private:
+  bool value_ = false;
+  absl::optional<debug::StackTrace> stack_;
 };
 
-class ScopedAllowBlockingForTesting {
+#else
+// inline if dcheck-is-off so it's no overhead
+#define INLINE_OR_NOT_TAIL_CALLED inline
+
+// The static_assert() eats follow-on semicolons.
+#define EMPTY_BODY_IF_DCHECK_IS_OFF \
+  {}                                \
+  static_assert(true)
+
+#define DEFAULT_IF_DCHECK_IS_OFF = default
+#endif  // DCHECK_IS_ON()
+
+namespace internal {
+
+// Asserts that blocking calls are allowed in the current scope. This is an
+// internal call, external code should use ScopedBlockingCall instead, which
+// serves as a precise annotation of the scope that may/will block.
+INLINE_OR_NOT_TAIL_CALLED void AssertBlockingAllowed()
+    EMPTY_BODY_IF_DCHECK_IS_OFF;
+INLINE_OR_NOT_TAIL_CALLED void AssertBlockingDisallowedForTesting()
+    EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+}  // namespace internal
+
+// Disallows blocking on the current thread.
+INLINE_OR_NOT_TAIL_CALLED void DisallowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+// Disallows blocking calls within its scope.
+class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedDisallowBlocking {
  public:
-  ScopedAllowBlockingForTesting() {}
-  ~ScopedAllowBlockingForTesting() {}
+  ScopedDisallowBlocking() DEFAULT_IF_DCHECK_IS_OFF;
+
+  ScopedDisallowBlocking(const ScopedDisallowBlocking&) = delete;
+  ScopedDisallowBlocking& operator=(const ScopedDisallowBlocking&) = delete;
+
+  ~ScopedDisallowBlocking() DEFAULT_IF_DCHECK_IS_OFF;
+
+ private:
+#if DCHECK_IS_ON()
+  const AutoReset<BooleanWithStack> resetter_;
+#endif
+};
+
+class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedAllowBlocking {
+ public:
+  ScopedAllowBlocking(const ScopedAllowBlocking&) = delete;
+  ScopedAllowBlocking& operator=(const ScopedAllowBlocking&) = delete;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest,
+                           NestedAllowRestoresPreviousStack);
+  FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest, ScopedAllowBlocking);
+  friend class ScopedAllowBlockingForTesting;
+
+  // This can only be instantiated by friends. Use ScopedAllowBlockingForTesting
+  // in unit tests to avoid the friend requirement.
+  // Sorted by class name (with namespace), #if blocks at the bottom.
+  friend class ::BrowserThemePack;  // http://crbug.com/80206
+  friend class ::DesktopNotificationBalloon;
+  friend class ::FirefoxProfileLock;
+  friend class ::GaiaConfig;
+  friend class ::ProfileImpl;
+  friend class ::ScopedAllowBlockingForProfile;
+  friend class ::StartupTabProviderImpl;
+  friend class ::WebEngineBrowserMainParts;
+  friend class android_webview::ScopedAllowInitGLBindings;
+  friend class ash::BrowserDataBackMigrator;
+  friend class ash::LoginEventRecorder;
+  friend class ash::MojoUtils;                     // http://crbug.com/1055467
+  friend class ash::StartupCustomizationDocument;  // http://crosbug.com/11103
+  friend class ash::StartupUtils;
+  friend class base::AdjustOOMScoreHelper;
+  friend class base::ChromeOSVersionInfo;
+  friend class base::Process;
+  friend class base::ScopedAllowBlockingForProc;
+  friend class base::ScopedAllowBlockingForProcessMetrics;
+  friend class base::StackSamplingProfiler;
+  friend class base::android::ScopedAllowBlockingForImportantFileWriter;
+  friend class base::debug::StackTrace;
+  friend class base::subtle::PlatformSharedMemoryRegion;
+  friend class base::win::ScopedAllowBlockingForUserAccountControl;
+  friend class blink::DiskDataAllocator;
+  friend class chromecast::CrashUtil;
+  friend class content::BrowserProcessIOThread;
+  friend class content::DWriteFontProxyImpl;
+  friend class content::NetworkServiceInstancePrivate;
+  friend class content::PepperPrintSettingsManagerImpl;
+  friend class content::RenderProcessHostImpl;
+  friend class content::RenderWidgetHostViewMac;  // http://crbug.com/121917
+  friend class content::
+      ScopedAllowBlockingForViewAura;  // http://crbug.com/332579
+  friend class content::ShellPathProvider;
+  friend class content::WebContentsViewMac;
+  friend class cronet::CronetContext;
+  friend class cronet::CronetPrefsManager;
+  friend class crosapi::LacrosThreadTypeDelegate;
+  friend class crypto::ScopedAllowBlockingForNSS;  // http://crbug.com/59847
+  friend class drive::FakeDriveService;
+  friend class extensions::InstalledLoader;
+  friend class extensions::UnpackedInstaller;
+  friend class font_service::internal::MappedFontFile;
+  friend class ios_web_view::WebViewBrowserState;
+  friend class io_thread::IOSIOThread;
+  friend class media::FileVideoCaptureDeviceFactory;
+  friend class memory_instrumentation::OSMetrics;
+  friend class memory_pressure::UserLevelMemoryPressureSignalGenerator;
+  friend class metrics::AndroidMetricsServiceClient;
+  friend class metrics::CleanExitBeacon;
+  friend class module_installer::ScopedAllowModulePakLoad;
+  friend class mojo::CoreLibraryInitializer;
+  friend class net::GSSAPISharedLibrary;    // http://crbug.com/66702
+  friend class net::ProxyConfigServiceWin;  // http://crbug.com/61453
+  friend class net::
+      ScopedAllowBlockingForSettingGetter;  // http://crbug.com/69057
+  friend class printing::LocalPrinterHandlerDefault;
+  friend class printing::PrintBackendServiceManager;
+  friend class printing::PrinterQuery;
+  friend class remote_cocoa::
+      DroppedScreenShotCopierMac;  // https://crbug.com/1148078
+  friend class remote_cocoa::SelectFileDialogBridge;
+  friend class remoting::
+      ScopedBypassIOThreadRestrictions;  // http://crbug.com/1144161
+  friend class ui::DrmDisplayHostManager;
+  friend class ui::ScopedAllowBlockingForGbmSurface;
+  friend class ui::SelectFileDialogLinux;
+  friend class weblayer::BrowserContextImpl;
+  friend class weblayer::ContentBrowserClientImpl;
+  friend class weblayer::ProfileImpl;
+  friend class weblayer::WebLayerPathProvider;
+#if BUILDFLAG(IS_MAC)
+  friend class printing::PrintBackendServiceImpl;
+#endif
+#if BUILDFLAG(IS_WIN)
+  friend class base::win::OSInfo;
+  friend class content::WebContentsImpl;  // http://crbug.com/1262162
+#endif
+
+  // Sorted by function name (with namespace), ignoring the return type.
+  friend bool ::EnsureBrowserStateDirectoriesCreated(const base::FilePath&,
+                                                     const base::FilePath&,
+                                                     const base::FilePath&);
+  friend Profile* ::GetLastProfileMac();  // http://crbug.com/1176734
+  friend bool ::HasWaylandDisplay(
+      base::Environment* env);  // http://crbug.com/1246928
+  friend bool ash::CameraAppUIShouldEnableLocalOverride(const std::string&);
+  friend void base::GetNSExecutablePath(base::FilePath*);
+  friend bool base::internal::ReadProcFile(const FilePath& file,
+                                           std::string* buffer);
+  friend bool chrome::PathProvider(int,
+                                   base::FilePath*);  // http://crbug.com/259796
+  friend void chrome::SessionEnding();
+  friend bool chromeos::system::IsCoreSchedulingAvailable();
+  friend int chromeos::system::NumberOfPhysicalCores();
+  friend base::File content::CreateFileForDrop(
+      base::FilePath* file_path);  // http://crbug.com/110709
+  friend bool disk_cache::CleanupDirectorySync(const base::FilePath&);
+  friend bool gl::init::InitializeStaticGLBindings(gl::GLImplementationParts);
+
+  ScopedAllowBlocking(const Location& from_here = Location::Current());
+  ~ScopedAllowBlocking();
+
+#if DCHECK_IS_ON()
+  const AutoReset<BooleanWithStack> resetter_;
+#endif
+};
+
+class [[maybe_unused, nodiscard]] ScopedAllowBlockingForTesting {
+ public:
+  ScopedAllowBlockingForTesting() = default;
+
+  ScopedAllowBlockingForTesting(const ScopedAllowBlockingForTesting&) = delete;
+  ScopedAllowBlockingForTesting& operator=(
+      const ScopedAllowBlockingForTesting&) = delete;
+
+  ~ScopedAllowBlockingForTesting() = default;
 
  private:
 #if DCHECK_IS_ON()
   ScopedAllowBlocking scoped_allow_blocking_;
 #endif
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedAllowBlockingForTesting);
 };
 
-// "Waiting on a //base sync primitive" refers to calling one of these methods:
-// - base::WaitableEvent::*Wait*
-// - base::ConditionVariable::*Wait*
-// - base::Process::WaitForExit*
-
-// Disallows waiting on a //base sync primitive on the current thread.
-INLINE_IF_DCHECK_IS_OFF void DisallowBaseSyncPrimitives()
+INLINE_OR_NOT_TAIL_CALLED void DisallowBaseSyncPrimitives()
     EMPTY_BODY_IF_DCHECK_IS_OFF;
 
-// ScopedAllowBaseSyncPrimitives(ForTesting)(OutsideBlockingScope) allow waiting
-// on a //base sync primitive within a scope where this is normally disallowed.
-//
-// Avoid using this.
-//
-// Instead of waiting on a WaitableEvent or a ConditionVariable, put the work
-// that should happen after the wait in a callback and post that callback from
-// where the WaitableEvent or ConditionVariable would have been signaled. If
-// something needs to be scheduled after many tasks have executed, use
-// base::BarrierClosure.
-//
-// On Windows, join processes asynchronously using base::win::ObjectWatcher.
+// Disallows singletons within its scope.
+class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedDisallowBaseSyncPrimitives {
+ public:
+  ScopedDisallowBaseSyncPrimitives() DEFAULT_IF_DCHECK_IS_OFF;
 
-// This can only be used in a scope where blocking is allowed.
-class BASE_EXPORT ScopedAllowBaseSyncPrimitives {
+  ScopedDisallowBaseSyncPrimitives(const ScopedDisallowBaseSyncPrimitives&) =
+      delete;
+  ScopedDisallowBaseSyncPrimitives& operator=(
+      const ScopedDisallowBaseSyncPrimitives&) = delete;
+
+  ~ScopedDisallowBaseSyncPrimitives() DEFAULT_IF_DCHECK_IS_OFF;
+
+ private:
+#if DCHECK_IS_ON()
+  const AutoReset<BooleanWithStack> resetter_;
+#endif
+};
+
+class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedAllowBaseSyncPrimitives {
+ public:
+  ScopedAllowBaseSyncPrimitives(const ScopedAllowBaseSyncPrimitives&) = delete;
+  ScopedAllowBaseSyncPrimitives& operator=(
+      const ScopedAllowBaseSyncPrimitives&) = delete;
+
  private:
   // This can only be instantiated by friends. Use
   // ScopedAllowBaseSyncPrimitivesForTesting in unit tests to avoid the friend
@@ -322,33 +737,75 @@
                            ScopedAllowBaseSyncPrimitivesResetsState);
   FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest,
                            ScopedAllowBaseSyncPrimitivesWithBlockingDisallowed);
-  friend class base::GetAppOutputScopedAllowBaseSyncPrimitives;
-  friend class content::BrowserProcessSubThread;
-  friend class content::SessionStorageDatabase;
+
+  // Allowed usage:
+  // Sorted by class name (with namespace).
+  friend class ::ChromeNSSCryptoModuleDelegate;
+  friend class ::tracing::FuchsiaPerfettoProducerConnector;
+  friend class android_webview::JsSandboxIsolate;
+  friend class base::SimpleThread;
+  friend class base::internal::GetAppOutputScopedAllowBaseSyncPrimitives;
+  friend class blink::IdentifiabilityActiveSampler;
+  friend class blink::SourceStream;
+  friend class blink::VideoTrackRecorderImplContextProvider;
+  friend class blink::WorkerThread;
+  friend class blink::scheduler::NonMainThreadImpl;
+  friend class cc::CategorizedWorkerPoolImpl;
+  friend class cc::CategorizedWorkerPoolJob;
+  friend class chrome_cleaner::ResetShortcutsComponent;
+  friend class chrome_cleaner::SystemReportComponent;
+  friend class content::BrowserMainLoop;
+  friend class content::BrowserProcessIOThread;
+  friend class content::DWriteFontCollectionProxy;
+  friend class content::RendererBlinkPlatformImpl;
+  friend class content::ServiceWorkerContextClient;
+  friend class device::UsbContext;
+  friend class enterprise_connectors::LinuxKeyRotationCommand;
   friend class functions::ExecScriptScopedAllowBaseSyncPrimitives;
-  friend class leveldb::LevelDBMojoProxy;
+  friend class history_report::HistoryReportJniBridge;
+  friend class internal::TaskTracker;
+  friend class leveldb::port::CondVar;
+  friend class nearby::chrome::ScheduledExecutor;
+  friend class nearby::chrome::SubmittableExecutor;
+  friend class media::AudioOutputDevice;
   friend class media::BlockingUrlProtocol;
+  friend class media::MojoVideoEncodeAccelerator;
   friend class mojo::core::ScopedIPCSupport;
   friend class net::MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives;
   friend class rlz_lib::FinancialPing;
   friend class shell_integration_linux::
       LaunchXdgUtilityScopedAllowBaseSyncPrimitives;
+  friend class storage::ObfuscatedFileUtil;
+  friend class syncer::HttpBridge;
+  friend class syncer::GetLocalChangesRequest;
+  friend class updater::SystemctlLauncherScopedAllowBaseSyncPrimitives;
+  friend class viz::ClientGpuMemoryBufferManager;
   friend class webrtc::DesktopConfigurationMonitor;
-  friend class content::ServiceWorkerSubresourceLoader;
-  friend class blink::VideoFrameResourceProvider;
 
-  ScopedAllowBaseSyncPrimitives() EMPTY_BODY_IF_DCHECK_IS_OFF;
-  ~ScopedAllowBaseSyncPrimitives() EMPTY_BODY_IF_DCHECK_IS_OFF;
+  // Usage that should be fixed:
+  // Sorted by class name (with namespace).
+  friend class ::NativeBackendKWallet;  // http://crbug.com/125331
+  friend class ::ash::system::
+      StatisticsProviderImpl;                      // http://crbug.com/125385
+  friend class blink::VideoFrameResourceProvider;  // http://crbug.com/878070
+
+  ScopedAllowBaseSyncPrimitives() DEFAULT_IF_DCHECK_IS_OFF;
+  ~ScopedAllowBaseSyncPrimitives() DEFAULT_IF_DCHECK_IS_OFF;
 
 #if DCHECK_IS_ON()
-  const bool was_disallowed_;
+  const AutoReset<BooleanWithStack> resetter_;
 #endif
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedAllowBaseSyncPrimitives);
 };
 
-// This can be used in a scope where blocking is disallowed.
-class BASE_EXPORT ScopedAllowBaseSyncPrimitivesOutsideBlockingScope {
+class BASE_EXPORT
+    [[maybe_unused,
+      nodiscard]] ScopedAllowBaseSyncPrimitivesOutsideBlockingScope {
+ public:
+  ScopedAllowBaseSyncPrimitivesOutsideBlockingScope(
+      const ScopedAllowBaseSyncPrimitivesOutsideBlockingScope&) = delete;
+  ScopedAllowBaseSyncPrimitivesOutsideBlockingScope& operator=(
+      const ScopedAllowBaseSyncPrimitivesOutsideBlockingScope&) = delete;
+
  private:
   // This can only be instantiated by friends. Use
   // ScopedAllowBaseSyncPrimitivesForTesting in unit tests to avoid the friend
@@ -358,206 +815,218 @@
   FRIEND_TEST_ALL_PREFIXES(
       ThreadRestrictionsTest,
       ScopedAllowBaseSyncPrimitivesOutsideBlockingScopeResetsState);
+
+  // Allowed usage:
+  // Sorted by class name (with namespace).
+  friend class ::BrowserProcessImpl;  // http://crbug.com/125207
   friend class ::KeyStorageLinux;
+  friend class ::NativeDesktopMediaList;
+  friend class android::JavaHandlerThread;
+  friend class android_webview::
+      AwFormDatabaseService;  // http://crbug.com/904431
+  friend class android_webview::CookieManager;
+  friend class android_webview::VizCompositorThreadRunnerWebView;
+  friend class audio::OutputDevice;
+  friend class base::FileDescriptorWatcher;
+  friend class base::ScopedAllowThreadRecallForStackSamplingProfiler;
+  friend class base::StackSamplingProfiler;
+  friend class base::internal::JobTaskSource;
+  friend class base::sequence_manager::internal::TaskQueueImpl;
+  friend class blink::LegacyWebRtcVideoFrameAdapter;
+  friend class blink::RTCVideoDecoderAdapter;
+  friend class blink::RTCVideoEncoder;
+  friend class blink::WebRtcVideoFrameAdapter;
+  friend class cc::CategorizedWorkerPoolImpl;
+  friend class cc::CategorizedWorkerPoolJob;
+  friend class cc::CategorizedWorkerPool;
+  friend class cc::TileTaskManagerImpl;
+  friend class content::DesktopCaptureDevice;
+  friend class content::EmergencyTraceFinalisationCoordinator;
+  friend class content::InProcessUtilityThread;
+  friend class content::RenderProcessHost;
+  friend class content::RTCVideoDecoder;
+  friend class content::SandboxHostLinux;
+  friend class content::ScopedAllowWaitForDebugURL;
   friend class content::SynchronousCompositor;
   friend class content::SynchronousCompositorHost;
   friend class content::SynchronousCompositorSyncCallBridge;
-  friend class midi::TaskService;  // https://crbug.com/796830
+  friend class media::AudioInputDevice;
+  friend class media::AudioOutputDevice;
+  friend class media::PaintCanvasVideoRenderer;
+  friend class mojo::SyncCallRestrictions;
+  friend class mojo::core::ipcz_driver::MojoTrap;
+  friend class net::NetworkConfigWatcherMacThread;
+  friend class ui::DrmThreadProxy;
+  friend class viz::HostGpuMemoryBufferManager;
+  friend class vr::VrShell;
+
+  // Usage that should be fixed:
+  friend class ::chromeos::BlockingMethodCaller;  // http://crbug.com/125360
+  friend class base::Thread;                      // http://crbug.com/918039
+  friend class cc::CompletionEvent;               // http://crbug.com/902653
+  friend class content::
+      BrowserGpuChannelHostFactory;                 // http://crbug.com/125248
+  friend class content::TextInputClientMac;         // http://crbug.com/121917
+  friend class dbus::Bus;                           // http://crbug.com/125222
+  friend class discardable_memory::
+      ClientDiscardableSharedMemoryManager;         // http://crbug.com/1396355
+  friend class disk_cache::BackendImpl;             // http://crbug.com/74623
+  friend class disk_cache::InFlightIO;              // http://crbug.com/74623
+  friend class midi::TaskService;                   // https://crbug.com/796830
+  friend class net::
+      MultiThreadedProxyResolverScopedAllowJoinOnIO;  // http://crbug.com/69710
+  friend class net::NetworkChangeNotifierMac;         // http://crbug.com/125097
+  friend class net::internal::AddressTrackerLinux;    // http://crbug.com/125097
+  friend class proxy_resolver::
+      ScopedAllowThreadJoinForProxyResolverV8Tracing;  // http://crbug.com/69710
+  friend class remoting::AutoThread;  // https://crbug.com/944316
+  friend class remoting::protocol::
+      ScopedAllowSyncPrimitivesForWebRtcDataStreamAdapter;  // http://b/233844893
+  friend class remoting::protocol::
+      ScopedAllowSyncPrimitivesForWebRtcTransport;  // http://crbug.com/1198501
+  friend class remoting::protocol::
+      ScopedAllowThreadJoinForWebRtcTransport;  // http://crbug.com/660081
   // Not used in production yet, https://crbug.com/844078.
   friend class service_manager::ServiceProcessLauncher;
-  friend class viz::HostGpuMemoryBufferManager;
+  friend class ui::WindowResizeHelperMac;  // http://crbug.com/902829
 
-  ScopedAllowBaseSyncPrimitivesOutsideBlockingScope()
-      EMPTY_BODY_IF_DCHECK_IS_OFF;
-  ~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope()
-      EMPTY_BODY_IF_DCHECK_IS_OFF;
+  ScopedAllowBaseSyncPrimitivesOutsideBlockingScope(
+      const Location& from_here = Location::Current());
+
+  ~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope();
 
 #if DCHECK_IS_ON()
-  const bool was_disallowed_;
+  const AutoReset<BooleanWithStack> resetter_;
 #endif
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedAllowBaseSyncPrimitivesOutsideBlockingScope);
 };
 
-// This can be used in tests without being a friend of
-// ScopedAllowBaseSyncPrimitives(OutsideBlockingScope).
-class BASE_EXPORT ScopedAllowBaseSyncPrimitivesForTesting {
+// Allow base-sync-primitives in tests, doesn't require explicit friend'ing like
+// ScopedAllowBaseSyncPrimitives-types aimed at production do.
+// Note: For WaitableEvents in the test logic, base::TestWaitableEvent is
+// exposed as a convenience to avoid the need for
+// ScopedAllowBaseSyncPrimitivesForTesting.
+class BASE_EXPORT
+    [[maybe_unused, nodiscard]] ScopedAllowBaseSyncPrimitivesForTesting {
  public:
-  ScopedAllowBaseSyncPrimitivesForTesting() EMPTY_BODY_IF_DCHECK_IS_OFF;
-  ~ScopedAllowBaseSyncPrimitivesForTesting() EMPTY_BODY_IF_DCHECK_IS_OFF;
+  ScopedAllowBaseSyncPrimitivesForTesting() DEFAULT_IF_DCHECK_IS_OFF;
+
+  ScopedAllowBaseSyncPrimitivesForTesting(
+      const ScopedAllowBaseSyncPrimitivesForTesting&) = delete;
+  ScopedAllowBaseSyncPrimitivesForTesting& operator=(
+      const ScopedAllowBaseSyncPrimitivesForTesting&) = delete;
+
+  ~ScopedAllowBaseSyncPrimitivesForTesting() DEFAULT_IF_DCHECK_IS_OFF;
 
  private:
 #if DCHECK_IS_ON()
-  const bool was_disallowed_;
+  const AutoReset<BooleanWithStack> resetter_;
 #endif
+};
 
-  DISALLOW_COPY_AND_ASSIGN(ScopedAllowBaseSyncPrimitivesForTesting);
+// Counterpart to base::DisallowUnresponsiveTasks() for tests to allow them to
+// block their thread after it was banned.
+class BASE_EXPORT
+    [[maybe_unused, nodiscard]] ScopedAllowUnresponsiveTasksForTesting {
+ public:
+  ScopedAllowUnresponsiveTasksForTesting() DEFAULT_IF_DCHECK_IS_OFF;
+
+  ScopedAllowUnresponsiveTasksForTesting(
+      const ScopedAllowUnresponsiveTasksForTesting&) = delete;
+  ScopedAllowUnresponsiveTasksForTesting& operator=(
+      const ScopedAllowUnresponsiveTasksForTesting&) = delete;
+
+  ~ScopedAllowUnresponsiveTasksForTesting() DEFAULT_IF_DCHECK_IS_OFF;
+
+ private:
+#if DCHECK_IS_ON()
+  const AutoReset<BooleanWithStack> base_sync_resetter_;
+  const AutoReset<BooleanWithStack> blocking_resetter_;
+  const AutoReset<BooleanWithStack> cpu_resetter_;
+#endif
 };
 
 namespace internal {
 
 // Asserts that waiting on a //base sync primitive is allowed in the current
 // scope.
-INLINE_IF_DCHECK_IS_OFF void AssertBaseSyncPrimitivesAllowed()
+INLINE_OR_NOT_TAIL_CALLED void AssertBaseSyncPrimitivesAllowed()
     EMPTY_BODY_IF_DCHECK_IS_OFF;
 
 // Resets all thread restrictions on the current thread.
-INLINE_IF_DCHECK_IS_OFF void ResetThreadRestrictionsForTesting()
+INLINE_OR_NOT_TAIL_CALLED void ResetThreadRestrictionsForTesting()
+    EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+// Check whether the current thread is allowed to use singletons (Singleton /
+// LazyInstance).  DCHECKs if not.
+INLINE_OR_NOT_TAIL_CALLED void AssertSingletonAllowed()
     EMPTY_BODY_IF_DCHECK_IS_OFF;
 
 }  // namespace internal
 
-// "Long CPU" work refers to any code that takes more than 100 ms to
-// run when there is no CPU contention and no hard page faults and therefore,
-// is not suitable to run on a thread required to keep the browser responsive
-// (where jank could be visible to the user).
+// Disallow using singleton on the current thread.
+INLINE_OR_NOT_TAIL_CALLED void DisallowSingleton() EMPTY_BODY_IF_DCHECK_IS_OFF;
 
-// Asserts that running long CPU work is allowed in the current scope.
-INLINE_IF_DCHECK_IS_OFF void AssertLongCPUWorkAllowed()
-    EMPTY_BODY_IF_DCHECK_IS_OFF;
-
-// Disallows all tasks that may be unresponsive on the current thread. This
-// disallows blocking calls, waiting on a //base sync primitive and long CPU
-// work.
-INLINE_IF_DCHECK_IS_OFF void DisallowUnresponsiveTasks()
-    EMPTY_BODY_IF_DCHECK_IS_OFF;
-
-class BASE_EXPORT ThreadRestrictions {
- public:
-  // Constructing a ScopedAllowIO temporarily allows IO for the current
-  // thread.  Doing this is almost certainly always incorrect.
-  //
-  // DEPRECATED. Use ScopedAllowBlocking(ForTesting).
-  class BASE_EXPORT ScopedAllowIO {
-   public:
-    ScopedAllowIO() EMPTY_BODY_IF_DCHECK_IS_OFF;
-    ~ScopedAllowIO() EMPTY_BODY_IF_DCHECK_IS_OFF;
-
-   private:
-#if DCHECK_IS_ON()
-    const bool was_allowed_;
-#endif
-
-    DISALLOW_COPY_AND_ASSIGN(ScopedAllowIO);
-  };
-
-#if DCHECK_IS_ON()
-  // Set whether the current thread to make IO calls.
-  // Threads start out in the *allowed* state.
-  // Returns the previous value.
-  //
-  // DEPRECATED. Use ScopedAllowBlocking(ForTesting) or ScopedDisallowBlocking.
-  static bool SetIOAllowed(bool allowed);
-
-  // Set whether the current thread can use singletons.  Returns the previous
-  // value.
-  static bool SetSingletonAllowed(bool allowed);
-
-  // Check whether the current thread is allowed to use singletons (Singleton /
-  // LazyInstance).  DCHECKs if not.
-  static void AssertSingletonAllowed();
-
-  // Disable waiting on the current thread. Threads start out in the *allowed*
-  // state. Returns the previous value.
-  //
-  // DEPRECATED. Use DisallowBaseSyncPrimitives.
-  static void DisallowWaiting();
 #if defined(STARBOARD)
-  // Get whether the current thread can use singletons.
-  static bool GetSingletonAllowed();
-#endif  // defined(STARBOARD)
+#if DCHECK_IS_ON()
+INLINE_OR_NOT_TAIL_CALLED bool GetSingletonAllowed() EMPTY_BODY_IF_DCHECK_IS_OFF;
 #else
-  // Inline the empty definitions of these functions so that they can be
-  // compiled out.
-  static bool SetIOAllowed(bool allowed) { return true; }
-  static bool SetSingletonAllowed(bool allowed) { return true; }
-  static void AssertSingletonAllowed() {}
-  static void DisallowWaiting() {}
-#if defined(STARBOARD)
-  // Get whether the current thread can use singletons.
-  static bool GetSingletonAllowed() {return true;}
-#endif  // defined(STARBOARD)
+INLINE_OR_NOT_TAIL_CALLED bool GetSingletonAllowed() { return true; }
 #endif
+#endif
+
+// Disallows singletons within its scope.
+class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedDisallowSingleton {
+ public:
+  ScopedDisallowSingleton() DEFAULT_IF_DCHECK_IS_OFF;
+
+  ScopedDisallowSingleton(const ScopedDisallowSingleton&) = delete;
+  ScopedDisallowSingleton& operator=(const ScopedDisallowSingleton&) = delete;
+
+  ~ScopedDisallowSingleton() DEFAULT_IF_DCHECK_IS_OFF;
 
  private:
-  // DO NOT ADD ANY OTHER FRIEND STATEMENTS.
-  // BEGIN ALLOWED USAGE.
-  friend class android_webview::AwFormDatabaseService;
-  friend class android_webview::CookieManager;
-  friend class base::StackSamplingProfiler;
-  friend class content::BrowserMainLoop;
-  friend class content::BrowserShutdownProfileDumper;
-  friend class content::BrowserTestBase;
-  friend class content::NestedMessagePumpAndroid;
-  friend class content::ScopedAllowWaitForAndroidLayoutTests;
-  friend class content::ScopedAllowWaitForDebugURL;
-  friend class ::HistogramSynchronizer;
-  friend class internal::TaskTracker;
-  friend class cc::CompletionEvent;
-  friend class cc::SingleThreadTaskGraphRunner;
-  friend class content::CategorizedWorkerPool;
-  friend class remoting::AutoThread;
-  friend class ui::WindowResizeHelperMac;
-  friend class MessagePumpDefault;
-  friend class SimpleThread;
-  friend class Thread;
-  friend class ThreadTestHelper;
-  friend class PlatformThread;
-  friend class android::JavaHandlerThread;
-  friend class mojo::SyncCallRestrictions;
-  friend class ui::CommandBufferClientImpl;
-  friend class ui::CommandBufferLocal;
-  friend class ui::GpuState;
-
-  // END ALLOWED USAGE.
-  // BEGIN USAGE THAT NEEDS TO BE FIXED.
-  friend class ::chromeos::BlockingMethodCaller;  // http://crbug.com/125360
-  friend class ::chromeos::system::StatisticsProviderImpl;  // http://crbug.com/125385
-  friend class chrome_browser_net::Predictor;     // http://crbug.com/78451
-  friend class
-      content::BrowserGpuChannelHostFactory;      // http://crbug.com/125248
-  friend class content::TextInputClientMac;       // http://crbug.com/121917
-  friend class dbus::Bus;                         // http://crbug.com/125222
-  friend class disk_cache::BackendImpl;           // http://crbug.com/74623
-  friend class disk_cache::InFlightIO;            // http://crbug.com/74623
-  friend class gpu::GpuChannelHost;               // http://crbug.com/125264
-  friend class net::internal::AddressTrackerLinux;  // http://crbug.com/125097
-  friend class net::NetworkChangeNotifierMac;     // http://crbug.com/125097
-  friend class ::BrowserProcessImpl;              // http://crbug.com/125207
-  friend class ::NativeBackendKWallet;            // http://crbug.com/125331
-#if !defined(OFFICIAL_BUILD)
-  friend class content::SoftwareOutputDeviceMus;  // Interim non-production code
-#endif
-// END USAGE THAT NEEDS TO BE FIXED.
-
 #if DCHECK_IS_ON()
-  // DEPRECATED. Use ScopedAllowBaseSyncPrimitives.
-  static bool SetWaitAllowed(bool allowed);
-#else
-  static bool SetWaitAllowed(bool allowed) { return true; }
+  const AutoReset<BooleanWithStack> resetter_;
 #endif
-
-  // Constructing a ScopedAllowWait temporarily allows waiting on the current
-  // thread.  Doing this is almost always incorrect, which is why we limit who
-  // can use this through friend.
-  //
-  // DEPRECATED. Use ScopedAllowBaseSyncPrimitives.
-  class BASE_EXPORT ScopedAllowWait {
-   public:
-    ScopedAllowWait() EMPTY_BODY_IF_DCHECK_IS_OFF;
-    ~ScopedAllowWait() EMPTY_BODY_IF_DCHECK_IS_OFF;
-
-   private:
-#if DCHECK_IS_ON()
-    const bool was_allowed_;
-#endif
-
-    DISALLOW_COPY_AND_ASSIGN(ScopedAllowWait);
-  };
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions);
 };
 
+// Asserts that running long CPU work is allowed in the current scope.
+INLINE_OR_NOT_TAIL_CALLED void AssertLongCPUWorkAllowed()
+    EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+INLINE_OR_NOT_TAIL_CALLED void DisallowUnresponsiveTasks()
+    EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+// Friend-only methods to permanently allow the current thread to use
+// blocking/sync-primitives calls. Threads start out in the *allowed* state but
+// are typically *disallowed* via the above base::Disallow*() methods after
+// being initialized.
+//
+// Only use these to permanently set the allowance on a thread, e.g. on
+// shutdown. For temporary allowances, use scopers above.
+class BASE_EXPORT PermanentThreadAllowance {
+ public:
+  // Class is merely a namespace-with-friends.
+  PermanentThreadAllowance() = delete;
+
+ private:
+  // Sorted by class name (with namespace)
+  friend class base::TestCustomDisallow;
+  friend class content::BrowserMainLoop;
+  friend class content::BrowserTestBase;
+#if BUILDFLAG(IS_IOS)
+  friend class content::ContentMainRunnerImpl;
+#endif  // BUILDFLAG(IS_IOS)
+  friend class web::WebMainLoop;
+
+  static void AllowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
+  static void AllowBaseSyncPrimitives() EMPTY_BODY_IF_DCHECK_IS_OFF;
+};
+
+#undef INLINE_OR_NOT_TAIL_CALLED
+#undef EMPTY_BODY_IF_DCHECK_IS_OFF
+#undef DEFAULT_IF_DCHECK_IS_OFF
+
 }  // namespace base
 
 #endif  // BASE_THREADING_THREAD_RESTRICTIONS_H_
diff --git a/base/threading/thread_restrictions_unittest.cc b/base/threading/thread_restrictions_unittest.cc
index 4b81b22..846a153 100644
--- a/base/threading/thread_restrictions_unittest.cc
+++ b/base/threading/thread_restrictions_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -6,10 +6,13 @@
 
 #include <utility>
 
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/macros.h"
+#include "base/compiler_specific.h"
+#include "base/dcheck_is_on.h"
+#include "base/debug/stack_trace.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
 #include "base/test/gtest_util.h"
+#include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -19,47 +22,50 @@
 class ThreadRestrictionsTest : public testing::Test {
  public:
   ThreadRestrictionsTest() = default;
+
+  ThreadRestrictionsTest(const ThreadRestrictionsTest&) = delete;
+  ThreadRestrictionsTest& operator=(const ThreadRestrictionsTest&) = delete;
+
   ~ThreadRestrictionsTest() override {
     internal::ResetThreadRestrictionsForTesting();
   }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ThreadRestrictionsTest);
 };
 
 }  // namespace
 
 TEST_F(ThreadRestrictionsTest, BlockingAllowedByDefault) {
-  AssertBlockingAllowed();
+  internal::AssertBlockingAllowed();
 }
 
 TEST_F(ThreadRestrictionsTest, ScopedDisallowBlocking) {
   {
     ScopedDisallowBlocking scoped_disallow_blocking;
-    EXPECT_DCHECK_DEATH({ AssertBlockingAllowed(); });
+    EXPECT_DCHECK_DEATH({ internal::AssertBlockingAllowed(); });
   }
-  AssertBlockingAllowed();
+  internal::AssertBlockingAllowed();
 }
 
 TEST_F(ThreadRestrictionsTest, ScopedAllowBlocking) {
   ScopedDisallowBlocking scoped_disallow_blocking;
   {
     ScopedAllowBlocking scoped_allow_blocking;
-    AssertBlockingAllowed();
+    internal::AssertBlockingAllowed();
   }
-  EXPECT_DCHECK_DEATH({ AssertBlockingAllowed(); });
+  EXPECT_DCHECK_DEATH({ internal::AssertBlockingAllowed(); });
 }
 
 TEST_F(ThreadRestrictionsTest, ScopedAllowBlockingForTesting) {
   ScopedDisallowBlocking scoped_disallow_blocking;
   {
     ScopedAllowBlockingForTesting scoped_allow_blocking_for_testing;
-    AssertBlockingAllowed();
+    internal::AssertBlockingAllowed();
   }
-  EXPECT_DCHECK_DEATH({ AssertBlockingAllowed(); });
+  EXPECT_DCHECK_DEATH({ internal::AssertBlockingAllowed(); });
 }
 
-TEST_F(ThreadRestrictionsTest, BaseSyncPrimitivesAllowedByDefault) {}
+TEST_F(ThreadRestrictionsTest, BaseSyncPrimitivesAllowedByDefault) {
+  internal::AssertBaseSyncPrimitivesAllowed();
+}
 
 TEST_F(ThreadRestrictionsTest, DisallowBaseSyncPrimitives) {
   DisallowBaseSyncPrimitives();
@@ -134,15 +140,91 @@
       scoped_allow_base_sync_primitives_for_testing;
 }
 
+TEST_F(ThreadRestrictionsTest, ScopedDisallowBaseSyncPrimitives) {
+  {
+    ScopedDisallowBaseSyncPrimitives disallow_sync_primitives;
+    EXPECT_DCHECK_DEATH({ internal::AssertBaseSyncPrimitivesAllowed(); });
+  }
+  internal::AssertBaseSyncPrimitivesAllowed();
+}
+
+TEST_F(ThreadRestrictionsTest, SingletonAllowedByDefault) {
+  internal::AssertSingletonAllowed();
+}
+
+TEST_F(ThreadRestrictionsTest, DisallowSingleton) {
+  DisallowSingleton();
+  EXPECT_DCHECK_DEATH({ internal::AssertSingletonAllowed(); });
+}
+
+TEST_F(ThreadRestrictionsTest, ScopedDisallowSingleton) {
+  {
+    ScopedDisallowSingleton disallow_sync_primitives;
+    EXPECT_DCHECK_DEATH({ internal::AssertSingletonAllowed(); });
+  }
+  internal::AssertSingletonAllowed();
+}
+
 TEST_F(ThreadRestrictionsTest, LongCPUWorkAllowedByDefault) {
   AssertLongCPUWorkAllowed();
 }
 
 TEST_F(ThreadRestrictionsTest, DisallowUnresponsiveTasks) {
   DisallowUnresponsiveTasks();
-  EXPECT_DCHECK_DEATH(AssertBlockingAllowed());
+  EXPECT_DCHECK_DEATH(internal::AssertBlockingAllowed());
   EXPECT_DCHECK_DEATH(internal::AssertBaseSyncPrimitivesAllowed());
   EXPECT_DCHECK_DEATH(AssertLongCPUWorkAllowed());
 }
 
+// thread_restriction_checks_and_has_death_tests
+#if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_ANDROID) && DCHECK_IS_ON() && \
+    defined(GTEST_HAS_DEATH_TEST)
+
+TEST_F(ThreadRestrictionsTest, BlockingCheckEmitsStack) {
+  ScopedDisallowBlocking scoped_disallow_blocking;
+  // The above ScopedDisallowBlocking should be on the blame list for who set
+  // the ban.
+  EXPECT_DEATH({ internal::AssertBlockingAllowed(); },
+               EXPENSIVE_DCHECKS_ARE_ON() &&
+                       debug::StackTrace::WillSymbolizeToStreamForTesting()
+                   ? "ScopedDisallowBlocking"
+                   : "");
+  // And the stack should mention this test body as source.
+  EXPECT_DEATH({ internal::AssertBlockingAllowed(); },
+               EXPENSIVE_DCHECKS_ARE_ON() &&
+                       debug::StackTrace::WillSymbolizeToStreamForTesting()
+                   ? "BlockingCheckEmitsStack"
+                   : "");
+}
+
+class TestCustomDisallow {
+ public:
+  NOINLINE TestCustomDisallow() { DisallowBlocking(); }
+  NOINLINE ~TestCustomDisallow() { PermanentThreadAllowance::AllowBlocking(); }
+};
+
+TEST_F(ThreadRestrictionsTest, NestedAllowRestoresPreviousStack) {
+  TestCustomDisallow custom_disallow;
+  {
+    ScopedAllowBlocking scoped_allow;
+    internal::AssertBlockingAllowed();
+  }
+  // TestCustomDisallow should be back on the blame list (as opposed to
+  // ~ScopedAllowBlocking which is the last one to have changed the state but is
+  // no longer relevant).
+  EXPECT_DEATH({ internal::AssertBlockingAllowed(); },
+               EXPENSIVE_DCHECKS_ARE_ON() &&
+                       debug::StackTrace::WillSymbolizeToStreamForTesting()
+                   ? "TestCustomDisallow"
+                   : "");
+  // And the stack should mention this test body as source.
+  EXPECT_DEATH({ internal::AssertBlockingAllowed(); },
+               EXPENSIVE_DCHECKS_ARE_ON() &&
+                       debug::StackTrace::WillSymbolizeToStreamForTesting()
+                   ? "NestedAllowRestoresPreviousStack"
+                   : "");
+}
+
+#endif  // thread_restriction_checks_and_has_death_tests
+
 }  // namespace base
diff --git a/base/threading/thread_task_runner_handle.cc b/base/threading/thread_task_runner_handle.cc
index 85b47f2..b00bfae 100644
--- a/base/threading/thread_task_runner_handle.cc
+++ b/base/threading/thread_task_runner_handle.cc
@@ -1,24 +1,9 @@
-// Copyright 2016 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 "base/threading/thread_task_runner_handle.h"
 
-#include <utility>
-
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/run_loop.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "base/threading/thread_local.h"
-
 namespace base {
-
 namespace {
 
-base::LazyInstance<base::ThreadLocalPointer<ThreadTaskRunnerHandle>>::Leaky
+base::LazyInstance<base::ThreadLocalOwnedPointer<ThreadTaskRunnerHandle>>::Leaky
     thread_task_runner_tls = LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
@@ -26,81 +11,6 @@
 // static
 const scoped_refptr<SingleThreadTaskRunner>& ThreadTaskRunnerHandle::Get() {
   ThreadTaskRunnerHandle* current = thread_task_runner_tls.Pointer()->Get();
-  CHECK(current) << "Error: This caller requires a single-threaded context "
-                    "(i.e. the current task needs to run from a "
-                    "SingleThreadTaskRunner).";
   return current->task_runner_;
 }
-
-// static
-bool ThreadTaskRunnerHandle::IsSet() {
-  return !!thread_task_runner_tls.Pointer()->Get();
 }
-
-// static
-ScopedClosureRunner ThreadTaskRunnerHandle::OverrideForTesting(
-    scoped_refptr<SingleThreadTaskRunner> overriding_task_runner) {
-  // OverrideForTesting() is not compatible with a SequencedTaskRunnerHandle
-  // being set (but SequencedTaskRunnerHandle::IsSet() includes
-  // ThreadTaskRunnerHandle::IsSet() so that's discounted as the only valid
-  // excuse for it to be true). Sadly this means that tests that merely need a
-  // SequencedTaskRunnerHandle on their main thread can be forced to use a
-  // ThreadTaskRunnerHandle if they're also using test task runners (that
-  // OverrideForTesting() when running their tasks from said main thread). To
-  // solve this: sequence_task_runner_handle.cc and thread_task_runner_handle.cc
-  // would have to be merged into a single impl file and share TLS state. This
-  // was deemed unecessary for now as most tests should use higher level
-  // constructs and not have to instantiate task runner handles on their own.
-  DCHECK(!SequencedTaskRunnerHandle::IsSet() || IsSet());
-
-  if (!IsSet()) {
-    auto top_level_ttrh = std::make_unique<ThreadTaskRunnerHandle>(
-        std::move(overriding_task_runner));
-    return ScopedClosureRunner(base::BindOnce(
-        [](std::unique_ptr<ThreadTaskRunnerHandle> ttrh_to_release) {},
-        std::move(top_level_ttrh)));
-  }
-
-  ThreadTaskRunnerHandle* ttrh = thread_task_runner_tls.Pointer()->Get();
-  // Swap the two (and below bind |overriding_task_runner|, which is now the
-  // previous one, as the |task_runner_to_restore|).
-  ttrh->task_runner_.swap(overriding_task_runner);
-
-  auto no_running_during_override =
-      std::make_unique<RunLoop::ScopedDisallowRunningForTesting>();
-
-  return ScopedClosureRunner(base::BindOnce(
-      [](scoped_refptr<SingleThreadTaskRunner> task_runner_to_restore,
-         SingleThreadTaskRunner* expected_task_runner_before_restore,
-         std::unique_ptr<RunLoop::ScopedDisallowRunningForTesting>
-             no_running_during_override) {
-        ThreadTaskRunnerHandle* ttrh = thread_task_runner_tls.Pointer()->Get();
-
-        DCHECK_EQ(expected_task_runner_before_restore, ttrh->task_runner_.get())
-            << "Nested overrides must expire their ScopedClosureRunners "
-               "in LIFO order.";
-
-        ttrh->task_runner_.swap(task_runner_to_restore);
-      },
-      std::move(overriding_task_runner),
-      base::Unretained(ttrh->task_runner_.get()),
-      std::move(no_running_during_override)));
-}
-
-ThreadTaskRunnerHandle::ThreadTaskRunnerHandle(
-    scoped_refptr<SingleThreadTaskRunner> task_runner)
-    : task_runner_(std::move(task_runner)) {
-  DCHECK(task_runner_->BelongsToCurrentThread());
-  // No SequencedTaskRunnerHandle (which includes ThreadTaskRunnerHandles)
-  // should already be set for this thread.
-  DCHECK(!SequencedTaskRunnerHandle::IsSet());
-  thread_task_runner_tls.Pointer()->Set(this);
-}
-
-ThreadTaskRunnerHandle::~ThreadTaskRunnerHandle() {
-  DCHECK(task_runner_->BelongsToCurrentThread());
-  DCHECK_EQ(thread_task_runner_tls.Pointer()->Get(), this);
-  thread_task_runner_tls.Pointer()->Set(nullptr);
-}
-
-}  // namespace base
diff --git a/base/threading/thread_task_runner_handle.h b/base/threading/thread_task_runner_handle.h
index fc66fec..5d1b453 100644
--- a/base/threading/thread_task_runner_handle.h
+++ b/base/threading/thread_task_runner_handle.h
@@ -1,57 +1,20 @@
-// Copyright 2016 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 BASE_THREADING_THREAD_TASK_RUNNER_HANDLE_H_
 #define BASE_THREADING_THREAD_TASK_RUNNER_HANDLE_H_
 
-#include "base/base_export.h"
-#include "base/callback_helpers.h"
-#include "base/compiler_specific.h"
-#include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
+#include "base/lazy_instance.h"
+#include "base/threading/thread_local.h"
 
 namespace base {
 
-// ThreadTaskRunnerHandle stores a reference to a thread's TaskRunner
-// in thread-local storage.  Callers can then retrieve the TaskRunner
-// for the current thread by calling ThreadTaskRunnerHandle::Get().
-// At most one TaskRunner may be bound to each thread at a time.
-// Prefer SequencedTaskRunnerHandle to this unless thread affinity is required.
-class BASE_EXPORT ThreadTaskRunnerHandle {
+class ThreadTaskRunnerHandle {
  public:
-  // Gets the SingleThreadTaskRunner for the current thread.
   static const scoped_refptr<SingleThreadTaskRunner>& Get();
-
-  // Returns true if the SingleThreadTaskRunner is already created for
-  // the current thread.
-  static bool IsSet();
-
-  // Overrides ThreadTaskRunnerHandle::Get()'s |task_runner_| to point at
-  // |overriding_task_runner| until the returned ScopedClosureRunner goes out of
-  // scope (instantiates a ThreadTaskRunnerHandle for that scope if |!IsSet()|).
-  // Nested overrides are allowed but callers must ensure the
-  // ScopedClosureRunners expire in LIFO (stack) order. Note: nesting
-  // ThreadTaskRunnerHandles isn't generally desired but it's useful in unit
-  // tests where multiple task runners can share the main thread for simplicity
-  // and determinism.
-  static ScopedClosureRunner OverrideForTesting(
-      scoped_refptr<SingleThreadTaskRunner> overriding_task_runner)
-      WARN_UNUSED_RESULT;
-
-  // Binds |task_runner| to the current thread. |task_runner| must belong
-  // to the current thread for this to succeed.
-  explicit ThreadTaskRunnerHandle(
-      scoped_refptr<SingleThreadTaskRunner> task_runner);
-  ~ThreadTaskRunnerHandle();
-
  private:
   scoped_refptr<SingleThreadTaskRunner> task_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadTaskRunnerHandle);
 };
 
-}  // namespace base
+}
 
-#endif  // BASE_THREADING_THREAD_TASK_RUNNER_HANDLE_H_
+#endif
diff --git a/base/threading/thread_task_runner_handle_unittest.cc b/base/threading/thread_task_runner_handle_unittest.cc
deleted file mode 100644
index 1aa02d1..0000000
--- a/base/threading/thread_task_runner_handle_unittest.cc
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2017 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 "base/threading/thread_task_runner_handle.h"
-
-#include "base/memory/ref_counted.h"
-#include "base/test/gtest_util.h"
-#include "base/test/test_simple_task_runner.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-
-TEST(ThreadTaskRunnerHandleTest, Basic) {
-  scoped_refptr<SingleThreadTaskRunner> task_runner(new TestSimpleTaskRunner);
-
-  EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet());
-  {
-    ThreadTaskRunnerHandle ttrh1(task_runner);
-    EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet());
-    EXPECT_EQ(task_runner, ThreadTaskRunnerHandle::Get());
-  }
-  EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet());
-}
-
-TEST(ThreadTaskRunnerHandleTest, DeathOnImplicitOverride) {
-  scoped_refptr<SingleThreadTaskRunner> task_runner(new TestSimpleTaskRunner);
-  scoped_refptr<SingleThreadTaskRunner> overidding_task_runner(
-      new TestSimpleTaskRunner);
-
-  ThreadTaskRunnerHandle ttrh(task_runner);
-  EXPECT_DCHECK_DEATH(
-      { ThreadTaskRunnerHandle overriding_ttrh(overidding_task_runner); });
-}
-
-TEST(ThreadTaskRunnerHandleTest, OverrideForTestingExistingTTRH) {
-  scoped_refptr<SingleThreadTaskRunner> task_runner_1(new TestSimpleTaskRunner);
-  scoped_refptr<SingleThreadTaskRunner> task_runner_2(new TestSimpleTaskRunner);
-  scoped_refptr<SingleThreadTaskRunner> task_runner_3(new TestSimpleTaskRunner);
-  scoped_refptr<SingleThreadTaskRunner> task_runner_4(new TestSimpleTaskRunner);
-
-  EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet());
-  {
-    // TTRH in place prior to override.
-    ThreadTaskRunnerHandle ttrh1(task_runner_1);
-    EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet());
-    EXPECT_EQ(task_runner_1, ThreadTaskRunnerHandle::Get());
-
-    {
-      // Override.
-      ScopedClosureRunner undo_override_2 =
-          ThreadTaskRunnerHandle::OverrideForTesting(task_runner_2);
-      EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet());
-      EXPECT_EQ(task_runner_2, ThreadTaskRunnerHandle::Get());
-
-      {
-        // Nested override.
-        ScopedClosureRunner undo_override_3 =
-            ThreadTaskRunnerHandle::OverrideForTesting(task_runner_3);
-        EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet());
-        EXPECT_EQ(task_runner_3, ThreadTaskRunnerHandle::Get());
-      }
-
-      // Back to single override.
-      EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet());
-      EXPECT_EQ(task_runner_2, ThreadTaskRunnerHandle::Get());
-
-      {
-        // Backup to double override with another TTRH.
-        ScopedClosureRunner undo_override_4 =
-            ThreadTaskRunnerHandle::OverrideForTesting(task_runner_4);
-        EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet());
-        EXPECT_EQ(task_runner_4, ThreadTaskRunnerHandle::Get());
-      }
-    }
-
-    // Back to simple TTRH.
-    EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet());
-    EXPECT_EQ(task_runner_1, ThreadTaskRunnerHandle::Get());
-  }
-  EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet());
-}
-
-TEST(ThreadTaskRunnerHandleTest, OverrideForTestingNoExistingTTRH) {
-  scoped_refptr<SingleThreadTaskRunner> task_runner_1(new TestSimpleTaskRunner);
-  scoped_refptr<SingleThreadTaskRunner> task_runner_2(new TestSimpleTaskRunner);
-
-  EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet());
-  {
-    // Override with no TTRH in place.
-    ScopedClosureRunner undo_override_1 =
-        ThreadTaskRunnerHandle::OverrideForTesting(task_runner_1);
-    EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet());
-    EXPECT_EQ(task_runner_1, ThreadTaskRunnerHandle::Get());
-
-    {
-      // Nested override works the same.
-      ScopedClosureRunner undo_override_2 =
-          ThreadTaskRunnerHandle::OverrideForTesting(task_runner_2);
-      EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet());
-      EXPECT_EQ(task_runner_2, ThreadTaskRunnerHandle::Get());
-    }
-
-    // Back to single override.
-    EXPECT_TRUE(ThreadTaskRunnerHandle::IsSet());
-    EXPECT_EQ(task_runner_1, ThreadTaskRunnerHandle::Get());
-  }
-  EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet());
-}
-
-TEST(ThreadTaskRunnerHandleTest, DeathOnTTRHOverOverride) {
-  scoped_refptr<SingleThreadTaskRunner> task_runner(new TestSimpleTaskRunner);
-  scoped_refptr<SingleThreadTaskRunner> overidding_task_runner(
-      new TestSimpleTaskRunner);
-
-  ScopedClosureRunner undo_override =
-      ThreadTaskRunnerHandle::OverrideForTesting(task_runner);
-  EXPECT_DCHECK_DEATH(
-      { ThreadTaskRunnerHandle overriding_ttrh(overidding_task_runner); });
-}
-
-}  // namespace base
diff --git a/base/threading/thread_type_delegate.cc b/base/threading/thread_type_delegate.cc
new file mode 100644
index 0000000..abef61a
--- /dev/null
+++ b/base/threading/thread_type_delegate.cc
@@ -0,0 +1,13 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_type_delegate.h"
+
+namespace base {
+
+ThreadTypeDelegate::ThreadTypeDelegate() = default;
+
+ThreadTypeDelegate::~ThreadTypeDelegate() = default;
+
+}  // namespace base
diff --git a/base/threading/thread_type_delegate.h b/base/threading/thread_type_delegate.h
new file mode 100644
index 0000000..1bbc1e0
--- /dev/null
+++ b/base/threading/thread_type_delegate.h
@@ -0,0 +1,34 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_TYPE_DELEGATE_H_
+#define BASE_THREADING_THREAD_TYPE_DELEGATE_H_
+
+#include "base/base_export.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// A ThreadTypeDelegate can intercept thread type changes. This can be used to
+// adjust thread properties via another process when the current process can't
+// directly adjust them (e.g. due to sandbox restrictions).
+class BASE_EXPORT ThreadTypeDelegate {
+ public:
+  ThreadTypeDelegate();
+
+  ThreadTypeDelegate(const ThreadTypeDelegate&) = delete;
+  ThreadTypeDelegate& operator=(const ThreadTypeDelegate&) = delete;
+
+  virtual ~ThreadTypeDelegate();
+
+  // Invoked on thread type change. Returns true if the delegate handles
+  // adjusting thread properties (i.e. //base code will not adjust thread
+  // properties such as nice value, c-group, latency sensitivity...).
+  virtual bool HandleThreadTypeChange(PlatformThreadId thread_id,
+                                      ThreadType thread_type) = 0;
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_TYPE_DELEGATE_H_
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc
index 29ce325..dd29977 100644
--- a/base/threading/thread_unittest.cc
+++ b/base/threading/thread_unittest.cc
@@ -1,31 +1,37 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/thread.h"
 
+#include <stddef.h>
+#include <stdint.h>
+
 #include <utility>
 #include <vector>
 
-#include "base/bind.h"
 #include "base/debug/leak_annotations.h"
-#include "base/macros.h"
+#include "base/functional/bind.h"
+#include "base/logging.h"
 #include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_current.h"
+#include "base/memory/raw_ptr.h"
 #include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/task/current_thread.h"
+#include "base/task/sequence_manager/sequence_manager_impl.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/test/bind.h"
 #include "base/test/gtest_util.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "starboard/types.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
 using base::Thread;
+using ::testing::NotNull;
 
 typedef PlatformTest ThreadTest;
 
@@ -44,18 +50,20 @@
     ANNOTATE_BENIGN_RACE(
         this, "Benign test-only data race on vptr - http://crbug.com/98219");
   }
+
+  SleepInsideInitThread(const SleepInsideInitThread&) = delete;
+  SleepInsideInitThread& operator=(const SleepInsideInitThread&) = delete;
+
   ~SleepInsideInitThread() override { Stop(); }
 
   void Init() override {
-    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500));
+    base::PlatformThread::Sleep(base::Milliseconds(500));
     init_called_ = true;
   }
   bool InitCalled() { return init_called_; }
 
  private:
   bool init_called_;
-
-  DISALLOW_COPY_AND_ASSIGN(SleepInsideInitThread);
 };
 
 enum ThreadEvent {
@@ -84,6 +92,9 @@
         event_list_(event_list) {
   }
 
+  CaptureToEventList(const CaptureToEventList&) = delete;
+  CaptureToEventList& operator=(const CaptureToEventList&) = delete;
+
   ~CaptureToEventList() override { Stop(); }
 
   void Init() override { event_list_->push_back(THREAD_EVENT_INIT); }
@@ -91,21 +102,23 @@
   void CleanUp() override { event_list_->push_back(THREAD_EVENT_CLEANUP); }
 
  private:
-  EventList* event_list_;
-
-  DISALLOW_COPY_AND_ASSIGN(CaptureToEventList);
+  raw_ptr<EventList> event_list_;
 };
 
 // Observer that writes a value into |event_list| when a message loop has been
 // destroyed.
 class CapturingDestructionObserver
-    : public base::MessageLoopCurrent::DestructionObserver {
+    : public base::CurrentThread::DestructionObserver {
  public:
   // |event_list| must remain valid throughout the observer's lifetime.
   explicit CapturingDestructionObserver(EventList* event_list)
       : event_list_(event_list) {
   }
 
+  CapturingDestructionObserver(const CapturingDestructionObserver&) = delete;
+  CapturingDestructionObserver& operator=(const CapturingDestructionObserver&) =
+      delete;
+
   // DestructionObserver implementation:
   void WillDestroyCurrentMessageLoop() override {
     event_list_->push_back(THREAD_EVENT_MESSAGE_LOOP_DESTROYED);
@@ -113,15 +126,13 @@
   }
 
  private:
-  EventList* event_list_;
-
-  DISALLOW_COPY_AND_ASSIGN(CapturingDestructionObserver);
+  raw_ptr<EventList> event_list_;
 };
 
 // Task that adds a destruction observer to the current message loop.
 void RegisterDestructionObserver(
-    base::MessageLoopCurrent::DestructionObserver* observer) {
-  base::MessageLoopCurrent::Get()->AddDestructionObserver(observer);
+    base::CurrentThread::DestructionObserver* observer) {
+  base::CurrentThread::Get()->AddDestructionObserver(observer);
 }
 
 // Task that calls GetThreadId() of |thread|, stores the result into |id|, then
@@ -141,16 +152,21 @@
   // message. At the same time, we should scale with the bitness of the system
   // where 12 kb is definitely not enough.
   // 12 kb = 3072 Slots on a 32-bit system, so we'll scale based off of that.
+  int multiplier = 1;
   Thread::Options options;
 #if defined(ADDRESS_SANITIZER) || !defined(NDEBUG)
   // ASan bloats the stack variables and overflows the 3072 slot stack. Some
   // debug builds also grow the stack too much.
-  options.stack_size = 2 * 3072 * sizeof(uintptr_t);
-#else
-  options.stack_size = 3072 * sizeof(uintptr_t);
+  ++multiplier;
 #endif
-  EXPECT_TRUE(a.StartWithOptions(options));
-  EXPECT_TRUE(a.message_loop());
+#if defined(LEAK_SANITIZER) && BUILDFLAG(IS_MAC)
+  // The first time an LSAN disable is fired on a thread, the LSAN Mac runtime
+  // initializes a 56k object on the stack.
+  ++multiplier;
+#endif
+  options.stack_size = 3072 * sizeof(uintptr_t) * multiplier;
+  EXPECT_TRUE(a.StartWithOptions(std::move(options)));
+  EXPECT_TRUE(a.task_runner());
   EXPECT_TRUE(a.IsRunning());
 
   base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
@@ -172,8 +188,8 @@
 
   Thread::Options options;
   options.joinable = false;
-  EXPECT_TRUE(a->StartWithOptions(options));
-  EXPECT_TRUE(a->message_loop());
+  EXPECT_TRUE(a->StartWithOptions(std::move(options)));
+  EXPECT_TRUE(a->task_runner());
   EXPECT_TRUE(a->IsRunning());
 
   // Without this call this test is racy. The above IsRunning() succeeds because
@@ -198,7 +214,7 @@
 
   // Unblock the task and give a bit of extra time to unwind QuitWhenIdle().
   block_event.Signal();
-  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
+  base::PlatformThread::Sleep(base::Milliseconds(20));
 
   // The thread should now have stopped on its own.
   EXPECT_FALSE(a->IsRunning());
@@ -210,7 +226,7 @@
   {
     Thread a("TwoTasksOnJoinableThread");
     EXPECT_TRUE(a.Start());
-    EXPECT_TRUE(a.message_loop());
+    EXPECT_TRUE(a.task_runner());
 
     // Test that all events are dispatched before the Thread object is
     // destroyed.  We do this by dispatching a sleep event before the
@@ -218,7 +234,7 @@
     a.task_runner()->PostTask(
         FROM_HERE, base::BindOnce(static_cast<void (*)(base::TimeDelta)>(
                                       &base::PlatformThread::Sleep),
-                                  base::TimeDelta::FromMilliseconds(20)));
+                                  base::Milliseconds(20)));
     a.task_runner()->PostTask(FROM_HERE,
                               base::BindOnce(&ToggleValue, &was_invoked));
   }
@@ -238,30 +254,30 @@
     Thread a("DestroyWhileRunningNonJoinableIsSafe");
     Thread::Options options;
     options.joinable = false;
-    EXPECT_TRUE(a.StartWithOptions(options));
+    EXPECT_TRUE(a.StartWithOptions(std::move(options)));
     EXPECT_TRUE(a.WaitUntilThreadStarted());
   }
 
   // Attempt to catch use-after-frees from the non-joinable thread in the
   // scope of this test if any.
-  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
+  base::PlatformThread::Sleep(base::Milliseconds(20));
 }
 
 TEST_F(ThreadTest, StopSoon) {
   Thread a("StopSoon");
   EXPECT_TRUE(a.Start());
-  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.task_runner());
   EXPECT_TRUE(a.IsRunning());
   a.StopSoon();
   a.Stop();
-  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.task_runner());
   EXPECT_FALSE(a.IsRunning());
 }
 
 TEST_F(ThreadTest, StopTwiceNop) {
   Thread a("StopTwiceNop");
   EXPECT_TRUE(a.Start());
-  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.task_runner());
   EXPECT_TRUE(a.IsRunning());
   a.StopSoon();
   // Calling StopSoon() a second time should be a nop.
@@ -269,7 +285,7 @@
   a.Stop();
   // Same with Stop().
   a.Stop();
-  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.task_runner());
   EXPECT_FALSE(a.IsRunning());
   // Calling them when not running should also nop.
   a.StopSoon();
@@ -284,13 +300,15 @@
 
   Thread b("NonOwningThread");
   b.Start();
-  EXPECT_DCHECK_DEATH({
-    // Stopping |a| on |b| isn't allowed.
-    b.task_runner()->PostTask(
-        FROM_HERE, base::BindOnce(&Thread::Stop, base::Unretained(&a)));
-    // Block here so the DCHECK on |b| always happens in this scope.
-    base::PlatformThread::Sleep(base::TimeDelta::Max());
-  });
+  EXPECT_DCHECK_DEATH_WITH(
+      {
+        // Stopping |a| on |b| isn't allowed.
+        b.task_runner()->PostTask(
+            FROM_HERE, base::BindOnce(&Thread::Stop, base::Unretained(&a)));
+        // Block here so the DCHECK on |b| always happens in this scope.
+        base::PlatformThread::Sleep(base::TimeDelta::Max());
+      },
+      "owning_sequence_checker_.CalledOnValidSequence()");
 }
 
 TEST_F(ThreadTest, TransferOwnershipAndStop) {
@@ -322,23 +340,23 @@
 TEST_F(ThreadTest, StartTwice) {
   Thread a("StartTwice");
 
-  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.task_runner());
   EXPECT_FALSE(a.IsRunning());
 
   EXPECT_TRUE(a.Start());
-  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.task_runner());
   EXPECT_TRUE(a.IsRunning());
 
   a.Stop();
-  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.task_runner());
   EXPECT_FALSE(a.IsRunning());
 
   EXPECT_TRUE(a.Start());
-  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.task_runner());
   EXPECT_TRUE(a.IsRunning());
 
   a.Stop();
-  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.task_runner());
   EXPECT_FALSE(a.IsRunning());
 }
 
@@ -354,8 +372,8 @@
 
   Thread::Options options;
   options.joinable = false;
-  EXPECT_TRUE(a->StartWithOptions(options));
-  EXPECT_TRUE(a->message_loop());
+  EXPECT_TRUE(a->StartWithOptions(std::move(options)));
+  EXPECT_TRUE(a->task_runner());
   EXPECT_TRUE(a->IsRunning());
 
   // Signaled when last task on |a| is processed.
@@ -372,7 +390,7 @@
   a->StopSoon();
   base::PlatformThread::YieldCurrentThread();
   last_task_event.Wait();
-  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
+  base::PlatformThread::Sleep(base::Milliseconds(20));
 
   // This test assumes that the above was sufficient to let the thread fully
   // stop.
@@ -445,7 +463,7 @@
 //
 //  (1) Thread::CleanUp()
 //  (2) MessageLoop::~MessageLoop()
-//      MessageLoopCurrent::DestructionObservers called.
+//      CurrentThread::DestructionObservers called.
 TEST_F(ThreadTest, CleanUp) {
   EventList captured_events;
   CapturingDestructionObserver loop_destruction_observer(&captured_events);
@@ -454,7 +472,7 @@
     // Start a thread which writes its event into |captured_events|.
     CaptureToEventList t(&captured_events);
     EXPECT_TRUE(t.Start());
-    EXPECT_TRUE(t.message_loop());
+    EXPECT_TRUE(t.task_runner());
     EXPECT_TRUE(t.IsRunning());
 
     // Register an observer that writes into |captured_events| once the
@@ -498,8 +516,7 @@
   // Flushing a thread with no tasks shouldn't block.
   a.FlushForTesting();
 
-  constexpr base::TimeDelta kSleepPerTestTask =
-      base::TimeDelta::FromMilliseconds(50);
+  constexpr base::TimeDelta kSleepPerTestTask = base::Milliseconds(50);
   constexpr size_t kNumSleepTasks = 5;
 
   const base::TimeTicks ticks_before_post = base::TimeTicks::Now();
@@ -523,55 +540,56 @@
 
 namespace {
 
-// A Thread which uses a MessageLoop on the stack. It won't start a real
-// underlying thread (instead its messages can be processed by a RunLoop on the
-// stack).
-class ExternalMessageLoopThread : public Thread {
+using TaskQueue = base::sequence_manager::TaskQueue;
+
+class SequenceManagerThreadDelegate : public Thread::Delegate {
  public:
-  ExternalMessageLoopThread() : Thread("ExternalMessageLoopThread") {}
+  SequenceManagerThreadDelegate()
+      : sequence_manager_(
+            base::sequence_manager::CreateUnboundSequenceManager()),
+        task_queue_(sequence_manager_->CreateTaskQueue(
+            TaskQueue::Spec(base::sequence_manager::QueueName::DEFAULT_TQ))) {
+    sequence_manager_->SetDefaultTaskRunner(GetDefaultTaskRunner());
+  }
 
-  ~ExternalMessageLoopThread() override { Stop(); }
+  SequenceManagerThreadDelegate(const SequenceManagerThreadDelegate&) = delete;
+  SequenceManagerThreadDelegate& operator=(
+      const SequenceManagerThreadDelegate&) = delete;
 
-  void InstallMessageLoop() { SetMessageLoop(&external_message_loop_); }
+  ~SequenceManagerThreadDelegate() override {}
 
-  void VerifyUsingExternalMessageLoop(
-      bool expected_using_external_message_loop) {
-    EXPECT_EQ(expected_using_external_message_loop,
-              using_external_message_loop());
+  // Thread::Delegate:
+
+  scoped_refptr<base::SingleThreadTaskRunner> GetDefaultTaskRunner() override {
+    return task_queue_->task_runner();
+  }
+
+  void BindToCurrentThread(base::TimerSlack timer_slack) override {
+    sequence_manager_->BindToMessagePump(
+        base::MessagePump::Create(base::MessagePumpType::DEFAULT));
+    sequence_manager_->SetTimerSlack(timer_slack);
   }
 
  private:
-  base::MessageLoop external_message_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(ExternalMessageLoopThread);
+  std::unique_ptr<base::sequence_manager::SequenceManager> sequence_manager_;
+  scoped_refptr<TaskQueue> task_queue_;
 };
 
 }  // namespace
 
-TEST_F(ThreadTest, ExternalMessageLoop) {
-  ExternalMessageLoopThread a;
-  EXPECT_FALSE(a.message_loop());
-  EXPECT_FALSE(a.IsRunning());
-  a.VerifyUsingExternalMessageLoop(false);
+TEST_F(ThreadTest, ProvidedThreadDelegate) {
+  Thread thread("ThreadDelegate");
+  base::Thread::Options options;
+  options.delegate = std::make_unique<SequenceManagerThreadDelegate>();
 
-  a.InstallMessageLoop();
-  EXPECT_TRUE(a.message_loop());
-  EXPECT_TRUE(a.IsRunning());
-  a.VerifyUsingExternalMessageLoop(true);
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+      options.delegate->GetDefaultTaskRunner();
+  thread.StartWithOptions(std::move(options));
 
-  bool ran = false;
-  a.task_runner()->PostTask(
-      FROM_HERE, base::BindOnce([](bool* toggled) { *toggled = true; }, &ran));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(ran);
+  base::WaitableEvent event;
+  task_runner->PostTask(FROM_HERE, base::BindOnce(&base::WaitableEvent::Signal,
+                                                  base::Unretained(&event)));
+  event.Wait();
 
-  a.Stop();
-  EXPECT_FALSE(a.message_loop());
-  EXPECT_FALSE(a.IsRunning());
-  a.VerifyUsingExternalMessageLoop(true);
-
-  // Confirm that running any remaining tasks posted from Stop() goes smoothly
-  // (e.g. https://codereview.chromium.org/2135413003/#ps300001 crashed if
-  // StopSoon() posted Thread::ThreadQuitHelper() while |run_loop_| was null).
-  base::RunLoop().RunUntilIdle();
+  thread.Stop();
 }
diff --git a/base/threading/threading_features.h b/base/threading/threading_features.h
new file mode 100644
index 0000000..856c9ef
--- /dev/null
+++ b/base/threading/threading_features.h
@@ -0,0 +1,37 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREADING_FEATURES_H_
+#define BASE_THREADING_THREADING_FEATURES_H_
+
+#include "base/base_export.h"
+#include "base/feature_list.h"
+#include "build/build_config.h"
+
+#if BUILDFLAG(IS_APPLE)
+#include "base/metrics/field_trial_params.h"
+#endif
+
+namespace base {
+
+#if BUILDFLAG(IS_APPLE)
+BASE_EXPORT BASE_DECLARE_FEATURE(kOptimizedRealtimeThreadingMac);
+extern const BASE_EXPORT FeatureParam<bool>
+    kOptimizedRealtimeThreadingMacPreemptible;
+extern const BASE_EXPORT FeatureParam<double>
+    kOptimizedRealtimeThreadingMacBusy;
+extern const BASE_EXPORT FeatureParam<double>
+    kOptimizedRealtimeThreadingMacBusyLimit;
+extern const BASE_EXPORT Feature kUseThreadQoSMac;
+#endif
+
+#if BUILDFLAG(IS_WIN)
+BASE_EXPORT BASE_DECLARE_FEATURE(kAboveNormalCompositingBrowserWin);
+#endif
+
+BASE_EXPORT BASE_DECLARE_FEATURE(kEnableHangWatcher);
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREADING_FEATURES_H_
diff --git a/base/threading/watchdog.cc b/base/threading/watchdog.cc
index 0e48c8e..8854f2b 100644
--- a/base/threading/watchdog.cc
+++ b/base/threading/watchdog.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -41,19 +41,20 @@
 // Start thread running in a Disarmed state.
 Watchdog::Watchdog(const TimeDelta& duration,
                    const std::string& thread_watched_name,
-                   bool enabled)
-  : enabled_(enabled),
-    lock_(),
-    condition_variable_(&lock_),
-    state_(DISARMED),
-    duration_(duration),
-    thread_watched_name_(thread_watched_name),
-    delegate_(this) {
-  if (!enabled_)
+                   bool enabled,
+                   Delegate* delegate)
+    : enabled_(enabled),
+      condition_variable_(&lock_),
+      state_(DISARMED),
+      duration_(duration),
+      thread_watched_name_(thread_watched_name),
+      thread_delegate_(this),
+      delegate_(delegate) {
+  if (!enabled_) {
     return;  // Don't start thread, or doing anything really.
+  }
   enabled_ = PlatformThread::Create(0,  // Default stack size.
-                                    &delegate_,
-                                    &handle_);
+                                    &thread_delegate_, &handle_);
   DCHECK(enabled_);
 }
 
@@ -108,6 +109,14 @@
 }
 
 void Watchdog::Alarm() {
+  if (delegate_) {
+    delegate_->Alarm();
+  } else {
+    DefaultAlarm();
+  }
+}
+
+void Watchdog::DefaultAlarm() {
   DVLOG(1) << "Watchdog alarmed for " << thread_watched_name_;
 }
 
@@ -118,7 +127,7 @@
   SetThreadName();
   TimeDelta remaining_duration;
   StaticData* static_data = GetStaticData();
-  while (1) {
+  while (true) {
     AutoLock lock(watchdog_->lock_);
     while (DISARMED == watchdog_->state_)
       watchdog_->condition_variable_.Wait();
@@ -155,7 +164,7 @@
       watchdog_->Alarm();  // Set a break point here to debug on alarms.
     }
     TimeDelta last_alarm_delay = TimeTicks::Now() - last_alarm_time;
-    if (last_alarm_delay <= TimeDelta::FromMilliseconds(2))
+    if (last_alarm_delay <= Milliseconds(2))
       continue;
     // Ignore race of two alarms/breaks going off at roughly the same time.
     AutoLock static_lock(static_data->lock);
diff --git a/base/threading/watchdog.h b/base/threading/watchdog.h
index f806984..f09e9a2 100644
--- a/base/threading/watchdog.h
+++ b/base/threading/watchdog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -22,7 +22,7 @@
 
 #include "base/base_export.h"
 #include "base/compiler_specific.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/platform_thread.h"
@@ -32,11 +32,26 @@
 
 class BASE_EXPORT Watchdog {
  public:
-  // Constructor specifies how long the Watchdog will wait before alarming.
+  class Delegate {
+   public:
+    virtual ~Delegate() = default;
+
+    // Called on the watchdog thread.
+    virtual void Alarm() = 0;
+  };
+
+  // Constructor specifies how long the Watchdog will wait before alarming. If
+  // `delegate` is non-null, `Alarm` on the delegate will be called instead of
+  // the default behavior.
   Watchdog(const TimeDelta& duration,
            const std::string& thread_watched_name,
-           bool enabled);
-  virtual ~Watchdog();
+           bool enabled,
+           Delegate* delegate = nullptr);
+
+  Watchdog(const Watchdog&) = delete;
+  Watchdog& operator=(const Watchdog&) = delete;
+
+  ~Watchdog();
 
   // Notify watchdog thread to finish up. Sets the state_ to SHUTDOWN.
   void Cleanup();
@@ -54,13 +69,16 @@
   void Disarm();
 
   // Alarm is called if the time expires after an Arm() without someone calling
-  // Disarm().  This method can be overridden to create testable classes.
-  virtual void Alarm();
+  // Disarm().
+  void Alarm();
 
   // Reset static data to initial state. Useful for tests, to ensure
   // they are independent.
   static void ResetStaticData();
 
+  // The default behavior of Alarm() if a delegate is not provided.
+  void DefaultAlarm();
+
  private:
   class ThreadDelegate : public PlatformThread::Delegate {
    public:
@@ -71,24 +89,23 @@
    private:
     void SetThreadName() const;
 
-    Watchdog* watchdog_;
+    raw_ptr<Watchdog> watchdog_;
   };
 
-  enum State {ARMED, DISARMED, SHUTDOWN, JOINABLE };
+  enum State { ARMED, DISARMED, SHUTDOWN, JOINABLE };
 
   bool enabled_;
 
-  Lock lock_;  // Mutex for state_.
+  Lock lock_;
   ConditionVariable condition_variable_;
-  State state_;
+  State state_ GUARDED_BY(lock_);
   const TimeDelta duration_;  // How long after start_time_ do we alarm?
   const std::string thread_watched_name_;
   PlatformThreadHandle handle_;
-  ThreadDelegate delegate_;  // Store it, because it must outlive the thread.
+  ThreadDelegate thread_delegate_;  // Must outlive the thread.
 
+  raw_ptr<Delegate> delegate_;
   TimeTicks start_time_;  // Start of epoch, and alarm after duration_.
-
-  DISALLOW_COPY_AND_ASSIGN(Watchdog);
 };
 
 }  // namespace base
diff --git a/base/threading/watchdog_unittest.cc b/base/threading/watchdog_unittest.cc
index f534a86..e249a8c 100644
--- a/base/threading/watchdog_unittest.cc
+++ b/base/threading/watchdog_unittest.cc
@@ -1,12 +1,13 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/threading/watchdog.h"
 
+#include <atomic>
+
 #include "base/logging.h"
-#include "base/macros.h"
-#include "base/synchronization/spin_wait.h"
+#include "base/test/spin_wait.h"
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -18,28 +19,29 @@
 //------------------------------------------------------------------------------
 // Provide a derived class to facilitate testing.
 
-class WatchdogCounter : public Watchdog {
+class WatchdogCounter : public Watchdog::Delegate {
  public:
   WatchdogCounter(const TimeDelta& duration,
                   const std::string& thread_watched_name,
                   bool enabled)
-      : Watchdog(duration, thread_watched_name, enabled),
-        alarm_counter_(0) {
-  }
+      : watchdog_(duration, thread_watched_name, enabled, this) {}
+
+  WatchdogCounter(const WatchdogCounter&) = delete;
+  WatchdogCounter& operator=(const WatchdogCounter&) = delete;
 
   ~WatchdogCounter() override = default;
 
   void Alarm() override {
     alarm_counter_++;
-    Watchdog::Alarm();
+    watchdog_.DefaultAlarm();
   }
 
-  int alarm_counter() { return alarm_counter_; }
+  Watchdog& watchdog() { return watchdog_; }
+  int alarm_counter() { return alarm_counter_.load(); }
 
  private:
-  int alarm_counter_;
-
-  DISALLOW_COPY_AND_ASSIGN(WatchdogCounter);
+  std::atomic<int> alarm_counter_{0};
+  Watchdog watchdog_;
 };
 
 class WatchdogTest : public testing::Test {
@@ -54,19 +56,19 @@
 
 // Minimal constructor/destructor test.
 TEST_F(WatchdogTest, StartupShutdownTest) {
-  Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false);
-  Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true);
+  Watchdog watchdog1(Milliseconds(300), "Disabled", false);
+  Watchdog watchdog2(Milliseconds(300), "Enabled", true);
 }
 
 // Test ability to call Arm and Disarm repeatedly.
 TEST_F(WatchdogTest, ArmDisarmTest) {
-  Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false);
+  Watchdog watchdog1(Milliseconds(300), "Disabled", false);
   watchdog1.Arm();
   watchdog1.Disarm();
   watchdog1.Arm();
   watchdog1.Disarm();
 
-  Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true);
+  Watchdog watchdog2(Milliseconds(300), "Enabled", true);
   watchdog2.Arm();
   watchdog2.Disarm();
   watchdog2.Arm();
@@ -75,10 +77,9 @@
 
 // Make sure a basic alarm fires when the time has expired.
 TEST_F(WatchdogTest, AlarmTest) {
-  WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Enabled", true);
-  watchdog.Arm();
-  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
-                                   watchdog.alarm_counter() > 0);
+  WatchdogCounter watchdog(Milliseconds(10), "Enabled", true);
+  watchdog.watchdog().Arm();
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(Minutes(5), watchdog.alarm_counter() > 0);
   EXPECT_EQ(1, watchdog.alarm_counter());
 }
 
@@ -86,35 +87,34 @@
 TEST_F(WatchdogTest, AlarmPriorTimeTest) {
   WatchdogCounter watchdog(TimeDelta(), "Enabled2", true);
   // Set a time in the past.
-  watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(2));
+  watchdog.watchdog().ArmSomeTimeDeltaAgo(Seconds(2));
   // It should instantly go off, but certainly in less than 5 minutes.
-  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
-                                   watchdog.alarm_counter() > 0);
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(Minutes(5), watchdog.alarm_counter() > 0);
 
   EXPECT_EQ(1, watchdog.alarm_counter());
 }
 
 // Make sure a disable alarm does nothing, even if we arm it.
 TEST_F(WatchdogTest, ConstructorDisabledTest) {
-  WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Disabled", false);
-  watchdog.Arm();
+  WatchdogCounter watchdog(Milliseconds(10), "Disabled", false);
+  watchdog.watchdog().Arm();
   // Alarm should not fire, as it was disabled.
-  PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
+  PlatformThread::Sleep(Milliseconds(500));
   EXPECT_EQ(0, watchdog.alarm_counter());
 }
 
 // Make sure Disarming will prevent firing, even after Arming.
 TEST_F(WatchdogTest, DisarmTest) {
-  WatchdogCounter watchdog(TimeDelta::FromSeconds(1), "Enabled3", true);
+  WatchdogCounter watchdog(Seconds(1), "Enabled3", true);
 
   TimeTicks start = TimeTicks::Now();
-  watchdog.Arm();
+  watchdog.watchdog().Arm();
   // Sleep a bit, but not past the alarm point.
-  PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
-  watchdog.Disarm();
+  PlatformThread::Sleep(Milliseconds(100));
+  watchdog.watchdog().Disarm();
   TimeTicks end = TimeTicks::Now();
 
-  if (end - start > TimeDelta::FromMilliseconds(500)) {
+  if (end - start > Milliseconds(500)) {
     LOG(WARNING) << "100ms sleep took over 500ms, making the results of this "
                  << "timing-sensitive test suspicious.  Aborting now.";
     return;
@@ -125,15 +125,14 @@
 
   // Sleep past the point where it would have fired if it wasn't disarmed,
   // and verify that it didn't fire.
-  PlatformThread::Sleep(TimeDelta::FromSeconds(1));
+  PlatformThread::Sleep(Seconds(1));
   EXPECT_EQ(0, watchdog.alarm_counter());
 
   // ...but even after disarming, we can still use the alarm...
   // Set a time greater than the timeout into the past.
-  watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(10));
+  watchdog.watchdog().ArmSomeTimeDeltaAgo(Seconds(10));
   // It should almost instantly go off, but certainly in less than 5 minutes.
-  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
-                                   watchdog.alarm_counter() > 0);
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(Minutes(5), watchdog.alarm_counter() > 0);
 
   EXPECT_EQ(1, watchdog.alarm_counter());
 }