diff --git a/DEPS b/DEPS
index 2f085716..121e276 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '02ab8cc2909d99377e4200cd426a02c0b482a040',
+  'skia_revision': 'e12c69e78db3b6451c42e36524ae9e87f75f24fc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '74c7e92b75798ba9d5d0b881ba4c8dcc6960f2ee',
+  'v8_revision': '25af2038a5d7f4b3cb345e996ad5cb1d6ce3ce35',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'd9a69250dacb324c594020c53e62097a6bb37569',
+  'catapult_revision': 'ada8f7cc7d7aa2d0a7d18016c6510c1d5892bd17',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/WATCHLISTS b/WATCHLISTS
index 0c95f03..f588378 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1322,10 +1322,6 @@
       'filepath': 'third_party/WebKit/Source/core/dom/custom/' \
                   '|third_party/WebKit/Source/bindings/v8/.*CustomElement',
     },
-    'blink_device_light': {
-      'filepath': 'third_party/WebKit/Source/modules/device_light/' \
-                  '|third_party/WebKit/LayoutTests/fast/dom/DeviceLight/'
-    },
     'blink_device_orientation': {
       'filepath': 'third_party/WebKit/Source/modules/device_orientation/' \
                   '|third_party/WebKit/LayoutTests/device_orientation/' \
@@ -1723,8 +1719,6 @@
     'blink_css_regions': ['ChromiumBugTracker@adobe.com'],
     'blink_custom_elements': ['dglazkov+blink@chromium.org',
                               'dominicc+watchlist@chromium.org'],
-    'blink_device_light': ['mlamouri+watch-blink@chromium.org',
-                           'timvolodine@chromium.org'],
     'blink_device_orientation': ['mlamouri+watch-blink@chromium.org',
                                  'timvolodine@chromium.org'],
     'blink_devtools': ['apavlov+blink@chromium.org',
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 8bb05143..c88e76c 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -75,8 +75,6 @@
 MessageLoop::DestructionObserver::~DestructionObserver() {
 }
 
-MessageLoop::NestingObserver::~NestingObserver() {}
-
 //------------------------------------------------------------------------------
 
 MessageLoop::MessageLoop(Type type)
@@ -138,6 +136,8 @@
   // OK, now make it so that no one can find us.
   if (current() == this)
     GetTLSMessageLoop()->Set(nullptr);
+
+  RunLoop::ResetTLSState();
 }
 
 // static
@@ -214,18 +214,6 @@
   destruction_observers_.RemoveObserver(destruction_observer);
 }
 
-void MessageLoop::AddNestingObserver(NestingObserver* observer) {
-  DCHECK_EQ(this, current());
-  CHECK(allow_nesting_);
-  nesting_observers_.AddObserver(observer);
-}
-
-void MessageLoop::RemoveNestingObserver(NestingObserver* observer) {
-  DCHECK_EQ(this, current());
-  CHECK(allow_nesting_);
-  nesting_observers_.RemoveObserver(observer);
-}
-
 void MessageLoop::QuitWhenIdle() {
   DCHECK_EQ(this, current());
   if (run_loop_) {
@@ -259,7 +247,7 @@
 
 void MessageLoop::SetNestableTasksAllowed(bool allowed) {
   if (allowed) {
-    CHECK(allow_nesting_);
+    CHECK(base::RunLoop::IsNestingAllowedOnCurrentThread());
 
     // Kick the native pump just in case we enter a OS-driven nested message
     // loop.
@@ -272,10 +260,9 @@
   return nestable_tasks_allowed_;
 }
 
-bool MessageLoop::IsNested() {
-  return run_loop_->run_depth_ > 1;
-}
-
+// TODO(gab): Migrate TaskObservers to RunLoop as part of separating concerns
+// between MessageLoop and RunLoop and making MessageLoop a swappable
+// implementation detail. http://crbug.com/703346
 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) {
   DCHECK_EQ(this, current());
   CHECK(allow_task_observers_);
@@ -288,11 +275,6 @@
   task_observers_.RemoveObserver(task_observer);
 }
 
-bool MessageLoop::is_running() const {
-  DCHECK_EQ(this, current());
-  return run_loop_ != NULL;
-}
-
 bool MessageLoop::HasHighResolutionTasks() {
   return incoming_task_queue_->HasHighResolutionTasks();
 }
@@ -383,12 +365,11 @@
 void MessageLoop::RunHandler() {
   DCHECK_EQ(this, current());
   DCHECK(run_loop_);
-  CHECK(allow_nesting_ || run_loop_->run_depth_ == 1);
   pump_->Run(this);
 }
 
 bool MessageLoop::ProcessNextDelayedNonNestableTask() {
-  if (run_loop_->run_depth_ != 1)
+  if (is_nested_)
     return false;
 
   if (deferred_non_nestable_work_queue_.empty())
@@ -430,7 +411,7 @@
 }
 
 bool MessageLoop::DeferOrRunPendingTask(PendingTask pending_task) {
-  if (pending_task.nestable || run_loop_->run_depth_ == 1) {
+  if (pending_task.nestable || !is_nested_) {
     RunTask(&pending_task);
     // Show that we ran a task (Note: a new one might arrive as a
     // consequence!).
@@ -496,11 +477,6 @@
   pump_->ScheduleWork();
 }
 
-void MessageLoop::NotifyBeginNestedLoop() {
-  for (auto& observer : nesting_observers_)
-    observer.OnBeginNestedMessageLoop();
-}
-
 bool MessageLoop::DoWork() {
   if (!nestable_tasks_allowed_) {
     // Task can't be executed right now.
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index a433ae56..c180c2d 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -162,19 +162,6 @@
   // DestructionObserver is receiving a notification callback.
   void RemoveDestructionObserver(DestructionObserver* destruction_observer);
 
-  // A NestingObserver is notified when a nested message loop begins. The
-  // observers are notified before the first task is processed.
-  class BASE_EXPORT NestingObserver {
-   public:
-    virtual void OnBeginNestedMessageLoop() = 0;
-
-   protected:
-    virtual ~NestingObserver();
-  };
-
-  void AddNestingObserver(NestingObserver* observer);
-  void RemoveNestingObserver(NestingObserver* observer);
-
   // Deprecated: use RunLoop instead.
   //
   // Signals the Run method to return when it becomes idle. It will continue to
@@ -277,9 +264,6 @@
     bool old_state_;
   };
 
-  // Returns true if we are currently running a nested message loop.
-  bool IsNested();
-
   // A TaskObserver is an object that receives task notifications from the
   // MessageLoop.
   //
@@ -303,9 +287,6 @@
   void AddTaskObserver(TaskObserver* task_observer);
   void RemoveTaskObserver(TaskObserver* task_observer);
 
-  // Can only be called from the thread that owns the MessageLoop.
-  bool is_running() const;
-
   // Returns true if the message loop has high resolution timers enabled.
   // Provided for testing.
   bool HasHighResolutionTasks();
@@ -320,12 +301,6 @@
   // Runs the specified PendingTask.
   void RunTask(PendingTask* pending_task);
 
-  bool nesting_allowed() const { return allow_nesting_; }
-
-  // Disallow nesting. After this is called, running a nested RunLoop or calling
-  // Add/RemoveNestingObserver() on this MessageLoop will crash.
-  void DisallowNesting() { allow_nesting_ = false; }
-
   // Disallow task observers. After this is called, calling
   // Add/RemoveTaskObserver() on this MessageLoop will crash.
   void DisallowTaskObservers() { allow_task_observers_ = false; }
@@ -402,9 +377,6 @@
   // responsible for synchronizing ScheduleWork() calls.
   void ScheduleWork();
 
-  // Notify observers that a nested message loop is starting.
-  void NotifyBeginNestedLoop();
-
   // MessagePump::Delegate methods:
   bool DoWork() override;
   bool DoDelayedWork(TimeTicks* next_delayed_work_time) override;
@@ -439,8 +411,6 @@
 
   ObserverList<DestructionObserver> destruction_observers_;
 
-  ObserverList<NestingObserver> nesting_observers_;
-
   // A recursion block that prevents accidentally running additional tasks when
   // insider a (accidentally induced?) nested message pump.
   bool nestable_tasks_allowed_;
@@ -475,8 +445,8 @@
   // MessageLoop is bound to its thread and constant forever after.
   PlatformThreadId thread_id_;
 
-  // Whether nesting is allowed.
-  bool allow_nesting_ = true;
+  // Whether this MessageLoop is currently running in nested RunLoops.
+  bool is_nested_ = false;
 
   // Whether task observers are allowed.
   bool allow_task_observers_ = true;
diff --git a/base/message_loop/message_loop_test.cc b/base/message_loop/message_loop_test.cc
index ad9f127..de607002 100644
--- a/base/message_loop/message_loop_test.cc
+++ b/base/message_loop/message_loop_test.cc
@@ -375,67 +375,6 @@
   EXPECT_EQ(depth, 0);
 }
 
-// A NestingObserver that tracks the number of nested message loop starts it
-// has seen.
-class TestNestingObserver : public MessageLoop::NestingObserver {
- public:
-  TestNestingObserver() {}
-  ~TestNestingObserver() override {}
-
-  int begin_nested_loop_count() const { return begin_nested_loop_count_; }
-
-  // MessageLoop::NestingObserver:
-  void OnBeginNestedMessageLoop() override { begin_nested_loop_count_++; }
-
- private:
-  int begin_nested_loop_count_ = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(TestNestingObserver);
-};
-
-void ExpectOneBeginNestedLoop(TestNestingObserver* observer) {
-  EXPECT_EQ(1, observer->begin_nested_loop_count());
-}
-
-// Starts a nested message loop.
-void RunNestedLoop(TestNestingObserver* observer,
-                   const Closure& quit_outer_loop) {
-  // The nested loop hasn't started yet.
-  EXPECT_EQ(0, observer->begin_nested_loop_count());
-
-  MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
-  RunLoop nested_loop;
-  // Verify that by the time the first task is run the observer has seen the
-  // message loop begin.
-  ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, BindOnce(&ExpectOneBeginNestedLoop, observer));
-  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, nested_loop.QuitClosure());
-  nested_loop.Run();
-
-  // Quitting message loops doesn't change the begin count.
-  EXPECT_EQ(1, observer->begin_nested_loop_count());
-
-  quit_outer_loop.Run();
-}
-
-// Tests that a NestingObserver is notified when a nested message loop begins.
-void RunTest_NestingObserver(MessagePumpFactory factory) {
-  std::unique_ptr<MessagePump> pump(factory());
-  MessageLoop outer_loop(std::move(pump));
-
-  // Observe the outer loop for nested message loops beginning.
-  TestNestingObserver nesting_observer;
-  outer_loop.AddNestingObserver(&nesting_observer);
-
-  // Post a task that runs a nested message loop.
-  outer_loop.task_runner()->PostTask(
-      FROM_HERE, BindOnce(&RunNestedLoop, &nesting_observer,
-                          outer_loop.QuitWhenIdleClosure()));
-  RunLoop().Run();
-
-  outer_loop.RemoveNestingObserver(&nesting_observer);
-}
-
 enum TaskType {
   MESSAGEBOX,
   ENDDIALOG,
diff --git a/base/message_loop/message_loop_test.h b/base/message_loop/message_loop_test.h
index b7ae28e..dbdbfbf 100644
--- a/base/message_loop/message_loop_test.h
+++ b/base/message_loop/message_loop_test.h
@@ -28,7 +28,6 @@
 void RunTest_EnsureDeletion(MessagePumpFactory factory);
 void RunTest_EnsureDeletion_Chain(MessagePumpFactory factory);
 void RunTest_Nesting(MessagePumpFactory factory);
-void RunTest_NestingObserver(MessagePumpFactory factory);
 void RunTest_RecursiveDenial1(MessagePumpFactory factory);
 void RunTest_RecursiveDenial3(MessagePumpFactory factory);
 void RunTest_RecursiveSupport1(MessagePumpFactory factory);
diff --git a/base/profiler/stack_sampling_profiler_unittest.cc b/base/profiler/stack_sampling_profiler_unittest.cc
index 88414b1..7cae1045 100644
--- a/base/profiler/stack_sampling_profiler_unittest.cc
+++ b/base/profiler/stack_sampling_profiler_unittest.cc
@@ -650,7 +650,9 @@
 
 // Checks that the basic expected information is present in a sampled call stack
 // profile.
-#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+// macOS ASAN is not yet supported - crbug.com/718628.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED) && \
+    !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX))
 #define MAYBE_Basic Basic
 #else
 #define MAYBE_Basic DISABLED_Basic
@@ -728,7 +730,9 @@
 
 // Checks that the profiler handles stacks containing dynamically-allocated
 // stack memory.
-#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+// macOS ASAN is not yet supported - crbug.com/718628.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED) && \
+    !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX))
 #define MAYBE_Alloca Alloca
 #else
 #define MAYBE_Alloca DISABLED_Alloca
@@ -1359,7 +1363,9 @@
 
 // Checks that a stack that runs through another library produces a stack with
 // the expected functions.
-#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+// macOS ASAN is not yet supported - crbug.com/718628.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED) && \
+    !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX))
 #define MAYBE_OtherLibrary OtherLibrary
 #else
 #define MAYBE_OtherLibrary DISABLED_OtherLibrary
@@ -1442,7 +1448,9 @@
 
 // Checks that a stack that runs through a library that has been unloaded
 // produces a stack, and doesn't crash.
-#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+// macOS ASAN is not yet supported - crbug.com/718628.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED) && \
+    !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX))
 #define MAYBE_UnloadedLibrary UnloadedLibrary
 #else
 #define MAYBE_UnloadedLibrary DISABLED_UnloadedLibrary
diff --git a/base/run_loop.cc b/base/run_loop.cc
index 4c19d358..b7df5b23 100644
--- a/base/run_loop.cc
+++ b/base/run_loop.cc
@@ -4,29 +4,97 @@
 
 #include "base/run_loop.h"
 
+#include <stack>
+
 #include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/observer_list.h"
+#include "base/threading/thread_local_storage.h"
 #include "base/tracked_objects.h"
 #include "build/build_config.h"
 
 namespace base {
 
+namespace {
+
+class ThreadLocalRunLoopState {
+ public:
+  // A vector-based stack is more memory efficient than the default deque-based
+  // stack as the active RunLoop stack isn't expected to ever have more than a
+  // few entries.
+  using RunLoopStack = std::stack<RunLoop*, std::vector<RunLoop*>>;
+
+  ThreadLocalRunLoopState()
+      : slot_(&ThreadLocalRunLoopState::OnTLSDestruction) {}
+
+  ~ThreadLocalRunLoopState() = delete;
+
+  RunLoopStack& GetActiveRunLoops() {
+    return GetOrCreateInternalState()->active_run_loops;
+  }
+
+  ObserverList<RunLoop::NestingObserver>& GetNestingObservers() {
+    InternalState* state = GetOrCreateInternalState();
+    CHECK(state->allow_nesting);
+    return state->nesting_observers;
+  }
+
+  bool IsNestingAllowed() { return GetOrCreateInternalState()->allow_nesting; }
+
+  void DisallowNesting() { GetOrCreateInternalState()->allow_nesting = false; }
+
+  void Reset() {
+    InternalState* state = static_cast<InternalState*>(slot_.Get());
+    if (state) {
+      slot_.Set(nullptr);
+      delete state;
+    }
+  }
+
+ private:
+  struct InternalState {
+    bool allow_nesting = true;
+    RunLoopStack active_run_loops;
+    ObserverList<RunLoop::NestingObserver> nesting_observers;
+  };
+
+  static void OnTLSDestruction(void* internal_state) {
+    delete static_cast<InternalState*>(internal_state);
+  }
+
+  InternalState* GetOrCreateInternalState() {
+    InternalState* state = static_cast<InternalState*>(slot_.Get());
+    if (!state) {
+      state = new InternalState;
+      slot_.Set(static_cast<void*>(state));
+    }
+    return state;
+  }
+
+  ThreadLocalStorage::Slot slot_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalRunLoopState);
+};
+
+LazyInstance<ThreadLocalRunLoopState>::Leaky tls_run_loop_state =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
 RunLoop::RunLoop()
     : loop_(MessageLoop::current()),
-      previous_run_loop_(NULL),
-      run_depth_(0),
-      run_called_(false),
-      quit_called_(false),
-      running_(false),
-      quit_when_idle_received_(false),
       weak_factory_(this) {
   DCHECK(loop_);
 }
 
 RunLoop::~RunLoop() {
+  // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
+  // DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 void RunLoop::Run() {
   DCHECK(thread_checker_.CalledOnValidThread());
+
   if (!BeforeRun())
     return;
 
@@ -41,12 +109,15 @@
 }
 
 void RunLoop::RunUntilIdle() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
   quit_when_idle_received_ = true;
   Run();
 }
 
 void RunLoop::Quit() {
   DCHECK(thread_checker_.CalledOnValidThread());
+
   quit_called_ = true;
   if (running_ && loop_->run_loop_ == this) {
     // This is the inner-most RunLoop, so quit now.
@@ -60,14 +131,55 @@
 }
 
 base::Closure RunLoop::QuitClosure() {
+  // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
+  // DCHECK(thread_checker_.CalledOnValidThread());
   return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr());
 }
 
 base::Closure RunLoop::QuitWhenIdleClosure() {
+  // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
+  // DCHECK(thread_checker_.CalledOnValidThread());
   return base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr());
 }
 
+// static
+void RunLoop::ResetTLSState() {
+  tls_run_loop_state.Get().Reset();
+}
+
+// static
+bool RunLoop::IsRunningOnCurrentThread() {
+  return !tls_run_loop_state.Get().GetActiveRunLoops().empty();
+}
+
+// static
+bool RunLoop::IsNestedOnCurrentThread() {
+  return tls_run_loop_state.Get().GetActiveRunLoops().size() > 1;
+}
+
+// static
+void RunLoop::AddNestingObserverOnCurrentThread(NestingObserver* observer) {
+  tls_run_loop_state.Get().GetNestingObservers().AddObserver(observer);
+}
+
+// static
+void RunLoop::RemoveNestingObserverOnCurrentThread(NestingObserver* observer) {
+  tls_run_loop_state.Get().GetNestingObservers().RemoveObserver(observer);
+}
+
+// static
+bool RunLoop::IsNestingAllowedOnCurrentThread() {
+  return tls_run_loop_state.Get().IsNestingAllowed();
+}
+
+// static
+void RunLoop::DisallowNestingOnCurrentThread() {
+  tls_run_loop_state.Get().DisallowNesting();
+}
+
 bool RunLoop::BeforeRun() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
   DCHECK(!run_called_);
   run_called_ = true;
 
@@ -75,26 +187,42 @@
   if (quit_called_)
     return false;
 
-  // Push RunLoop stack:
-  previous_run_loop_ = loop_->run_loop_;
-  run_depth_ = previous_run_loop_? previous_run_loop_->run_depth_ + 1 : 1;
-  loop_->run_loop_ = this;
+  auto& active_run_loops = tls_run_loop_state.Get().GetActiveRunLoops();
+  active_run_loops.push(this);
 
-  if (run_depth_ > 1)
-    loop_->NotifyBeginNestedLoop();
+  const bool is_nested = active_run_loops.size() > 1;
+
+  // TODO(gab): Break the inter-dependency between MessageLoop and RunLoop
+  // further. http://crbug.com/703346
+  loop_->run_loop_ = this;
+  loop_->is_nested_ = is_nested;
+
+  if (is_nested) {
+    CHECK(tls_run_loop_state.Get().IsNestingAllowed());
+    for (auto& observer : tls_run_loop_state.Get().GetNestingObservers())
+      observer.OnBeginNestedRunLoop();
+  }
 
   running_ = true;
   return true;
 }
 
 void RunLoop::AfterRun() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
   running_ = false;
 
-  // Pop RunLoop stack:
-  loop_->run_loop_ = previous_run_loop_;
+  auto& active_run_loops = tls_run_loop_state.Get().GetActiveRunLoops();
+  DCHECK_EQ(active_run_loops.top(), this);
+  active_run_loops.pop();
+
+  RunLoop* previous_run_loop =
+      active_run_loops.empty() ? nullptr : active_run_loops.top();
+  loop_->run_loop_ = previous_run_loop;
+  loop_->is_nested_ = active_run_loops.size() > 1;
 
   // Execute deferred QuitNow, if any:
-  if (previous_run_loop_ && previous_run_loop_->quit_called_)
+  if (previous_run_loop && previous_run_loop->quit_called_)
     loop_->QuitNow();
 }
 
diff --git a/base/run_loop.h b/base/run_loop.h
index 077d097b..cd4a211 100644
--- a/base/run_loop.h
+++ b/base/run_loop.h
@@ -43,7 +43,11 @@
   // when repeating tasks such as animated web pages have been shut down.
   void RunUntilIdle();
 
-  bool running() const { return running_; }
+  bool running() const {
+    // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
+    // DCHECK(thread_checker_.CalledOnValidThread());
+    return running_;
+  }
 
   // Quit() quits an earlier call to Run() immediately. QuitWhenIdle() quits an
   // earlier call to Run() when there aren't any tasks or messages in the queue.
@@ -72,6 +76,39 @@
   base::Closure QuitClosure();
   base::Closure QuitWhenIdleClosure();
 
+  // Cleans pre-existing TLS state.
+  // TODO(gab): Remove this in favor of managing TLS through RunLoop::Delegate
+  // as part of the RunLoop<=>MessageLoop split in http://crbug.com/703346.
+  static void ResetTLSState();
+
+  // Returns true if there is an active RunLoop on this thread.
+  static bool IsRunningOnCurrentThread();
+
+  // Returns true if there is an active RunLoop on this thread and it's nested
+  // within another active RunLoop.
+  static bool IsNestedOnCurrentThread();
+
+  // A NestingObserver is notified when a nested run loop begins. The observers
+  // are notified before the current thread's RunLoop::Delegate::Run() is
+  // invoked and nested work begins.
+  class BASE_EXPORT NestingObserver {
+   public:
+    virtual void OnBeginNestedRunLoop() = 0;
+
+   protected:
+    virtual ~NestingObserver() = default;
+  };
+
+  static void AddNestingObserverOnCurrentThread(NestingObserver* observer);
+  static void RemoveNestingObserverOnCurrentThread(NestingObserver* observer);
+
+  // Returns true if nesting is allowed on this thread.
+  static bool IsNestingAllowedOnCurrentThread();
+
+  // Disallow nesting. After this is called, running a nested RunLoop or calling
+  // Add/RemoveNestingObserverOnCurrentThread() on this thread will crash.
+  static void DisallowNestingOnCurrentThread();
+
  private:
   friend class MessageLoop;
 #if defined(OS_ANDROID)
@@ -92,20 +129,16 @@
 
   MessageLoop* loop_;
 
-  // Parent RunLoop or NULL if this is the top-most RunLoop.
-  RunLoop* previous_run_loop_;
-
-  // Used to count how many nested Run() invocations are on the stack.
-  int run_depth_;
-
-  bool run_called_;
-  bool quit_called_;
-  bool running_;
+  bool run_called_ = false;
+  bool quit_called_ = false;
+  bool running_ = false;
 
   // Used to record that QuitWhenIdle() was called on the MessageLoop, meaning
   // that we should quit Run once it becomes idle.
-  bool quit_when_idle_received_;
+  bool quit_when_idle_received_ = false;
 
+  // RunLoop's non-static methods are affine to the thread it's running on per
+  // this class' underlying use of thread-local-storage.
   base::ThreadChecker thread_checker_;
 
   // WeakPtrFactory for QuitClosure safety.
diff --git a/base/run_loop_unittest.cc b/base/run_loop_unittest.cc
index 5be97d4..dcddcfbf 100644
--- a/base/run_loop_unittest.cc
+++ b/base/run_loop_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -62,12 +63,12 @@
 }  // namespace
 
 TEST_F(RunLoopTest, QuitWhenIdle) {
-  message_loop_.task_runner()->PostTask(
+  ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, BindOnce(&QuitWhenIdleTask, Unretained(&run_loop_),
                           Unretained(&counter_)));
-  message_loop_.task_runner()->PostTask(
+  ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, BindOnce(&ShouldRunTask, Unretained(&counter_)));
-  message_loop_.task_runner()->PostDelayedTask(
+  ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1));
 
   run_loop_.Run();
@@ -75,14 +76,14 @@
 }
 
 TEST_F(RunLoopTest, QuitWhenIdleNestedLoop) {
-  message_loop_.task_runner()->PostTask(
+  ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, BindOnce(&RunNestedLoopTask, Unretained(&counter_)));
-  message_loop_.task_runner()->PostTask(
+  ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, BindOnce(&QuitWhenIdleTask, Unretained(&run_loop_),
                           Unretained(&counter_)));
-  message_loop_.task_runner()->PostTask(
+  ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, BindOnce(&ShouldRunTask, Unretained(&counter_)));
-  message_loop_.task_runner()->PostDelayedTask(
+  ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1));
 
   run_loop_.Run();
@@ -90,11 +91,11 @@
 }
 
 TEST_F(RunLoopTest, QuitWhenIdleClosure) {
-  message_loop_.task_runner()->PostTask(FROM_HERE,
-                                        run_loop_.QuitWhenIdleClosure());
-  message_loop_.task_runner()->PostTask(
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                          run_loop_.QuitWhenIdleClosure());
+  ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, BindOnce(&ShouldRunTask, Unretained(&counter_)));
-  message_loop_.task_runner()->PostDelayedTask(
+  ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1));
 
   run_loop_.Run();
@@ -113,4 +114,95 @@
   quit_when_idle_closure.Run();
 }
 
+TEST_F(RunLoopTest, IsRunningOnCurrentThread) {
+  EXPECT_FALSE(RunLoop::IsRunningOnCurrentThread());
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      Bind([]() { EXPECT_TRUE(RunLoop::IsRunningOnCurrentThread()); }));
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop_.QuitClosure());
+  run_loop_.Run();
+}
+
+TEST_F(RunLoopTest, IsNestedOnCurrentThread) {
+  EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread());
+
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind([]() {
+        EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread());
+
+        RunLoop nested_run_loop;
+
+        ThreadTaskRunnerHandle::Get()->PostTask(
+            FROM_HERE,
+            Bind([]() { EXPECT_TRUE(RunLoop::IsNestedOnCurrentThread()); }));
+        ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                nested_run_loop.QuitClosure());
+
+        EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread());
+        MessageLoop::ScopedNestableTaskAllower allower(MessageLoop::current());
+        nested_run_loop.Run();
+        EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread());
+      }));
+
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop_.QuitClosure());
+  run_loop_.Run();
+}
+
+class MockNestingObserver : public RunLoop::NestingObserver {
+ public:
+  MockNestingObserver() = default;
+
+  // RunLoop::NestingObserver:
+  MOCK_METHOD0(OnBeginNestedRunLoop, void());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockNestingObserver);
+};
+
+TEST_F(RunLoopTest, NestingObservers) {
+  EXPECT_TRUE(RunLoop::IsNestingAllowedOnCurrentThread());
+
+  testing::StrictMock<MockNestingObserver> nesting_observer;
+
+  RunLoop::AddNestingObserverOnCurrentThread(&nesting_observer);
+
+  const RepeatingClosure run_nested_loop = Bind([]() {
+    RunLoop nested_run_loop;
+    ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, Bind([]() {
+          EXPECT_TRUE(RunLoop::IsNestingAllowedOnCurrentThread());
+        }));
+    ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                            nested_run_loop.QuitClosure());
+    MessageLoop::ScopedNestableTaskAllower allower(MessageLoop::current());
+    nested_run_loop.Run();
+  });
+
+  // Generate a stack of nested RunLoops, an OnBeginNestedRunLoop() is
+  // expected when beginning each nesting depth.
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_nested_loop);
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_nested_loop);
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop_.QuitClosure());
+
+  EXPECT_CALL(nesting_observer, OnBeginNestedRunLoop()).Times(2);
+  run_loop_.Run();
+
+  RunLoop::RemoveNestingObserverOnCurrentThread(&nesting_observer);
+}
+
+// Disabled on Android per http://crbug.com/643760.
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+TEST_F(RunLoopTest, DisallowWaitingDeathTest) {
+  EXPECT_TRUE(RunLoop::IsNestingAllowedOnCurrentThread());
+  RunLoop::DisallowNestingOnCurrentThread();
+  EXPECT_FALSE(RunLoop::IsNestingAllowedOnCurrentThread());
+
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind([]() {
+                                            RunLoop nested_run_loop;
+                                            nested_run_loop.RunUntilIdle();
+                                          }));
+  EXPECT_DEATH({ run_loop_.RunUntilIdle(); }, "Check failed");
+}
+#endif  // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+
 }  // namespace base
diff --git a/base/win/scoped_comptr.h b/base/win/scoped_comptr.h
index 598f9095..527efee 100644
--- a/base/win/scoped_comptr.h
+++ b/base/win/scoped_comptr.h
@@ -100,7 +100,7 @@
   }
 
   template <class Query>
-  HRESULT QueryInterface(Query** p) {
+  HRESULT CopyTo(Query** p) {
     DCHECK(p);
     DCHECK(ptr_);
     // IUnknown already has a template version of QueryInterface
@@ -110,7 +110,7 @@
   }
 
   // QI for times when the IID is not associated with the type.
-  HRESULT QueryInterface(const IID& iid, void** obj) {
+  HRESULT CopyTo(const IID& iid, void** obj) {
     DCHECK(obj);
     DCHECK(ptr_);
     return ptr_->QueryInterface(iid, obj);
@@ -142,7 +142,7 @@
       return false;
 
     ScopedComPtr<IUnknown> my_identity;
-    QueryInterface(IID_PPV_ARGS(my_identity.Receive()));
+    CopyTo(IID_PPV_ARGS(my_identity.Receive()));
 
     ScopedComPtr<IUnknown> other_identity;
     other->QueryInterface(IID_PPV_ARGS(other_identity.Receive()));
diff --git a/base/win/scoped_comptr_unittest.cc b/base/win/scoped_comptr_unittest.cc
index b5f5f36..51a20ca 100644
--- a/base/win/scoped_comptr_unittest.cc
+++ b/base/win/scoped_comptr_unittest.cc
@@ -49,7 +49,7 @@
   EXPECT_TRUE(SUCCEEDED(CoGetMalloc(1, mem_alloc.Receive())));
 
   ScopedComPtr<IUnknown> qi_test;
-  EXPECT_HRESULT_SUCCEEDED(mem_alloc.QueryInterface(IID_PPV_ARGS(&qi_test)));
+  EXPECT_HRESULT_SUCCEEDED(mem_alloc.CopyTo(IID_PPV_ARGS(&qi_test)));
   EXPECT_TRUE(qi_test.Get() != NULL);
   qi_test.Reset();
 
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml
index 1327a6b8..e864b66b 100644
--- a/build/android/lint/suppressions.xml
+++ b/build/android/lint/suppressions.xml
@@ -437,8 +437,10 @@
     <!-- TODO(crbug.com/635567): Fix this properly. -->
     <ignore regexp="content/shell/android/shell_apk/res/values/strings.xml"/>
   </issue>
-  <!-- TODO(crbug.com/669629): Remove this when the Chromecast dependency on old layout code is removed. -->
   <issue id="UseCompoundDrawables">
+    <!-- Upscaling 24dp to 48dp doesn't work as expected with a TextView compound drawable. -->
+    <ignore regexp="chrome/android/java/res/layout/photo_picker_bitmap_view.xml"/>
+    <!-- TODO(crbug.com/669629): Remove this when the Chromecast dependency on old layout code is removed. -->
     <ignore regexp="chromecast/internal/android/prebuilt/settings/res/layout-v17/setup_activity_progress.xml"/>
   </issue>
   <issue id="UselessParent">
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index fa983d6..b6483fa 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1018,6 +1018,9 @@
         "-Wno-unknown-pragmas",  # http://crbug.com/505314
         "-Wno-microsoft-cast",  # http://crbug.com/550065
       ]
+      if (llvm_force_head_revision) {
+        cflags += [ "-Wno-microsoft-enum-forward-reference" ]  # http://crbug.com/718880
+      }
     }
   } else {
     if (is_mac && !is_nacl) {
diff --git a/chrome/android/java/res/drawable/checkmark_blue.xml b/chrome/android/java/res/drawable/checkmark_blue.xml
new file mode 100644
index 0000000..2f74dcf
--- /dev/null
+++ b/chrome/android/java/res/drawable/checkmark_blue.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:targetApi="21"
+    android:width="20dp"
+    android:height="20dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="@color/black_alpha_20"
+        android:pathData="M13,13m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M4 6H20v12H4z" />
+    <path
+        android:fillColor="@color/google_blue_500"
+        android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
+</vector>
diff --git a/chrome/android/java/res/drawable/circle_white.xml b/chrome/android/java/res/drawable/circle_white.xml
index 4fc0220..513d4a1 100644
--- a/chrome/android/java/res/drawable/circle_white.xml
+++ b/chrome/android/java/res/drawable/circle_white.xml
@@ -5,9 +5,9 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="oval">
-    <size android:height="22dp"
-        android:width="22dp"/>
+    <size android:height="20dp"
+        android:width="20dp"/>
     <stroke
-        android:width="3dp"
-        android:color="@color/white_mode_tint"/>
+        android:width="2dp"
+        android:color="@color/white_alpha_50"/>
 </shape>
diff --git a/chrome/android/java/res/layout/photo_picker_bitmap_view.xml b/chrome/android/java/res/layout/photo_picker_bitmap_view.xml
index 0171822..bb6faba 100644
--- a/chrome/android/java/res/layout/photo_picker_bitmap_view.xml
+++ b/chrome/android/java/res/layout/photo_picker_bitmap_view.xml
@@ -24,45 +24,63 @@
             android:layout_height="wrap_content"
             android:contentDescription="@null" />
 
-        <View
+        <ImageView
             android:id="@+id/scrim"
             android:layout_width="64dp"
             android:layout_height="64dp"
             android:background="@drawable/file_picker_scrim"
+            android:contentDescription="@null"
             android:visibility="gone" />
     </FrameLayout>
 
     <ImageView
         android:id="@+id/selected"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:layout_marginStart="4dp"
-        android:layout_marginTop="4dp"
+        android:layout_width="26dp"
+        android:layout_height="26dp"
+        android:layout_marginStart="2dp"
+        android:layout_marginTop="2dp"
+        android:background="@drawable/checkmark_blue"
         android:contentDescription="@null"
-        android:src="@drawable/verify_checkmark"
         android:visibility="gone" />
 
-    <View
+    <ImageView
         android:id="@+id/unselected"
         android:layout_width="22dp"
         android:layout_height="22dp"
         android:layout_marginStart="4dp"
         android:layout_marginTop="4dp"
         android:background="@drawable/circle_white"
+        android:contentDescription="@null"
         android:visibility="gone" />
 
     <!-- Special tiles, that give access to the camera and gallery  -->
-    <TextView
+    <LinearLayout
         android:id="@+id/special_tile"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/photo_picker_label_gap"
-        android:drawablePadding="10dp"
-        android:fontFamily="sans-serif-medium"
-        android:textStyle="bold"
-        android:textSize="14sp"
-        android:textAllCaps="true"
-        android:textColor="@color/photo_picker_special_tile_color"
+        android:orientation="vertical"
+        android:layout_gravity="center"
         android:gravity="center"
-        android:layout_gravity="center" />
+        android:visibility="gone">
+
+        <ImageView
+            android:id="@+id/special_tile_icon"
+            android:adjustViewBounds="true"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:contentDescription="@null"
+            android:tint="@color/photo_picker_special_tile_color" />
+
+        <TextView
+            android:id="@+id/special_tile_label"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/photo_picker_label_gap"
+            android:fontFamily="sans-serif-medium"
+            android:gravity="center"
+            android:textStyle="bold"
+            android:textSize="14sp"
+            android:textAllCaps="true"
+            android:textColor="@color/photo_picker_special_tile_color" />
+    </LinearLayout>
 </view>
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index 59556ce..3d305f5 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -36,6 +36,7 @@
     <color name="modal_dialog_scrim_color">#7f000000</color>
 
     <!-- New list of common text colors -->
+    <color name="black_alpha_20">#33000000</color>
     <color name="black_alpha_30">#4d000000</color>
     <color name="black_alpha_38">#61000000</color>
     <color name="black_alpha_40">#66000000</color>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapView.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapView.java
index 268ae51..4ae42da 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapView.java
@@ -53,16 +53,22 @@
 
     // The little shader in the top left corner (provides backdrop for selection ring on
     // unfavorable image backgrounds).
-    private View mScrim;
+    private ImageView mScrim;
 
     // The control that signifies the image has been selected.
     private ImageView mSelectedView;
 
     // The control that signifies the image has not been selected.
-    private View mUnselectedView;
+    private ImageView mUnselectedView;
 
     // The camera/gallery special tile (with icon as drawable).
-    private TextView mSpecialTile;
+    private View mSpecialTile;
+
+    // The camera/gallery icon.
+    public ImageView mSpecialTileIcon;
+
+    // The label under the special tile.
+    public TextView mSpecialTileLabel;
 
     // Whether the image has been loaded already.
     private boolean mImageLoaded;
@@ -82,10 +88,12 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mIconView = (ImageView) findViewById(R.id.bitmap_view);
-        mScrim = findViewById(R.id.scrim);
+        mScrim = (ImageView) findViewById(R.id.scrim);
         mSelectedView = (ImageView) findViewById(R.id.selected);
-        mUnselectedView = findViewById(R.id.unselected);
-        mSpecialTile = (TextView) findViewById(R.id.special_tile);
+        mUnselectedView = (ImageView) findViewById(R.id.unselected);
+        mSpecialTile = findViewById(R.id.special_tile);
+        mSpecialTileIcon = (ImageView) findViewById(R.id.special_tile_icon);
+        mSpecialTileLabel = (TextView) findViewById(R.id.special_tile_label);
     }
 
     @Override
@@ -218,12 +226,13 @@
             labelStringId = R.string.photo_picker_browse;
         }
 
-        ApiCompatibilityUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(
-                mSpecialTile, null, image, null, null);
-        mSpecialTile.setText(labelStringId);
+        mSpecialTileIcon.setImageDrawable(image);
+        mSpecialTileLabel.setText(labelStringId);
 
         // Reset visibility, since #initialize() sets mSpecialTile visibility to GONE.
         mSpecialTile.setVisibility(View.VISIBLE);
+        mSpecialTileIcon.setVisibility(View.VISIBLE);
+        mSpecialTileLabel.setVisibility(View.VISIBLE);
     }
 
     /**
@@ -274,6 +283,8 @@
         mSelectedView.setVisibility(View.GONE);
         mScrim.setVisibility(View.GONE);
         mSpecialTile.setVisibility(View.GONE);
+        mSpecialTileIcon.setVisibility(View.GONE);
+        mSpecialTileLabel.setVisibility(View.GONE);
     }
 
     /**
@@ -295,28 +306,27 @@
         boolean checked = super.isChecked();
         boolean anySelection =
                 mSelectionDelegate != null && mSelectionDelegate.isSelectionEnabled();
+        Resources resources = mContext.getResources();
         int bgColorId;
-        int fgColorId;
         if (!special) {
             bgColorId = R.color.photo_picker_tile_bg_color;
-            fgColorId = R.color.photo_picker_special_tile_color;
-        } else if (!anySelection) {
-            bgColorId = R.color.photo_picker_special_tile_bg_color;
-            fgColorId = R.color.photo_picker_special_tile_color;
         } else {
-            bgColorId = R.color.photo_picker_special_tile_disabled_bg_color;
-            fgColorId = R.color.photo_picker_special_tile_disabled_color;
+            int fgColorId;
+            if (!anySelection) {
+                bgColorId = R.color.photo_picker_special_tile_bg_color;
+                fgColorId = R.color.photo_picker_special_tile_color;
+            } else {
+                bgColorId = R.color.photo_picker_special_tile_disabled_bg_color;
+                fgColorId = R.color.photo_picker_special_tile_disabled_color;
+            }
+
+            mSpecialTileLabel.setTextColor(ApiCompatibilityUtils.getColor(resources, fgColorId));
+            Drawable drawable = mSpecialTileIcon.getDrawable();
+            int color = ApiCompatibilityUtils.getColor(resources, fgColorId);
+            drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
         }
 
-        Resources resources = mContext.getResources();
         setBackgroundColor(ApiCompatibilityUtils.getColor(resources, bgColorId));
-        mSpecialTile.setTextColor(ApiCompatibilityUtils.getColor(resources, fgColorId));
-        Drawable[] drawables = mSpecialTile.getCompoundDrawables();
-        // The textview only has a top compound drawable (2nd element).
-        if (drawables[1] != null) {
-            int color = ApiCompatibilityUtils.getColor(resources, fgColorId);
-            drawables[1].setColorFilter(color, PorterDuff.Mode.SRC_IN);
-        }
 
         // The visibility of the unselected image is a little more complex because we don't want
         // to show it when nothing is selected and also not on a blank canvas.
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 49c2b8c..8045063b 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1574,9 +1574,11 @@
      flag_descriptions::kWebglDraftExtensionsName,
      flag_descriptions::kWebglDraftExtensionsDescription, kOsAll,
      SINGLE_VALUE_TYPE(switches::kEnableWebGLDraftExtensions)},
+#if !defined(OS_ANDROID)
     {"enable-account-consistency", flag_descriptions::kAccountConsistencyName,
-     flag_descriptions::kAccountConsistencyDescription, kOsAll,
+     flag_descriptions::kAccountConsistencyDescription, kOsDesktop,
      SINGLE_VALUE_TYPE(switches::kEnableAccountConsistency)},
+#endif
     {"enable-password-separated-signin-flow",
      flag_descriptions::kEnablePasswordSeparatedSigninFlowName,
      flag_descriptions::kEnablePasswordSeparatedSigninFlowDescription,
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 8111889..a11ce33 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -15,9 +15,9 @@
 #include "base/mac/sdk_forward_declarations.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
+#include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -947,8 +947,9 @@
   // nested message loop and commands dispatched during this operation cause
   // havoc.
   if (SessionRestore::IsRestoring(lastProfile) &&
-      base::MessageLoop::current()->IsNested())
+      base::RunLoop::IsNestedOnCurrentThread()) {
     return;
+  }
 
   NSInteger tag = [sender tag];
 
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 7f1689a1..fae2f71 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -23,6 +23,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/path_service.h"
+#include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/sequenced_worker_pool.h"
@@ -1356,7 +1357,7 @@
   __lsan_do_leak_check();
 #endif
 
-  CHECK(base::MessageLoop::current()->is_running());
+  CHECK(base::RunLoop::IsRunningOnCurrentThread());
 
 #if defined(OS_MACOSX)
   base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index ab32f408..c275577 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1447,7 +1447,16 @@
     ShouldFrameShareParentSiteInstanceDespiteTopDocumentIsolation(
         const GURL& url,
         content::SiteInstance* parent_site_instance) {
-  return IsNTPSiteInstance(parent_site_instance);
+  if (IsNTPSiteInstance(parent_site_instance))
+    return true;
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  return ChromeContentBrowserClientExtensionsPart::
+      ShouldFrameShareParentSiteInstanceDespiteTopDocumentIsolation(
+          url, parent_site_instance);
+#else
+  return false;
+#endif
 }
 
 bool ChromeContentBrowserClient::IsSuitableHost(
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
index 7f26e936..4a87a2d4 100644
--- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
+++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
@@ -681,6 +681,19 @@
 }
 
 // static
+bool ChromeContentBrowserClientExtensionsPart::
+    ShouldFrameShareParentSiteInstanceDespiteTopDocumentIsolation(
+        const GURL& subframe_url,
+        content::SiteInstance* parent_site_instance) {
+  const Extension* extension =
+      ExtensionRegistry::Get(parent_site_instance->GetBrowserContext())
+          ->enabled_extensions()
+          .GetExtensionOrAppByURL(parent_site_instance->GetSiteURL());
+
+  return extension && extension->is_hosted_app();
+}
+
+// static
 void ChromeContentBrowserClientExtensionsPart::RecordShouldAllowOpenURLFailure(
     ShouldAllowOpenURLFailureReason reason,
     const GURL& site_url) {
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h
index 3e8d323..c4c8b78 100644
--- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h
+++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h
@@ -71,6 +71,10 @@
   static std::unique_ptr<content::VpnServiceProxy> GetVpnServiceProxy(
       content::BrowserContext* browser_context);
 
+  static bool ShouldFrameShareParentSiteInstanceDespiteTopDocumentIsolation(
+      const GURL& url,
+      content::SiteInstance* parent_site_instance);
+
  private:
   FRIEND_TEST_ALL_PREFIXES(ChromeContentBrowserClientExtensionsPartTest,
                            ShouldAllowOpenURLMetricsForEmptySiteURL);
diff --git a/chrome/browser/google/google_update_win.cc b/chrome/browser/google/google_update_win.cc
index 0b1d646..4c93b43 100644
--- a/chrome/browser/google/google_update_win.cc
+++ b/chrome/browser/google/google_update_win.cc
@@ -529,7 +529,7 @@
     hresult = google_update_->createAppBundleWeb(dispatch.Receive());
     if (FAILED(hresult))
       return hresult;
-    hresult = dispatch.QueryInterface(app_bundle.Receive());
+    hresult = dispatch.CopyTo(app_bundle.Receive());
     if (FAILED(hresult))
       return hresult;
     dispatch.Reset();
@@ -576,7 +576,7 @@
     if (FAILED(hresult))
       return hresult;
     base::win::ScopedComPtr<IAppWeb> app;
-    hresult = dispatch.QueryInterface(app.Receive());
+    hresult = dispatch.CopyTo(app.Receive());
     if (FAILED(hresult))
       return hresult;
     ConfigureProxyBlanket(app.Get());
@@ -598,7 +598,7 @@
   *hresult = app_->get_currentState(dispatch.Receive());
   if (FAILED(*hresult))
     return false;
-  *hresult = dispatch.QueryInterface(current_state->Receive());
+  *hresult = dispatch.CopyTo(current_state->Receive());
   if (FAILED(*hresult))
     return false;
   ConfigureProxyBlanket(current_state->Get());
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc
index 1f3da25..412147f 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc
@@ -41,8 +41,8 @@
 #include "components/policy/core/common/policy_switches.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/signin_header_helper.h"
+#include "components/signin/core/common/profile_management_switches.h"
 #include "components/signin/core/common/signin_pref_names.h"
-#include "components/signin/core/common/signin_switches.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_data.h"
@@ -482,8 +482,8 @@
                        MirrorRequestHeader) {
   // Enable account consistency so that mirror actually sets the
   // X-Chrome-Connected header in requests to Google.
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableAccountConsistency);
+  switches::EnableAccountConsistencyForTesting(
+      base::CommandLine::ForCurrentProcess());
 
   browser()->profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
                                               "user@gmail.com");
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
index 23c2049..562ca64 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
+++ b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
@@ -568,6 +568,16 @@
           "createAndAddStreams(" + base::SizeTToString(count) + ")", tab));
 }
 
+void WebRtcTestBase::VerifyRtpSenders(
+    content::WebContents* tab,
+    base::Optional<size_t> expected_num_tracks) const {
+  std::string javascript =
+      expected_num_tracks ? "verifyRtpSenders(" +
+                                base::SizeTToString(*expected_num_tracks) + ")"
+                          : "verifyRtpSenders()";
+  EXPECT_EQ("ok-senders-verified", ExecuteJavascript(javascript, tab));
+}
+
 void WebRtcTestBase::VerifyRtpReceivers(
     content::WebContents* tab,
     base::Optional<size_t> expected_num_tracks) const {
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest_base.h b/chrome/browser/media/webrtc/webrtc_browsertest_base.h
index 71e0cf68..4e1b150 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest_base.h
+++ b/chrome/browser/media/webrtc/webrtc_browsertest_base.h
@@ -188,6 +188,9 @@
   void EnableOpusDtx(content::WebContents* tab) const;
 
   void CreateAndAddStreams(content::WebContents* tab, size_t count) const;
+  void VerifyRtpSenders(content::WebContents* tab,
+                        base::Optional<size_t> expected_num_tracks =
+                            base::Optional<size_t>()) const;
   void VerifyRtpReceivers(content::WebContents* tab,
                           base::Optional<size_t> expected_num_tracks =
                               base::Optional<size_t>()) const;
diff --git a/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc b/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
index 5de342e..bd591a9 100644
--- a/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
@@ -19,6 +19,8 @@
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
+    command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures,
+                                    "RTCRtpSender");
   }
 
  protected:
@@ -32,6 +34,21 @@
   content::WebContents* right_tab_;
 };
 
+IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest, GetSenders) {
+  StartServerAndOpenTabs();
+
+  SetupPeerconnectionWithoutLocalStream(left_tab_);
+  CreateAndAddStreams(left_tab_, 3);
+
+  SetupPeerconnectionWithoutLocalStream(right_tab_);
+  CreateAndAddStreams(right_tab_, 1);
+
+  NegotiateCall(left_tab_, right_tab_);
+
+  VerifyRtpSenders(left_tab_, 6);
+  VerifyRtpSenders(right_tab_, 2);
+}
+
 IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest, GetReceivers) {
   StartServerAndOpenTabs();
 
diff --git a/chrome/browser/metrics/chromeos_metrics_provider_unittest.cc b/chrome/browser/metrics/chromeos_metrics_provider_unittest.cc
index 76f8ac0bb..1e8357ac 100644
--- a/chrome/browser/metrics/chromeos_metrics_provider_unittest.cc
+++ b/chrome/browser/metrics/chromeos_metrics_provider_unittest.cc
@@ -132,7 +132,7 @@
     base::RunLoop().Run();
   }
   void GetBluetoothAdapterCallback() {
-    ASSERT_TRUE(base::MessageLoop::current()->is_running());
+    ASSERT_TRUE(base::RunLoop::IsRunningOnCurrentThread());
     base::MessageLoop::current()->QuitWhenIdle();
   }
 };
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
index 80b59a1c..2a3c059 100644
--- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -6,10 +6,12 @@
 
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
+#include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/extensions/test_extension_dir.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
@@ -17,11 +19,17 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_utils.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_set.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 #if defined(OS_MACOSX)
 #include "chrome/common/chrome_features.h"
@@ -60,9 +68,12 @@
 
  protected:
   void SetupApp(const std::string& app_folder, bool is_bookmark_app) {
+    SetupApp(test_data_dir_.AppendASCII(app_folder), is_bookmark_app);
+  }
+
+  void SetupApp(const base::FilePath& app_folder, bool is_bookmark_app) {
     const Extension* app = InstallExtensionWithSourceAndFlags(
-        test_data_dir_.AppendASCII(app_folder), 1,
-        extensions::Manifest::INTERNAL,
+        app_folder, 1, extensions::Manifest::INTERNAL,
         is_bookmark_app ? extensions::Extension::FROM_BOOKMARK
                         : extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(app);
@@ -186,3 +197,155 @@
   NavigateAndCheckForLocationBar(
       app_browser_, "http://www.foo.com/blah", true);
 }
+
+class HostedAppVsTdiTest : public HostedAppTest {
+ public:
+  HostedAppVsTdiTest() {}
+  ~HostedAppVsTdiTest() override {}
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    HostedAppTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kTopDocumentIsolation);
+  }
+
+  void SetUpOnMainThread() override {
+    HostedAppTest::SetUpOnMainThread();
+    host_resolver()->AddRule("*", "127.0.0.1");
+    ASSERT_TRUE(embedded_test_server()->Start());
+  }
+};
+
+// Tests that even with --top-document-isolation, app.site.com (covered by app's
+// web extent) main frame and foo.site.com (not covered by app's web extent)
+// share the same renderer process.  See also https://crbug.com/679011.
+//
+// Relevant frames in the test:
+// - |app| - app.site.com/frame_tree/cross_origin_but_same_site_frames.html
+//           Main frame, launch URL of the hosted app (i.e. app.launch.web_url).
+// - |same_dir| - app.site.com/frame_tree/simple.htm
+//                Another URL, but still covered by hosted app's web extent
+//                (i.e. by app.urls).
+// - |diff_dir| - app.site.com/save_page/a.htm
+//                Same origin as |same_dir| and |app|, but not covered by app's
+//                extent.
+// - |same_site| - other.site.com/title1.htm
+//                 Different origin, but same site as |app|, |same_dir|,
+//                 |diff_dir|.
+// - |cross_site| - cross.domain.com/title1.htm
+//                  Cross-site from all the other frames.
+//
+// Verifications of |*_site| (e.g. EXPECT_EQ(same_dir_site, app_site) are
+// sanity checks of the test setup.
+//
+// First real verification in the test is whether |same_dir| and |diff_dir| can
+// script each other (despite their effective URLs being cross-site, because
+// |same_dir| is mapped to a chrome-extension URL).  This was a functionality
+// problem caused by https://crbug.com/679011.
+//
+// The test also verifies that all same-site frames (i.e. |app|, |same_dir|,
+// |diff_dir|, |same_site|) share the same renderer process.  This was a small
+// performance problem caused by https://crbug.com/679011.
+IN_PROC_BROWSER_TEST_F(HostedAppVsTdiTest, ProcessAllocation) {
+  // Setup and launch the hosted app.
+  GURL url = embedded_test_server()->GetURL(
+      "app.site.com", "/frame_tree/cross_origin_but_same_site_frames.html");
+
+  extensions::TestExtensionDir test_app_dir;
+  test_app_dir.WriteManifest(base::StringPrintf(
+      R"( { "name": "Hosted App vs TDI Test",
+            "version": "1",
+            "manifest_version": 2,
+            "app": {
+              "launch": {
+                "web_url": "%s"
+              },
+              "urls": ["*://app.site.com/frame_tree"]
+            }
+          } )",
+      url.spec().c_str()));
+  SetupApp(test_app_dir.UnpackedPath(), false);
+
+  content::WebContents* web_contents =
+      app_browser_->tab_strip_model()->GetActiveWebContents();
+  content::WaitForLoadStop(web_contents);
+
+  auto find_frame = [web_contents](const std::string& name) {
+    return content::FrameMatchingPredicate(
+        web_contents, base::Bind(&content::FrameMatchesName, name));
+  };
+  content::RenderFrameHost* app = web_contents->GetMainFrame();
+  content::RenderFrameHost* same_dir = find_frame("SameOrigin-SamePath");
+  content::RenderFrameHost* diff_dir = find_frame("SameOrigin-DifferentPath");
+  content::RenderFrameHost* same_site = find_frame("OtherSubdomain-SameSite");
+  content::RenderFrameHost* cross_site = find_frame("CrossSite");
+
+  // Sanity-check sites of all relevant frames to verify test setup.
+  GURL app_site = content::SiteInstance::GetSiteForURL(
+      app_browser_->profile(), app->GetLastCommittedURL());
+  EXPECT_EQ(extensions::kExtensionScheme, app_site.scheme());
+
+  GURL same_dir_site = content::SiteInstance::GetSiteForURL(
+      app_browser_->profile(), same_dir->GetLastCommittedURL());
+  EXPECT_EQ(extensions::kExtensionScheme, same_dir_site.scheme());
+  EXPECT_EQ(same_dir_site, app_site);
+
+  GURL diff_dir_site = content::SiteInstance::GetSiteForURL(
+      app_browser_->profile(), diff_dir->GetLastCommittedURL());
+  EXPECT_NE(extensions::kExtensionScheme, diff_dir_site.scheme());
+  EXPECT_NE(diff_dir_site, app_site);
+
+  GURL same_site_site = content::SiteInstance::GetSiteForURL(
+      app_browser_->profile(), same_site->GetLastCommittedURL());
+  EXPECT_NE(extensions::kExtensionScheme, same_site_site.scheme());
+  EXPECT_NE(same_site_site, app_site);
+  EXPECT_EQ(same_site_site, diff_dir_site);
+
+  GURL cross_site_site = content::SiteInstance::GetSiteForURL(
+      app_browser_->profile(), cross_site->GetLastCommittedURL());
+  EXPECT_NE(cross_site_site, app_site);
+  EXPECT_NE(cross_site_site, same_site_site);
+
+  // Verify that |same_dir| and |diff_dir| have the same origin according to
+  // |window.origin| (even though they have different |same_dir_site| and
+  // |diff_dir_site|).
+  std::string same_dir_origin;
+  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+      same_dir, "domAutomationController.send(window.origin)",
+      &same_dir_origin));
+
+  std::string diff_dir_origin;
+  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+      diff_dir, "domAutomationController.send(window.origin)",
+      &diff_dir_origin));
+
+  EXPECT_EQ(diff_dir_origin, same_dir_origin);
+
+  // Verify scriptability and process placement.
+  EXPECT_EQ(same_dir->GetProcess(), app->GetProcess());
+  if (!content::AreAllSitesIsolatedForTesting()) {
+    // Verify that |same_dir| and |diff_dir| can script each other.
+    // (they should - they have the same origin).
+    std::string inner_text_from_other_frame;
+    ASSERT_TRUE(content::ExecuteScriptAndExtractString(
+        diff_dir,
+        R"( var w = window.open('', 'SameOrigin-SamePath');
+            domAutomationController.send(w.document.body.innerText); )",
+        &inner_text_from_other_frame));
+    EXPECT_EQ("Simple test page.", inner_text_from_other_frame);
+
+    // Verify there are no additional processes for same-site frames.
+    EXPECT_EQ(diff_dir->GetProcess(), app->GetProcess());
+    EXPECT_EQ(same_site->GetProcess(), app->GetProcess());
+    // TODO(lukasza): https://crbug.com/718516: For now it is okay for
+    // |cross_site| to be in any process, but we should probably revisit
+    // before launching --top-document-isolation more broadly.
+  } else {
+    // TODO(lukasza): https://crbug.com/718516: Process policy is not
+    // well-defined / settled wrt relationship between 1) hosted apps and 2)
+    // same-site web content outside of hosted app's extent.  When this test was
+    // authored --site-per-process would put |app| in a separate renderer
+    // process from |diff_dir| and |same_site|, even though such process
+    // placement can be problematic (if |app| tries to synchronously script
+    // |diff_dir| and/or |same_site|).
+  }
+}
diff --git a/chrome/browser/ui/views/simple_message_box_views.cc b/chrome/browser/ui/views/simple_message_box_views.cc
index 91c21939..972b848 100644
--- a/chrome/browser/ui/views/simple_message_box_views.cc
+++ b/chrome/browser/ui/views/simple_message_box_views.cc
@@ -223,7 +223,7 @@
   // Fallback to logging with a default response or a Windows MessageBox.
 #if defined(OS_WIN)
   if (!base::MessageLoopForUI::IsCurrent() ||
-      !base::MessageLoopForUI::current()->is_running() ||
+      !base::RunLoop::IsRunningOnCurrentThread() ||
       !ResourceBundle::HasSharedInstance()) {
     LOG_IF(ERROR, !checkbox_text.empty()) << "Dialog checkbox won't be shown";
     int result = ui::MessageBox(views::HWNDForNativeWindow(parent), message,
diff --git a/chrome/browser/win/jumplist_updater.cc b/chrome/browser/win/jumplist_updater.cc
index 0040196..c087a4c9 100644
--- a/chrome/browser/win/jumplist_updater.cc
+++ b/chrome/browser/win/jumplist_updater.cc
@@ -63,7 +63,7 @@
   // shortcut which doesn't have titles.
   // So, we should use the IPropertyStore interface to set its title.
   base::win::ScopedComPtr<IPropertyStore> property_store;
-  result = link.QueryInterface(property_store.Receive());
+  result = link.CopyTo(property_store.Receive());
   if (FAILED(result))
     return false;
 
@@ -196,7 +196,7 @@
   // interface to retrieve each item in the list. So, we retrieve the
   // IObjectArray interface from the EnumerableObjectCollection object.
   base::win::ScopedComPtr<IObjectArray> object_array;
-  result = collection.QueryInterface(object_array.Receive());
+  result = collection.CopyTo(object_array.Receive());
   if (FAILED(result))
     return false;
 
@@ -246,7 +246,7 @@
   // It seems the ICustomDestinationList::AppendCategory() function just
   // replaces all items in the given category with the ones in the new list.
   base::win::ScopedComPtr<IObjectArray> object_array;
-  result = collection.QueryInterface(object_array.Receive());
+  result = collection.CopyTo(object_array.Receive());
   if (FAILED(result))
     return false;
 
diff --git a/chrome/test/data/frame_tree/cross_origin_but_same_site_frames.html b/chrome/test/data/frame_tree/cross_origin_but_same_site_frames.html
new file mode 100644
index 0000000..eb6a8b9c
--- /dev/null
+++ b/chrome/test/data/frame_tree/cross_origin_but_same_site_frames.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html>
+<head></head>
+<body>
+  This page has iframes for testing hosted app's web extents:
+  <hr>
+  Same origin, same path:
+  <iframe name="SameOrigin-SamePath"
+          src="simple.htm"></iframe>
+  <hr>
+  Same origin, but different path:
+  <iframe name="SameOrigin-DifferentPath"
+          src="/save_page/a.htm"></iframe>
+  <hr>
+  other.site.com site:
+  <iframe name="OtherSubdomain-SameSite"
+          src="/cross-site/other.site.com/title1.html"></iframe>
+  <hr>
+  cross.domain.com site:
+  <iframe name="CrossSite"
+          src="/cross-site/cross.domain.com/title1.html"></iframe>
+</body>
+</html>
diff --git a/chrome/test/data/frame_tree/simple.htm b/chrome/test/data/frame_tree/simple.htm
new file mode 100644
index 0000000..903213a
--- /dev/null
+++ b/chrome/test/data/frame_tree/simple.htm
@@ -0,0 +1,4 @@
+<html>
+<head></head>
+<body>Simple test page.</body>
+</html>
diff --git a/chrome/test/data/webrtc/peerconnection_rtp.js b/chrome/test/data/webrtc/peerconnection_rtp.js
index 755c097..49962de 100644
--- a/chrome/test/data/webrtc/peerconnection_rtp.js
+++ b/chrome/test/data/webrtc/peerconnection_rtp.js
@@ -30,6 +30,51 @@
 }
 
 /**
+ * Verifies that the peer connection's getSenders() returns one sender per local
+ * track, that there are no duplicates and that object identity is preserved.
+ *
+ * Returns "ok-senders-verified" on success.
+ */
+function verifyRtpSenders(expectedNumTracks = null) {
+  if (expectedNumTracks != null &&
+      peerConnection_().getSenders().length != expectedNumTracks) {
+    throw failTest('getSenders().length != expectedNumTracks');
+  }
+  if (!arrayEquals_(peerConnection_().getSenders(),
+                    peerConnection_().getSenders())) {
+    throw failTest('One getSenders() call is not equal to the next.');
+  }
+
+  let localTracks = new Set();
+  peerConnection_().getLocalStreams().forEach(function(stream) {
+    stream.getTracks().forEach(function(track) {
+      localTracks.add(track);
+    });
+  });
+  if (peerConnection_().getSenders().length != localTracks.size)
+    throw failTest('The number of senders and tracks are not the same.');
+
+  let senders = new Set();
+  let senderTracks = new Set();
+  peerConnection_().getSenders().forEach(function(sender) {
+    if (sender == null)
+      throw failTest('sender is null or undefined.');
+    if (sender.track == null)
+      throw failTest('sender.track is null or undefined.');
+    senders.add(sender);
+    senderTracks.add(sender.track);
+  });
+  if (senderTracks.size != senders.size)
+    throw failTest('senderTracks.size != senders.size');
+
+  if (!setEquals_(senderTracks, localTracks)) {
+    throw failTest('The set of sender tracks is not equal to the set of ' +
+                   'stream tracks.');
+  }
+  returnToTest('ok-senders-verified');
+}
+
+/**
  * Verifies that the peer connection's getReceivers() returns one receiver per
  * remote track, that there are no duplicates and that object identity is
  * preserved.
diff --git a/chrome/tools/build/win/FILES.cfg b/chrome/tools/build/win/FILES.cfg
index 79d382c..58d5771 100644
--- a/chrome/tools/build/win/FILES.cfg
+++ b/chrome/tools/build/win/FILES.cfg
@@ -420,6 +420,39 @@
     'optional': ['dev'],
   },
   {
+    'filename': 'remote_assistance_host.exe',
+    'buildtype': ['official'],
+    'archive': 'remoting-win32.zip',
+    'filegroup': ['symsrc'],
+  },
+  {
+    'filename': 'remote_assistance_host.exe.pdb',
+    'buildtype': ['official'],
+    'archive': 'remoting-win32.zip',
+  },
+  {
+    'filename': 'remote_assistance_host_uiaccess.exe',
+    'buildtype': ['official'],
+    'archive': 'remoting-win32.zip',
+    'filegroup': ['symsrc'],
+  },
+  {
+    'filename': 'remote_assistance_host_uiaccess.exe.pdb',
+    'buildtype': ['official'],
+    'archive': 'remoting-win32.zip',
+  },
+  {
+    'filename': 'remote_security_key.exe',
+    'buildtype': ['official'],
+    'archive': 'remoting-win32.zip',
+    'filegroup': ['symsrc'],
+  },
+  {
+    'filename': 'remote_security_key.exe.pdb',
+    'buildtype': ['official'],
+    'archive': 'remoting-win32.zip',
+  },
+  {
     'filename': 'remoting_core.dll',
     'buildtype': ['official'],
     'archive': 'remoting-win32.zip',
@@ -454,6 +487,28 @@
     'buildtype': ['official'],
     'archive': 'remoting-win32.zip',
   },
+  {
+    'filename': 'remoting_native_messaging_host.exe',
+    'buildtype': ['official'],
+    'archive': 'remoting-win32.zip',
+    'filegroup': ['symsrc'],
+  },
+  {
+    'filename': 'remoting_native_messaging_host.exe.pdb',
+    'buildtype': ['official'],
+    'archive': 'remoting-win32.zip',
+  },
+  {
+    'filename': 'remoting_start_host.exe',
+    'buildtype': ['official'],
+    'archive': 'remoting-win32.zip',
+    'filegroup': ['symsrc'],
+  },
+  {
+    'filename': 'remoting_start_host.exe.pdb',
+    'buildtype': ['official'],
+    'archive': 'remoting-win32.zip',
+  },
   # Cloud Print files:
   {
     'filename': 'gcp_portmon.dll',
diff --git a/chromeos/dbus/services/service_provider_test_helper.cc b/chromeos/dbus/services/service_provider_test_helper.cc
index f463a65d..6a3488d 100644
--- a/chromeos/dbus/services/service_provider_test_helper.cc
+++ b/chromeos/dbus/services/service_provider_test_helper.cc
@@ -158,7 +158,7 @@
     std::unique_ptr<dbus::Response> response) {
   response_ = std::move(response);
   response_received_ = true;
-  if (base::MessageLoop::current()->is_running())
+  if (base::RunLoop::IsRunningOnCurrentThread())
     base::MessageLoop::current()->QuitWhenIdle();
 }
 
diff --git a/components/metrics/metrics_log.cc b/components/metrics/metrics_log.cc
index 42331e3..ac35ce3 100644
--- a/components/metrics/metrics_log.cc
+++ b/components/metrics/metrics_log.cc
@@ -151,7 +151,12 @@
 
   metrics::SystemProfileProto::Hardware* hardware =
       system_profile->mutable_hardware();
+#if !defined(OS_IOS)
+  // On iOS, OperatingSystemArchitecture() returns values like iPad4,4 which is
+  // not the actual CPU architecture. Don't set it until the API is fixed. See
+  // crbug.com/370104 for details.
   hardware->set_cpu_architecture(base::SysInfo::OperatingSystemArchitecture());
+#endif
   hardware->set_system_ram_mb(base::SysInfo::AmountOfPhysicalMemoryMB());
   hardware->set_hardware_class(base::SysInfo::HardwareModelName());
 #if defined(OS_WIN)
diff --git a/components/metrics/metrics_log_unittest.cc b/components/metrics/metrics_log_unittest.cc
index 63152c6..f1a7792 100644
--- a/components/metrics/metrics_log_unittest.cc
+++ b/components/metrics/metrics_log_unittest.cc
@@ -196,7 +196,9 @@
 #endif
   metrics::SystemProfileProto::Hardware* hardware =
       system_profile->mutable_hardware();
+#if !defined(OS_IOS)
   hardware->set_cpu_architecture(base::SysInfo::OperatingSystemArchitecture());
+#endif
   hardware->set_system_ram_mb(base::SysInfo::AmountOfPhysicalMemoryMB());
   hardware->set_hardware_class(base::SysInfo::HardwareModelName());
 #if defined(OS_WIN)
diff --git a/components/omnibox/browser/autocomplete_provider_unittest.cc b/components/omnibox/browser/autocomplete_provider_unittest.cc
index e3f3a3ff..4710743 100644
--- a/components/omnibox/browser/autocomplete_provider_unittest.cc
+++ b/components/omnibox/browser/autocomplete_provider_unittest.cc
@@ -74,7 +74,7 @@
       AutocompleteController* controller) override {
     if (!closure_.is_null())
       closure_.Run();
-    if (base::MessageLoop::current()->is_running())
+    if (base::RunLoop::IsRunningOnCurrentThread())
       base::MessageLoop::current()->QuitWhenIdle();
   }
 
diff --git a/components/os_crypt/os_crypt.h b/components/os_crypt/os_crypt.h
index b62aca4..10945309 100644
--- a/components/os_crypt/os_crypt.h
+++ b/components/os_crypt/os_crypt.h
@@ -38,6 +38,9 @@
   // this when we stop supporting keyring.
   static void SetMainThreadRunner(
       scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner);
+
+  // Returns true iff the real secret key (not hardcoded one) is available.
+  static bool IsEncryptionAvailable();
 #endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
 
   // Encrypt a string16. The output (second argument) is really an array of
diff --git a/components/os_crypt/os_crypt_linux.cc b/components/os_crypt/os_crypt_linux.cc
index 496d971..ac8d5c4 100644
--- a/components/os_crypt/os_crypt_linux.cc
+++ b/components/os_crypt/os_crypt_linux.cc
@@ -248,6 +248,11 @@
   KeyStorageLinux::SetMainThreadRunner(main_thread_runner);
 }
 
+// static
+bool OSCrypt::IsEncryptionAvailable() {
+  return g_get_password[Version::V11]();
+}
+
 void UseMockKeyStorageForTesting(KeyStorageLinux* (*get_key_storage_mock)(),
                                  std::string* (*get_password_v11_mock)()) {
   // Save the real implementation to restore it later.
@@ -259,7 +264,7 @@
     is_get_password_saved = true;
   }
 
-  if (get_key_storage_mock && get_password_v11_mock) {
+  if (get_key_storage_mock || get_password_v11_mock) {
     // Bypass calling KeyStorage::CreateService and caching of the key for V11
     if (get_password_v11_mock)
       g_get_password[Version::V11] = get_password_v11_mock;
diff --git a/components/os_crypt/os_crypt_linux_unittest.cc b/components/os_crypt/os_crypt_linux_unittest.cc
index 5f22c316..dce4c4a2 100644
--- a/components/os_crypt/os_crypt_linux_unittest.cc
+++ b/components/os_crypt/os_crypt_linux_unittest.cc
@@ -12,6 +12,10 @@
 
 namespace {
 
+KeyStorageLinux* GetNullKeyStorage() {
+  return nullptr;
+}
+
 class OSCryptLinuxTest : public testing::Test {
  public:
   OSCryptLinuxTest() = default;
@@ -67,4 +71,13 @@
   ASSERT_EQ(originaltext, decipheredtext);
 }
 
+TEST_F(OSCryptLinuxTest, IsEncryptionAvailable) {
+  EXPECT_TRUE(OSCrypt::IsEncryptionAvailable());
+  // Restore default GetKeyStorage and GetPassword functions.
+  UseMockKeyStorageForTesting(nullptr, nullptr);
+  // Mock only GetKeyStorage function.
+  UseMockKeyStorageForTesting(GetNullKeyStorage, nullptr);
+  EXPECT_FALSE(OSCrypt::IsEncryptionAvailable());
+}
+
 }  // namespace
diff --git a/components/policy/core/common/config_dir_policy_loader.cc b/components/policy/core/common/config_dir_policy_loader.cc
index b58a0bc..91f3067 100644
--- a/components/policy/core/common/config_dir_policy_loader.cc
+++ b/components/policy/core/common/config_dir_policy_loader.cc
@@ -129,7 +129,7 @@
        !config_file_path.empty(); config_file_path = file_enumerator.Next())
     files.insert(config_file_path);
 
-  PolicyLoadStatusSample status;
+  PolicyLoadStatusUmaReporter status;
   if (files.empty()) {
     status.Add(POLICY_LOAD_STATUS_NO_POLICY);
     return;
diff --git a/components/policy/core/common/policy_load_status.cc b/components/policy/core/common/policy_load_status.cc
index 71c5059a..1495d7c5 100644
--- a/components/policy/core/common/policy_load_status.cc
+++ b/components/policy/core/common/policy_load_status.cc
@@ -4,6 +4,7 @@
 
 #include "components/policy/core/common/policy_load_status.h"
 
+#include "base/bind.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/stringprintf.h"
 #include "components/policy/core/common/policy_types.h"
@@ -16,23 +17,27 @@
 
 }  // namespace
 
-PolicyLoadStatusSample::PolicyLoadStatusSample()
-    : histogram_(base::LinearHistogram::FactoryGet(
-          kHistogramName, 1, POLICY_LOAD_STATUS_SIZE,
-          POLICY_LOAD_STATUS_SIZE + 1,
-          base::Histogram::kUmaTargetedHistogramFlag)) {
+PolicyLoadStatusSampler::PolicyLoadStatusSampler() {
   Add(POLICY_LOAD_STATUS_STARTED);
 }
 
-PolicyLoadStatusSample::~PolicyLoadStatusSample() {
-  for (int i = 0; i < POLICY_LOAD_STATUS_SIZE; ++i) {
-    if (status_bits_[i])
-      histogram_->Add(i);
-  }
+PolicyLoadStatusSampler::~PolicyLoadStatusSampler() {}
+
+void PolicyLoadStatusSampler::Add(PolicyLoadStatus status) {
+  status_bits_[status] = true;
 }
 
-void PolicyLoadStatusSample::Add(PolicyLoadStatus status) {
-  status_bits_[status] = true;
+PolicyLoadStatusUmaReporter::PolicyLoadStatusUmaReporter() {}
+
+PolicyLoadStatusUmaReporter::~PolicyLoadStatusUmaReporter() {
+  base::HistogramBase* histogram(base::LinearHistogram::FactoryGet(
+      kHistogramName, 1, POLICY_LOAD_STATUS_SIZE, POLICY_LOAD_STATUS_SIZE + 1,
+      base::Histogram::kUmaTargetedHistogramFlag));
+
+  for (int i = 0; i < POLICY_LOAD_STATUS_SIZE; ++i) {
+    if (GetStatusSet()[i])
+      histogram->Add(i);
+  }
 }
 
 }  // namespace policy
diff --git a/components/policy/core/common/policy_load_status.h b/components/policy/core/common/policy_load_status.h
index 6c9e907..dc3979e 100644
--- a/components/policy/core/common/policy_load_status.h
+++ b/components/policy/core/common/policy_load_status.h
@@ -10,10 +10,6 @@
 #include "base/macros.h"
 #include "components/policy/policy_export.h"
 
-namespace base {
-class HistogramBase;
-}
-
 namespace policy {
 
 // UMA histogram enum for policy load status. Don't change existing constants,
@@ -44,22 +40,35 @@
   POLICY_LOAD_STATUS_SIZE
 };
 
-// A helper for generating policy load status UMA statistics that'll collect
-// histogram samples for a policy load operation and records histogram samples
-// for the status codes that were seen on destruction.
-class POLICY_EXPORT PolicyLoadStatusSample {
+// A helper for collecting statuses for a policy load operation.
+class POLICY_EXPORT PolicyLoadStatusSampler {
  public:
-  PolicyLoadStatusSample();
-  ~PolicyLoadStatusSample();
+  using StatusSet = std::bitset<POLICY_LOAD_STATUS_SIZE>;
+
+  PolicyLoadStatusSampler();
+  virtual ~PolicyLoadStatusSampler();
 
   // Adds a status code.
   void Add(PolicyLoadStatus status);
 
- private:
-  std::bitset<POLICY_LOAD_STATUS_SIZE> status_bits_;
-  base::HistogramBase* histogram_;
+  // Returns a set with all statuses.
+  const StatusSet& GetStatusSet() const { return status_bits_; }
 
-  DISALLOW_COPY_AND_ASSIGN(PolicyLoadStatusSample);
+ private:
+  StatusSet status_bits_;
+  DISALLOW_COPY_AND_ASSIGN(PolicyLoadStatusSampler);
+};
+
+// A helper for generating policy load status UMA statistics. On destruction,
+// records histogram samples for the collected status codes.
+class POLICY_EXPORT PolicyLoadStatusUmaReporter
+    : public PolicyLoadStatusSampler {
+ public:
+  PolicyLoadStatusUmaReporter();
+  ~PolicyLoadStatusUmaReporter() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PolicyLoadStatusUmaReporter);
 };
 
 }  // namespace policy
diff --git a/components/policy/core/common/policy_loader_mac.mm b/components/policy/core/common/policy_loader_mac.mm
index 94e8ebc6..e444c705 100644
--- a/components/policy/core/common/policy_loader_mac.mm
+++ b/components/policy/core/common/policy_loader_mac.mm
@@ -70,7 +70,7 @@
   PolicyMap& chrome_policy =
       bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
 
-  PolicyLoadStatusSample status;
+  PolicyLoadStatusUmaReporter status;
   bool policy_present = false;
   const Schema* schema =
       schema_map()->GetSchema(PolicyNamespace(POLICY_DOMAIN_CHROME, ""));
diff --git a/components/policy/core/common/policy_loader_win.cc b/components/policy/core/common/policy_loader_win.cc
index b5ff23fa..0881e239 100644
--- a/components/policy/core/common/policy_loader_win.cc
+++ b/components/policy/core/common/policy_loader_win.cc
@@ -4,7 +4,6 @@
 
 #include "components/policy/core/common/policy_loader_win.h"
 
-#include <windows.h>
 #include <ntdsapi.h>  // For Ds[Un]Bind
 #include <rpc.h>      // For struct GUID
 #include <shlwapi.h>  // For PathIsUNC()
@@ -70,7 +69,7 @@
     key::kRestoreOnStartupURLs};
 
 #pragma warning(push)
-#pragma warning(disable: 4068)  // unknown pragmas
+#pragma warning(disable : 4068)  // unknown pragmas
 // TODO(dcheng): Remove pragma once http://llvm.org/PR24007 is fixed.
 #pragma clang diagnostic ignored "-Wmissing-braces"
 // The GUID of the registry settings group policy extension.
@@ -132,8 +131,8 @@
       filtered_entry.value = std::move(filtered_values);
       policy->Set(key::kExtensionInstallForcelist, std::move(filtered_entry));
 
-      const PolicyDetails* details = GetChromePolicyDetails(
-          key::kExtensionInstallForcelist);
+      const PolicyDetails* details =
+          GetChromePolicyDetails(key::kExtensionInstallForcelist);
       UMA_HISTOGRAM_SPARSE_SLOWLY("EnterpriseCheck.InvalidPolicies",
                                   details->id);
     }
@@ -159,10 +158,10 @@
 class Wow64Functions {
  public:
   Wow64Functions()
-    : kernel32_lib_(base::FilePath(L"kernel32")),
-      is_wow_64_process_(NULL),
-      wow_64_disable_wow_64_fs_redirection_(NULL),
-      wow_64_revert_wow_64_fs_redirection_(NULL) {
+      : kernel32_lib_(base::FilePath(L"kernel32")),
+        is_wow_64_process_(NULL),
+        wow_64_disable_wow_64_fs_redirection_(NULL),
+        wow_64_revert_wow_64_fs_redirection_(NULL) {
     if (kernel32_lib_.is_valid()) {
       is_wow_64_process_ = reinterpret_cast<IsWow64Process>(
           kernel32_lib_.GetFunctionPointer("IsWow64Process"));
@@ -178,9 +177,8 @@
   }
 
   bool is_valid() {
-    return is_wow_64_process_ &&
-        wow_64_disable_wow_64_fs_redirection_ &&
-        wow_64_revert_wow_64_fs_redirection_;
+    return is_wow_64_process_ && wow_64_disable_wow_64_fs_redirection_ &&
+           wow_64_revert_wow_64_fs_redirection_;
   }
 
   bool IsWow64() {
@@ -199,9 +197,9 @@
   }
 
  private:
-  typedef BOOL (WINAPI* IsWow64Process)(HANDLE, PBOOL);
-  typedef BOOL (WINAPI* Wow64DisableWow64FSRedirection)(PVOID*);
-  typedef BOOL (WINAPI* Wow64RevertWow64FSRedirection)(PVOID);
+  typedef BOOL(WINAPI* IsWow64Process)(HANDLE, PBOOL);
+  typedef BOOL(WINAPI* Wow64DisableWow64FSRedirection)(PVOID*);
+  typedef BOOL(WINAPI* Wow64RevertWow64FSRedirection)(PVOID);
 
   base::ScopedNativeLibrary kernel32_lib_;
 
@@ -219,9 +217,7 @@
 // Scoper that switches off Wow64 File System Redirection during its lifetime.
 class ScopedDisableWow64Redirection {
  public:
-  ScopedDisableWow64Redirection()
-    : active_(false),
-      previous_state_(NULL) {
+  ScopedDisableWow64Redirection() : active_(false), previous_state_(NULL) {
     Wow64Functions* wow64 = g_wow_64_functions.Pointer();
     if (wow64->is_valid() && wow64->IsWow64()) {
       if (wow64->DisableFsRedirection(&previous_state_))
@@ -372,8 +368,8 @@
     PolicyScope scope;
     HKEY hive;
   } kScopes[] = {
-    { POLICY_SCOPE_MACHINE, HKEY_LOCAL_MACHINE },
-    { POLICY_SCOPE_USER,    HKEY_CURRENT_USER  },
+      {POLICY_SCOPE_MACHINE, HKEY_LOCAL_MACHINE},
+      {POLICY_SCOPE_USER, HKEY_CURRENT_USER},
   };
 
   bool honor_policies = ShouldHonorPolicies();
@@ -386,7 +382,7 @@
       &bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
   for (size_t i = 0; i < arraysize(kScopes); ++i) {
     PolicyScope scope = kScopes[i].scope;
-    PolicyLoadStatusSample status;
+    PolicyLoadStatusUmaReporter status;
     RegistryDict gpo_dict;
 
     // Note: GPO rules mandate a call to EnterCriticalPolicySection() here, and
@@ -434,7 +430,7 @@
 
 bool PolicyLoaderWin::ReadPRegFile(const base::FilePath& preg_file,
                                    RegistryDict* policy,
-                                   PolicyLoadStatusSample* status) {
+                                   PolicyLoadStatusSampler* status) {
   // The following deals with the minor annoyance that Wow64 FS redirection
   // might need to be turned off: This is the case if running as a 32-bit
   // process on a 64-bit system, in which case Wow64 FS redirection redirects
@@ -462,11 +458,11 @@
 bool PolicyLoaderWin::LoadGPOPolicy(PolicyScope scope,
                                     PGROUP_POLICY_OBJECT policy_object_list,
                                     RegistryDict* policy,
-                                    PolicyLoadStatusSample* status) {
+                                    PolicyLoadStatusSampler* status) {
   RegistryDict parsed_policy;
   RegistryDict forced_policy;
-  for (GROUP_POLICY_OBJECT* policy_object = policy_object_list;
-       policy_object; policy_object = policy_object->pNext) {
+  for (GROUP_POLICY_OBJECT* policy_object = policy_object_list; policy_object;
+       policy_object = policy_object->pNext) {
     if (policy_object->dwOptions & GPO_FLAG_DISABLE)
       continue;
 
@@ -510,12 +506,12 @@
 
 bool PolicyLoaderWin::ReadPolicyFromGPO(PolicyScope scope,
                                         RegistryDict* policy,
-                                        PolicyLoadStatusSample* status) {
+                                        PolicyLoadStatusSampler* status) {
   PGROUP_POLICY_OBJECT policy_object_list = NULL;
   DWORD flags = scope == POLICY_SCOPE_MACHINE ? GPO_LIST_FLAG_MACHINE : 0;
-  if (gpo_provider_->GetAppliedGPOList(
-          flags, NULL, NULL, &kRegistrySettingsCSEGUID,
-          &policy_object_list) != ERROR_SUCCESS) {
+  if (gpo_provider_->GetAppliedGPOList(flags, NULL, NULL,
+                                       &kRegistrySettingsCSEGUID,
+                                       &policy_object_list) != ERROR_SUCCESS) {
     PLOG(ERROR) << "GetAppliedGPOList scope " << scope;
     status->Add(POLICY_LOAD_STATUS_QUERY_FAILED);
     return false;
@@ -553,7 +549,7 @@
     const char* name;
     PolicyDomain domain;
   } k3rdPartyDomains[] = {
-    { "extensions", POLICY_DOMAIN_EXTENSIONS },
+      {"extensions", POLICY_DOMAIN_EXTENSIONS},
   };
 
   // Policy level and corresponding path.
@@ -561,8 +557,8 @@
     PolicyLevel level;
     const char* path;
   } kLevels[] = {
-    { POLICY_LEVEL_MANDATORY,   kKeyMandatory   },
-    { POLICY_LEVEL_RECOMMENDED, kKeyRecommended },
+      {POLICY_LEVEL_MANDATORY, kKeyMandatory},
+      {POLICY_LEVEL_RECOMMENDED, kKeyRecommended},
   };
 
   for (size_t i = 0; i < arraysize(k3rdPartyDomains); i++) {
@@ -574,8 +570,7 @@
 
     for (RegistryDict::KeyMap::const_iterator component(
              domain_dict->keys().begin());
-         component != domain_dict->keys().end();
-         ++component) {
+         component != domain_dict->keys().end(); ++component) {
       const PolicyNamespace policy_namespace(domain, component->first);
 
       const Schema* schema_from_map = schema_map()->GetSchema(policy_namespace);
@@ -621,8 +616,8 @@
 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) {
   DCHECK(object == user_policy_changed_event_.handle() ||
          object == machine_policy_changed_event_.handle())
-      << "unexpected object signaled policy reload, obj = "
-      << std::showbase << std::hex << object;
+      << "unexpected object signaled policy reload, obj = " << std::showbase
+      << std::hex << object;
   Reload(false);
 }
 
diff --git a/components/policy/core/common/policy_loader_win.h b/components/policy/core/common/policy_loader_win.h
index c1195b1b..2b3b0a12 100644
--- a/components/policy/core/common/policy_loader_win.h
+++ b/components/policy/core/common/policy_loader_win.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_POLICY_CORE_COMMON_POLICY_LOADER_WIN_H_
 
 #include <windows.h>
+
 #include <userenv.h>
 
 #include <memory>
@@ -27,7 +28,7 @@
 namespace policy {
 
 class AppliedGPOListProvider;
-class PolicyLoadStatusSample;
+class PolicyLoadStatusSampler;
 class PolicyMap;
 class RegistryDict;
 
@@ -74,7 +75,7 @@
   // result in |policy|.
   bool ReadPRegFile(const base::FilePath& preg_file,
                     RegistryDict* policy,
-                    PolicyLoadStatusSample* status);
+                    PolicyLoadStatusSampler* status);
 
   // Loads and parses GPO policy in |policy_object_list| for scope |scope|. If
   // successful, stores the result in |policy| and returns true. Returns false
@@ -83,14 +84,14 @@
   bool LoadGPOPolicy(PolicyScope scope,
                      PGROUP_POLICY_OBJECT policy_object_list,
                      RegistryDict* policy,
-                     PolicyLoadStatusSample* status);
+                     PolicyLoadStatusSampler* status);
 
   // Queries Windows for applied group policy and writes the result to |policy|.
   // This is the preferred way to obtain GPO data, there are reports of abuse
   // of the registry GPO keys by 3rd-party software.
   bool ReadPolicyFromGPO(PolicyScope scope,
                          RegistryDict* policy,
-                         PolicyLoadStatusSample* status);
+                         PolicyLoadStatusSampler* status);
 
   // Parses Chrome policy from |gpo_dict| for the given |scope| and |level| and
   // merges it into |chrome_policy_map|.
diff --git a/components/policy/core/common/preg_parser.cc b/components/policy/core/common/preg_parser.cc
index 2dbe5fa..4514ef5 100644
--- a/components/policy/core/common/preg_parser.cc
+++ b/components/policy/core/common/preg_parser.cc
@@ -294,30 +294,24 @@
 bool ReadFile(const base::FilePath& file_path,
               const base::string16& root,
               RegistryDict* dict,
-              PolicyLoadStatusSample* status_sample) {
+              PolicyLoadStatusSampler* status) {
   base::MemoryMappedFile mapped_file;
   if (!mapped_file.Initialize(file_path) || !mapped_file.IsValid()) {
     PLOG(ERROR) << "Failed to map " << file_path.value();
-    status_sample->Add(POLICY_LOAD_STATUS_READ_ERROR);
+    status->Add(POLICY_LOAD_STATUS_READ_ERROR);
     return false;
   }
 
-  PolicyLoadStatus status = POLICY_LOAD_STATUS_SIZE;
-  bool res = ReadDataInternal(
-      mapped_file.data(), mapped_file.length(), root, dict, &status,
+  return ReadDataInternal(
+      mapped_file.data(), mapped_file.length(), root, dict, status,
       base::StringPrintf("file '%s'", file_path.value().c_str()));
-  if (!res) {
-    DCHECK(status != POLICY_LOAD_STATUS_SIZE);
-    status_sample->Add(status);
-  }
-  return res;
 }
 
 POLICY_EXPORT bool ReadDataInternal(const uint8_t* preg_data,
                                     size_t preg_data_size,
                                     const base::string16& root,
                                     RegistryDict* dict,
-                                    PolicyLoadStatus* status,
+                                    PolicyLoadStatusSampler* status,
                                     const std::string& debug_name) {
   DCHECK(status);
   DCHECK(root.empty() || root.back() != kRegistryPathSeparator[0]);
@@ -325,7 +319,7 @@
   // Check data size.
   if (preg_data_size > kMaxPRegFileSize) {
     LOG(ERROR) << "PReg " << debug_name << " too large: " << preg_data_size;
-    *status = POLICY_LOAD_STATUS_TOO_BIG;
+    status->Add(POLICY_LOAD_STATUS_TOO_BIG);
     return false;
   }
 
@@ -334,7 +328,7 @@
   if (!preg_data || preg_data_size < kHeaderSize ||
       memcmp(kPRegFileHeader, preg_data, kHeaderSize) != 0) {
     LOG(ERROR) << "Bad PReg " << debug_name;
-    *status = POLICY_LOAD_STATUS_PARSE_ERROR;
+    status->Add(POLICY_LOAD_STATUS_PARSE_ERROR);
     return false;
   }
 
@@ -398,7 +392,7 @@
 
   LOG(ERROR) << "Error parsing PReg " << debug_name << " at offset "
              << (reinterpret_cast<const uint8_t*>(cursor - 1) - preg_data);
-  *status = POLICY_LOAD_STATUS_PARSE_ERROR;
+  status->Add(POLICY_LOAD_STATUS_PARSE_ERROR);
   return false;
 }
 
diff --git a/components/policy/core/common/preg_parser.h b/components/policy/core/common/preg_parser.h
index bf0367ba8..cf9bb37 100644
--- a/components/policy/core/common/preg_parser.h
+++ b/components/policy/core/common/preg_parser.h
@@ -37,18 +37,17 @@
 POLICY_EXPORT bool ReadFile(const base::FilePath& file_path,
                             const base::string16& root,
                             RegistryDict* dict,
-                            PolicyLoadStatusSample* status_sample);
+                            PolicyLoadStatusSampler* status);
 
 // Similar to ReadFile, but reads from |preg_data| of length |preg_data_size|
-// instead of a file, and writes status to the enum PolicyLoadStatus, which does
-// not record UMA stats, unlike |PolicyLoadStatusSample|. |debug_name| is
-// printed out along with error messages. Used internally and for testing only.
-// All other callers should use ReadFile instead.
+// instead of a file. |debug_name| is printed out along with error messages.
+// Used internally and for testing only. All other callers should use ReadFile
+// instead.
 POLICY_EXPORT bool ReadDataInternal(const uint8_t* preg_data,
                                     size_t preg_data_size,
                                     const base::string16& root,
                                     RegistryDict* dict,
-                                    PolicyLoadStatus* status,
+                                    PolicyLoadStatusSampler* status,
                                     const std::string& debug_name);
 
 }  // namespace preg_parser
diff --git a/components/policy/core/common/preg_parser_fuzzer.cc b/components/policy/core/common/preg_parser_fuzzer.cc
index aff3544..003031f 100644
--- a/components/policy/core/common/preg_parser_fuzzer.cc
+++ b/components/policy/core/common/preg_parser_fuzzer.cc
@@ -34,8 +34,9 @@
 
 // Entry point for LibFuzzer.
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  // Note: Don't use PolicyLoadStatusUmaReporter here, it leaks!
+  PolicyLoadStatusSampler status;
   RegistryDict dict;
-  PolicyLoadStatus status;
   ReadDataInternal(data, size, env->root, &dict, &status, "data");
   return 0;
 }
diff --git a/components/policy/core/common/preg_parser_unittest.cc b/components/policy/core/common/preg_parser_unittest.cc
index d45a57b..e4716a1 100644
--- a/components/policy/core/common/preg_parser_unittest.cc
+++ b/components/policy/core/common/preg_parser_unittest.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/base_paths.h"
+#include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/json/json_writer.h"
 #include "base/logging.h"
@@ -26,6 +27,7 @@
 const char kRegistryPolBaseDir[] = "chrome/test/data/policy/gpo";
 const char kRegistryPolFile[] = "parser_test/registry.pol";
 const char kInvalidEncodingRegistryPolFile[] = "invalid_encoding/registry.pol";
+const char kNonExistingRegistryPolFile[] = "does_not_exist.pol";
 
 const char kRegistryKey[] = "SOFTWARE\\Policies\\Chromium";
 
@@ -116,7 +118,7 @@
 
   // Run the parser.
   base::FilePath test_file(test_data_dir_.AppendASCII(kRegistryPolFile));
-  PolicyLoadStatusSample status;
+  PolicyLoadStatusUmaReporter status;
   ASSERT_TRUE(preg_parser::ReadFile(test_file, base::ASCIIToUTF16(kRegistryKey),
                                     &dict, &status));
 
@@ -144,7 +146,7 @@
   // key like "Aa/Bb/C".
   base::FilePath test_file(test_data_dir_.AppendASCII(kRegistryPolFile));
   RegistryDict empty;
-  PolicyLoadStatusSample status;
+  PolicyLoadStatusUmaReporter status;
 
   // No data should be loaded for partial roots ("Aa/Bb/C").
   RegistryDict dict1;
@@ -164,7 +166,7 @@
   // Tests whether strings with invalid characters are rejected.
   base::FilePath test_file(
       test_data_dir_.AppendASCII(kInvalidEncodingRegistryPolFile));
-  PolicyLoadStatusSample status;
+  PolicyLoadStatusUmaReporter status;
   RegistryDict dict;
   ASSERT_TRUE(preg_parser::ReadFile(test_file, base::ASCIIToUTF16(kRegistryKey),
                                     &dict, &status));
@@ -173,6 +175,21 @@
   EXPECT_TRUE(RegistryDictEquals(dict, empty));
 }
 
+TEST_F(PRegParserTest, LoadStatusSampling) {
+  // Tests load status sampling.
+  PolicyLoadStatusUmaReporter status;
+  RegistryDict dict;
+  base::FilePath test_file(
+      test_data_dir_.AppendASCII(kNonExistingRegistryPolFile));
+  ASSERT_FALSE(preg_parser::ReadFile(
+      test_file, base::ASCIIToUTF16(kRegistryKey), &dict, &status));
+
+  PolicyLoadStatusSampler::StatusSet expected_status_set;
+  expected_status_set[POLICY_LOAD_STATUS_STARTED] = true;
+  expected_status_set[POLICY_LOAD_STATUS_READ_ERROR] = true;
+  EXPECT_EQ(expected_status_set, status.GetStatusSet());
+}
+
 }  // namespace
 }  // namespace preg_parser
 }  // namespace policy
diff --git a/components/signin/core/browser/signin_header_helper_unittest.cc b/components/signin/core/browser/signin_header_helper_unittest.cc
index 74e5a78..5141e3d 100644
--- a/components/signin/core/browser/signin_header_helper_unittest.cc
+++ b/components/signin/core/browser/signin_header_helper_unittest.cc
@@ -8,7 +8,7 @@
 #include "base/message_loop/message_loop.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/signin/core/browser/signin_header_helper.h"
-#include "components/signin/core/common/signin_switches.h"
+#include "components/signin/core/common/profile_management_switches.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/url_request_test_util.h"
@@ -71,8 +71,8 @@
 // Tests that no Mirror request is returned when the user is not signed in (no
 // account id).
 TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestNoAccountId) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableAccountConsistency);
+  switches::EnableAccountConsistencyForTesting(
+      base::CommandLine::ForCurrentProcess());
   CheckMirrorHeaderRequest(GURL("https://docs.google.com"), "", "");
   CheckMirrorCookieRequest(GURL("https://docs.google.com"), "", "");
 }
@@ -80,8 +80,8 @@
 // Tests that no Mirror request is returned when the cookies aren't allowed to
 // be set.
 TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestCookieSettingBlocked) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableAccountConsistency);
+  switches::EnableAccountConsistencyForTesting(
+      base::CommandLine::ForCurrentProcess());
   cookie_settings_->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK);
   CheckMirrorHeaderRequest(GURL("https://docs.google.com"), "0123456789", "");
   CheckMirrorCookieRequest(GURL("https://docs.google.com"), "0123456789", "");
@@ -89,8 +89,8 @@
 
 // Tests that no Mirror request is returned when the target is a non-Google URL.
 TEST_F(SigninHeaderHelperTest, TestNoMirrorRequestExternalURL) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableAccountConsistency);
+  switches::EnableAccountConsistencyForTesting(
+      base::CommandLine::ForCurrentProcess());
   CheckMirrorHeaderRequest(GURL("https://foo.com"), "0123456789", "");
   CheckMirrorCookieRequest(GURL("https://foo.com"), "0123456789", "");
 }
@@ -98,8 +98,8 @@
 // Tests that the Mirror request is returned without the GAIA Id when the target
 // is a google TLD domain.
 TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleTLD) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableAccountConsistency);
+  switches::EnableAccountConsistencyForTesting(
+      base::CommandLine::ForCurrentProcess());
   CheckMirrorHeaderRequest(GURL("https://google.fr"), "0123456789",
                            "mode=0,enable_account_consistency=true");
   CheckMirrorCookieRequest(GURL("https://google.de"), "0123456789",
@@ -109,8 +109,8 @@
 // Tests that the Mirror request is returned when the target is the domain
 // google.com, and that the GAIA Id is only attached for the cookie.
 TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleCom) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableAccountConsistency);
+  switches::EnableAccountConsistencyForTesting(
+      base::CommandLine::ForCurrentProcess());
   CheckMirrorHeaderRequest(GURL("https://www.google.com"), "0123456789",
                            "mode=0,enable_account_consistency=true");
   CheckMirrorCookieRequest(
@@ -125,8 +125,7 @@
 // only relevant on Desktop.
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
 TEST_F(SigninHeaderHelperTest, TestMirrorRequestDrive) {
-  DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kEnableAccountConsistency));
+  DCHECK(!switches::IsEnableAccountConsistency());
   CheckMirrorHeaderRequest(
       GURL("https://docs.google.com/document"), "0123456789",
       "id=0123456789,mode=0,enable_account_consistency=false");
@@ -135,8 +134,8 @@
       "id=0123456789:mode=0:enable_account_consistency=false");
 
   // Enable Account Consistency will override the disable.
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableAccountConsistency);
+  switches::EnableAccountConsistencyForTesting(
+      base::CommandLine::ForCurrentProcess());
   CheckMirrorHeaderRequest(
       GURL("https://docs.google.com/document"), "0123456789",
       "id=0123456789,mode=0,enable_account_consistency=true");
@@ -149,9 +148,8 @@
 // Tests that the Mirror header request is returned normally when the redirect
 // URL is eligible.
 TEST_F(SigninHeaderHelperTest, TestMirrorHeaderEligibleRedirectURL) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableAccountConsistency);
-
+  switches::EnableAccountConsistencyForTesting(
+      base::CommandLine::ForCurrentProcess());
   const GURL url("https://docs.google.com/document");
   const GURL redirect_url("https://www.google.com");
   const std::string account_id = "0123456789";
@@ -168,9 +166,8 @@
 // Tests that the Mirror header request is stripped when the redirect URL is not
 // eligible.
 TEST_F(SigninHeaderHelperTest, TestMirrorHeaderNonEligibleRedirectURL) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableAccountConsistency);
-
+  switches::EnableAccountConsistencyForTesting(
+      base::CommandLine::ForCurrentProcess());
   const GURL url("https://docs.google.com/document");
   const GURL redirect_url("http://www.foo.com");
   const std::string account_id = "0123456789";
@@ -187,9 +184,8 @@
 // Tests that the Mirror header, whatever its value is, is untouched when both
 // the current and the redirect URL are non-eligible.
 TEST_F(SigninHeaderHelperTest, TestIgnoreMirrorHeaderNonEligibleURLs) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableAccountConsistency);
-
+  switches::EnableAccountConsistencyForTesting(
+      base::CommandLine::ForCurrentProcess());
   const GURL url("https://www.bar.com");
   const GURL redirect_url("http://www.foo.com");
   const std::string account_id = "0123456789";
diff --git a/components/signin/core/common/profile_management_switches.cc b/components/signin/core/common/profile_management_switches.cc
index 733ea08..8ad5de6 100644
--- a/components/signin/core/common/profile_management_switches.cc
+++ b/components/signin/core/common/profile_management_switches.cc
@@ -18,10 +18,10 @@
 #if defined(OS_ANDROID) || defined(OS_IOS)
   // Account consistency is enabled on Android and iOS.
   return true;
-#endif
-
+#else
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kEnableAccountConsistency);
+#endif  // defined(OS_ANDROID) || defined(OS_IOS)
 }
 
 bool IsExtensionsMultiAccount() {
@@ -42,7 +42,9 @@
 }
 
 void EnableAccountConsistencyForTesting(base::CommandLine* command_line) {
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
   command_line->AppendSwitch(switches::kEnableAccountConsistency);
+#endif
 }
 
 }  // namespace switches
diff --git a/components/signin/core/common/signin_switches.cc b/components/signin/core/common/signin_switches.cc
index f31bc2c..8bd17cac 100644
--- a/components/signin/core/common/signin_switches.cc
+++ b/components/signin/core/common/signin_switches.cc
@@ -16,8 +16,10 @@
 // Disables sending signin scoped device id to LSO with refresh token request.
 const char kDisableSigninScopedDeviceId[] = "disable-signin-scoped-device-id";
 
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
 // Enables consistent identity features.
 const char kEnableAccountConsistency[] = "enable-account-consistency";
+#endif
 
 // Enables sending EnableRefreshTokenAnnotationRequest.
 extern const char kEnableRefreshTokenAnnotationRequest[] =
diff --git a/components/signin/core/common/signin_switches.h b/components/signin/core/common/signin_switches.h
index c2dd7384..d837505 100644
--- a/components/signin/core/common/signin_switches.h
+++ b/components/signin/core/common/signin_switches.h
@@ -18,13 +18,18 @@
 extern const char kClearTokenService[];
 extern const char kDisableSigninPromo[];
 extern const char kDisableSigninScopedDeviceId[];
-extern const char kEnableAccountConsistency[];
 extern const char kEnableRefreshTokenAnnotationRequest[];
 extern const char kEnableSigninPromo[];
 extern const char kExtensionsMultiAccount[];
 
 extern const base::Feature kUsePasswordSeparatedSigninFlow;
 
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+// Note: Account consistency is already enabled on mobile platforms, so this
+// switch only exist on desktop platforms.
+extern const char kEnableAccountConsistency[];
+#endif
+
 }  // namespace switches
 
 #endif  // COMPONENTS_SIGNIN_CORE_COMMON_SIGNIN_SWITCHES_H_
diff --git a/components/subresource_filter/core/common/BUILD.gn b/components/subresource_filter/core/common/BUILD.gn
index 6c1ce856..a65b2292 100644
--- a/components/subresource_filter/core/common/BUILD.gn
+++ b/components/subresource_filter/core/common/BUILD.gn
@@ -83,6 +83,7 @@
     "scoped_timers_unittest.cc",
     "string_splitter_unittest.cc",
     "unindexed_ruleset_unittest.cc",
+    "url_pattern_index_unittest.cc",
     "url_pattern_unittest.cc",
   ]
   deps = [
diff --git a/components/subresource_filter/core/common/indexed_ruleset_unittest.cc b/components/subresource_filter/core/common/indexed_ruleset_unittest.cc
index 41778883..bf94498f 100644
--- a/components/subresource_filter/core/common/indexed_ruleset_unittest.cc
+++ b/components/subresource_filter/core/common/indexed_ruleset_unittest.cc
@@ -5,8 +5,6 @@
 #include "components/subresource_filter/core/common/indexed_ruleset.h"
 
 #include <memory>
-#include <string>
-#include <vector>
 
 #include "base/logging.h"
 #include "base/macros.h"
@@ -63,7 +61,7 @@
 
   bool AddSimpleWhitelistRule(base::StringPiece url_pattern,
                               int32_t activation_types) {
-    auto rule = MakeUrlRule(url_pattern);
+    auto rule = MakeUrlRule(UrlPattern(url_pattern, kSubstring));
     rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
     rule.clear_element_types();
     rule.set_activation_types(activation_types);
@@ -88,509 +86,6 @@
   DISALLOW_COPY_AND_ASSIGN(SubresourceFilterIndexedRulesetTest);
 };
 
-TEST_F(SubresourceFilterIndexedRulesetTest, OneRuleWithoutMetaInfo) {
-  const struct {
-    UrlPattern url_pattern;
-    const char* url;
-    bool expect_allowed;
-  } kTestCases[] = {
-      // SUBSTRING
-      {{"abcd", kSubstring}, "http://ex.com/abcd", false},
-      {{"abcd", kSubstring}, "http://ex.com/dcab", true},
-      {{"42", kSubstring}, "http://ex.com/adcd/picture42.png", false},
-      {{"&test", kSubstring},
-       "http://ex.com/params?para1=false&test=true",
-       false},
-      {{"-test-42.", kSubstring}, "http://ex.com/unit-test-42.1", false},
-      {{"/abcdtest160x600.", kSubstring},
-       "http://ex.com/abcdtest160x600.png",
-       false},
-
-      // WILDCARDED
-      {{"http://ex.com/abcd/picture*.png"},
-       "http://ex.com/abcd/picture42.png",
-       false},
-      {{"ex.com", kSubdomain, kAnchorNone}, "http://ex.com", false},
-      {{"ex.com", kSubdomain, kAnchorNone}, "http://test.ex.com", false},
-      {{"ex.com", kSubdomain, kAnchorNone}, "https://test.ex.com.com", false},
-      {{"ex.com", kSubdomain, kAnchorNone}, "https://test.rest.ex.com", false},
-      {{"ex.com", kSubdomain, kAnchorNone}, "https://test_ex.com", true},
-
-      {{"http://ex.com", kBoundary, kAnchorNone}, "http://ex.com/", false},
-      {{"http://ex.com", kBoundary, kAnchorNone}, "http://ex.com/42", false},
-      {{"http://ex.com", kBoundary, kAnchorNone},
-       "http://ex.com/42/http://ex.com/",
-       false},
-      {{"http://ex.com", kBoundary, kAnchorNone},
-       "http://ex.com/42/http://ex.info/",
-       false},
-      {{"http://ex.com/", kBoundary, kBoundary}, "http://ex.com", false},
-      {{"http://ex.com/", kBoundary, kBoundary}, "http://ex.com/42", true},
-      {{"http://ex.com/", kBoundary, kBoundary},
-       "http://ex.info/42/http://ex.com/",
-       true},
-      {{"http://ex.com/", kBoundary, kBoundary},
-       "http://ex.info/42/http://ex.com/",
-       true},
-      {{"http://ex.com/", kBoundary, kBoundary}, "http://ex.com/", false},
-      {{"http://ex.com/", kBoundary, kBoundary}, "http://ex.com/42.swf", true},
-      {{"http://ex.com/", kBoundary, kBoundary},
-       "http://ex.info/redirect/http://ex.com/",
-       true},
-      {{"pdf", kAnchorNone, kBoundary}, "http://ex.com/abcd.pdf", false},
-      {{"pdf", kAnchorNone, kBoundary}, "http://ex.com/pdfium", true},
-      {{"http://ex.com^"}, "http://ex.com/", false},
-      {{"http://ex.com^"}, "http://ex.com:8000/", false},
-      {{"http://ex.com^"}, "http://ex.com.ru", true},
-      {{"^ex.com^"},
-       "http://ex.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82",
-       false},
-      {{"^42.loss^"},
-       "http://ex.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82",
-       false},
-
-      // TODO(pkalinnikov): The '^' at the end should match end-of-string.
-      //
-      // {"^%D1%82%D0%B5%D1%81%D1%82^",
-      //  "http://ex.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82",
-      //  false},
-      // {"/abcd/*/picture^", "http://ex.com/abcd/42/picture", false},
-
-      {{"/abcd/*/picture^"}, "http://ex.com/abcd/42/loss/picture?param", false},
-      {{"/abcd/*/picture^"}, "http://ex.com/abcd//picture/42", false},
-      {{"/abcd/*/picture^"}, "http://ex.com/abcd/picture", true},
-      {{"/abcd/*/picture^"}, "http://ex.com/abcd/42/pictureraph", true},
-      {{"/abcd/*/picture^"}, "http://ex.com/abcd/42/picture.swf", true},
-      {{"test.ex.com^", kSubdomain, kAnchorNone},
-       "http://test.ex.com/42.swf",
-       false},
-      {{"test.ex.com^", kSubdomain, kAnchorNone},
-       "http://server1.test.ex.com/42.swf",
-       false},
-      {{"test.ex.com^", kSubdomain, kAnchorNone},
-       "https://test.ex.com:8000/",
-       false},
-      {{"test.ex.com^", kSubdomain, kAnchorNone},
-       "http://test.ex.com.ua/42.swf",
-       true},
-      {{"test.ex.com^", kSubdomain, kAnchorNone},
-       "http://ex.com/redirect/http://test.ex.com/",
-       true},
-
-      {{"/abcd/*"}, "https://ex.com/abcd/", false},
-      {{"/abcd/*"}, "http://ex.com/abcd/picture.jpeg", false},
-      {{"/abcd/*"}, "https://ex.com/abcd", true},
-      {{"/abcd/*"}, "http://abcd.ex.com", true},
-      {{"*/abcd/"}, "https://ex.com/abcd/", false},
-      {{"*/abcd/"}, "http://ex.com/abcd/picture.jpeg", false},
-      {{"*/abcd/"}, "https://ex.com/test-abcd/", true},
-      {{"*/abcd/"}, "http://abcd.ex.com", true},
-  };
-
-  for (const auto& test_case : kTestCases) {
-    SCOPED_TRACE(::testing::Message() << "UrlPattern: " << test_case.url_pattern
-                                      << "; URL: " << test_case.url);
-
-    ASSERT_TRUE(AddUrlRule(MakeUrlRule(test_case.url_pattern)));
-    Finish();
-
-    EXPECT_EQ(test_case.expect_allowed, ShouldAllow(test_case.url));
-    Reset();
-  }
-}
-
-TEST_F(SubresourceFilterIndexedRulesetTest, OneRuleWithThirdParty) {
-  const struct {
-    const char* url_pattern;
-    proto::SourceType source_type;
-
-    const char* url;
-    const char* document_origin;
-    bool expect_allowed;
-  } kTestCases[] = {
-      {"ex.com", kThirdParty, "http://ex.com", "http://exmpl.org", false},
-      {"ex.com", kThirdParty, "http://ex.com", "http://ex.com", true},
-      {"ex.com", kThirdParty, "http://ex.com/path?k=v", "http://exmpl.org",
-       false},
-      {"ex.com", kThirdParty, "http://ex.com/path?k=v", "http://ex.com", true},
-      {"ex.com", kFirstParty, "http://ex.com/path?k=v", "http://ex.com", false},
-      {"ex.com", kFirstParty, "http://ex.com/path?k=v", "http://exmpl.com",
-       true},
-      {"ex.com", kAnyParty, "http://ex.com/path?k=v", "http://ex.com", false},
-      {"ex.com", kAnyParty, "http://ex.com/path?k=v", "http://exmpl.com",
-       false},
-      {"ex.com", kThirdParty, "http://subdomain.ex.com", "http://ex.com", true},
-      {"ex.com", kThirdParty, "http://ex.com", nullptr, false},
-
-      // Public Suffix List tests.
-      {"ex.com", kThirdParty, "http://two.ex.com", "http://one.ex.com", true},
-      {"ex.com", kThirdParty, "http://ex.com", "http://one.ex.com", true},
-      {"ex.com", kThirdParty, "http://two.ex.com", "http://ex.com", true},
-      {"ex.com", kThirdParty, "http://ex.com", "http://ex.org", false},
-      {"appspot.com", kThirdParty, "http://two.appspot.org",
-       "http://one.appspot.com", true},
-  };
-
-  for (auto test_case : kTestCases) {
-    SCOPED_TRACE(::testing::Message()
-                 << "UrlPattern: " << test_case.url_pattern
-                 << "; SourceType: " << static_cast<int>(test_case.source_type)
-                 << "; URL: " << test_case.url
-                 << "; DocumentOrigin: " << test_case.document_origin);
-
-    auto rule = MakeUrlRule(UrlPattern(test_case.url_pattern, kSubstring));
-    rule.set_source_type(test_case.source_type);
-    ASSERT_TRUE(AddUrlRule(rule));
-    Finish();
-
-    EXPECT_EQ(test_case.expect_allowed,
-              ShouldAllow(test_case.url, test_case.document_origin));
-    Reset();
-  }
-}
-
-TEST_F(SubresourceFilterIndexedRulesetTest, OneRuleWithDomainList) {
-  constexpr const char* kUrl = "http://example.com";
-
-  const struct {
-    std::vector<std::string> domains;
-    const char* document_origin;
-    bool expect_allowed;
-  } kTestCases[] = {
-      {std::vector<std::string>(), nullptr, false},
-      {std::vector<std::string>(), "http://domain.com", false},
-
-      {{"domain.com"}, nullptr, true},
-      {{"domain.com"}, "http://domain.com", false},
-      {{"ddomain.com"}, "http://domain.com", true},
-      {{"domain.com"}, "http://ddomain.com", true},
-      {{"domain.com"}, "http://sub.domain.com", false},
-      {{"sub.domain.com"}, "http://domain.com", true},
-      {{"sub.domain.com"}, "http://sub.domain.com", false},
-      {{"sub.domain.com"}, "http://a.b.c.sub.domain.com", false},
-      {{"sub.domain.com"}, "http://sub.domain.com.com", true},
-
-      // TODO(pkalinnikov): Probably need to canonicalize domain patterns to
-      // avoid subtleties like below.
-      {{"domain.com"}, "http://domain.com.", false},
-      {{"domain.com"}, "http://.domain.com", false},
-      {{"domain.com"}, "http://.domain.com.", false},
-      {{".domain.com"}, "http://.domain.com", false},
-      {{"domain.com."}, "http://domain.com", true},
-      {{"domain.com."}, "http://domain.com.", false},
-
-      {{"domain..com"}, "http://domain.com", true},
-      {{"domain.com"}, "http://domain..com", true},
-      {{"domain..com"}, "http://domain..com", false},
-
-      {{"~domain.com"}, nullptr, false},
-      {{"~domain.com"}, "http://domain.com", true},
-      {{"~ddomain.com"}, "http://domain.com", false},
-      {{"~domain.com"}, "http://ddomain.com", false},
-      {{"~domain.com"}, "http://sub.domain.com", true},
-      {{"~sub.domain.com"}, "http://domain.com", false},
-      {{"~sub.domain.com"}, "http://sub.domain.com", true},
-      {{"~sub.domain.com"}, "http://a.b.c.sub.domain.com", true},
-      {{"~sub.domain.com"}, "http://sub.domain.com.com", false},
-
-      {{"domain1.com", "domain2.com"}, nullptr, true},
-      {{"domain1.com", "domain2.com"}, "http://domain1.com", false},
-      {{"domain1.com", "domain2.com"}, "http://domain2.com", false},
-      {{"domain1.com", "domain2.com"}, "http://domain3.com", true},
-      {{"domain1.com", "domain2.com"}, "http://not_domain1.com", true},
-      {{"domain1.com", "domain2.com"}, "http://sub.domain1.com", false},
-      {{"domain1.com", "domain2.com"}, "http://a.b.c.sub.domain2.com", false},
-
-      {{"~domain1.com", "~domain2.com"}, "http://domain1.com", true},
-      {{"~domain1.com", "~domain2.com"}, "http://domain2.com", true},
-      {{"~domain1.com", "~domain2.com"}, "http://domain3.com", false},
-
-      {{"domain.com", "~sub.domain.com"}, "http://domain.com", false},
-      {{"domain.com", "~sub.domain.com"}, "http://sub.domain.com", true},
-      {{"domain.com", "~sub.domain.com"}, "http://a.b.sub.domain.com", true},
-      {{"domain.com", "~sub.domain.com"}, "http://ssub.domain.com", false},
-
-      {{"domain.com", "~a.domain.com", "~b.domain.com"},
-       "http://domain.com",
-       false},
-      {{"domain.com", "~a.domain.com", "~b.domain.com"},
-       "http://a.domain.com",
-       true},
-      {{"domain.com", "~a.domain.com", "~b.domain.com"},
-       "http://b.domain.com",
-       true},
-
-      {{"domain.com", "~a.domain.com", "b.a.domain.com"},
-       "http://domain.com",
-       false},
-      {{"domain.com", "~a.domain.com", "b.a.domain.com"},
-       "http://a.domain.com",
-       true},
-      {{"domain.com", "~a.domain.com", "b.a.domain.com"},
-       "http://b.a.domain.com",
-       false},
-      {{"domain.com", "~a.domain.com", "b.a.domain.com"},
-       "http://c.b.a.domain.com",
-       false},
-
-      // The following test addresses a former bug in domain list matcher. When
-      // "domain.com" was matched, the positive filters lookup stopped, and the
-      // next domain was considered as a negative. The initial character was
-      // skipped (supposing it's a '~') and the remainder was considered a
-      // domain. So "ddomain.com" would be matched and thus the whole rule would
-      // be classified as non-matching, which is not correct.
-      {{"domain.com", "ddomain.com", "~sub.domain.com"},
-       "http://domain.com",
-       false},
-  };
-
-  for (const auto& test_case : kTestCases) {
-    SCOPED_TRACE(::testing::Message()
-                 << "Domains: " << ::testing::PrintToString(test_case.domains)
-                 << "; DocumentOrigin: " << test_case.document_origin);
-
-    auto rule = MakeUrlRule(UrlPattern(kUrl, kSubstring));
-    AddDomains(test_case.domains, &rule);
-    ASSERT_TRUE(AddUrlRule(rule));
-    Finish();
-
-    EXPECT_EQ(test_case.expect_allowed,
-              ShouldAllow(kUrl, test_case.document_origin));
-    Reset();
-  }
-}
-
-TEST_F(SubresourceFilterIndexedRulesetTest, OneRuleWithLongDomainList) {
-  constexpr const char* kUrl = "http://example.com";
-  constexpr size_t kDomains = 200;
-
-  std::vector<std::string> domains;
-  for (size_t i = 0; i < kDomains; ++i) {
-    const std::string domain = "domain" + std::to_string(i) + ".com";
-    domains.push_back(domain);
-    domains.push_back("~sub." + domain);
-    domains.push_back("a.sub." + domain);
-    domains.push_back("b.sub." + domain);
-    domains.push_back("c.sub." + domain);
-    domains.push_back("~aa.sub." + domain);
-    domains.push_back("~ab.sub." + domain);
-    domains.push_back("~ba.sub." + domain);
-    domains.push_back("~bb.sub." + domain);
-    domains.push_back("~sub.sub.c.sub." + domain);
-  }
-
-  auto rule = MakeUrlRule(UrlPattern(kUrl, kSubstring));
-  AddDomains(domains, &rule);
-  ASSERT_TRUE(AddUrlRule(rule));
-  Finish();
-
-  for (size_t i = 0; i < kDomains; ++i) {
-    SCOPED_TRACE(::testing::Message() << "Iteration: " << i);
-    const std::string domain = "domain" + std::to_string(i) + ".com";
-
-    EXPECT_FALSE(ShouldAllow(kUrl, "http://" + domain));
-    EXPECT_TRUE(ShouldAllow(kUrl, "http://sub." + domain));
-    EXPECT_FALSE(ShouldAllow(kUrl, "http://a.sub." + domain));
-    EXPECT_FALSE(ShouldAllow(kUrl, "http://b.sub." + domain));
-    EXPECT_FALSE(ShouldAllow(kUrl, "http://c.sub." + domain));
-    EXPECT_TRUE(ShouldAllow(kUrl, "http://aa.sub." + domain));
-    EXPECT_TRUE(ShouldAllow(kUrl, "http://ab.sub." + domain));
-    EXPECT_TRUE(ShouldAllow(kUrl, "http://ba.sub." + domain));
-    EXPECT_TRUE(ShouldAllow(kUrl, "http://bb.sub." + domain));
-    EXPECT_FALSE(ShouldAllow(kUrl, "http://sub.c.sub." + domain));
-    EXPECT_TRUE(ShouldAllow(kUrl, "http://sub.sub.c.sub." + domain));
-  }
-}
-
-TEST_F(SubresourceFilterIndexedRulesetTest, OneRuleWithElementTypes) {
-  constexpr auto kAll = kAllElementTypes;
-  const struct {
-    const char* url_pattern;
-    int32_t element_types;
-
-    const char* url;
-    proto::ElementType element_type;
-    bool expect_allowed;
-  } kTestCases[] = {
-      {"ex.com", kAll, "http://ex.com/img.jpg", kImage, false},
-      {"ex.com", kAll & ~kPopup, "http://ex.com/img", kPopup, true},
-
-      {"ex.com", kImage, "http://ex.com/img.jpg", kImage, false},
-      {"ex.com", kAll & ~kImage, "http://ex.com/img.jpg", kImage, true},
-      {"ex.com", kScript, "http://ex.com/img.jpg", kImage, true},
-      {"ex.com", kAll & ~kScript, "http://ex.com/img.jpg", kImage, false},
-
-      {"ex.com", kImage | kFont, "http://ex.com/font", kFont, false},
-      {"ex.com", kImage | kFont, "http://ex.com/image", kImage, false},
-      {"ex.com", kImage | kFont, "http://ex.com/video",
-       proto::ELEMENT_TYPE_MEDIA, true},
-      {"ex.com", kAll & ~kFont & ~kScript, "http://ex.com/font", kFont, true},
-      {"ex.com", kAll & ~kFont & ~kScript, "http://ex.com/scr", kScript, true},
-      {"ex.com", kAll & ~kFont & ~kScript, "http://ex.com/img", kImage, false},
-
-      {"ex.com", kAll, "http://ex.com", proto::ELEMENT_TYPE_OTHER, false},
-      {"ex.com", kAll, "http://ex.com", proto::ELEMENT_TYPE_UNSPECIFIED, true},
-      {"ex.com", kWebSocket, "ws://ex.com", proto::ELEMENT_TYPE_WEBSOCKET,
-       false},
-  };
-
-  for (const auto& test_case : kTestCases) {
-    SCOPED_TRACE(
-        ::testing::Message()
-        << "UrlPattern: " << test_case.url_pattern
-        << "; ElementTypes: " << static_cast<int>(test_case.element_types)
-        << "; URL: " << test_case.url
-        << "; ElementType: " << static_cast<int>(test_case.element_type));
-
-    auto rule = MakeUrlRule(UrlPattern(test_case.url_pattern, kSubstring));
-    rule.set_element_types(test_case.element_types);
-    ASSERT_TRUE(AddUrlRule(rule));
-    Finish();
-
-    EXPECT_EQ(test_case.expect_allowed,
-              ShouldAllow(test_case.url, nullptr /* document_origin */,
-                          test_case.element_type));
-    Reset();
-  }
-}
-
-TEST_F(SubresourceFilterIndexedRulesetTest, OneRuleWithActivationTypes) {
-  constexpr proto::ActivationType kNone = proto::ACTIVATION_TYPE_UNSPECIFIED;
-
-  const struct {
-    const char* url_pattern;
-    int32_t activation_types;
-
-    const char* document_url;
-    proto::ActivationType activation_type;
-    bool expect_disabled;
-  } kTestCases[] = {
-      {"example.com", kDocument, "http://example.com", kDocument, true},
-      {"xample.com", kDocument, "http://example.com", kDocument, true},
-      {"exampl.com", kDocument, "http://example.com", kDocument, false},
-
-      {"example.com", kGenericBlock, "http://example.com", kDocument, false},
-      {"example.com", kDocument, "http://example.com", kNone, false},
-      {"example.com", kGenericBlock, "http://example.com", kNone, false},
-
-      // Invalid GURL.
-      {"example.com", kDocument, "http;//example.com", kDocument, false},
-  };
-
-  for (const auto& test_case : kTestCases) {
-    SCOPED_TRACE(
-        ::testing::Message()
-        << "UrlPattern: " << test_case.url_pattern
-        << "; ActivationTypes: " << static_cast<int>(test_case.activation_types)
-        << "; DocumentURL: " << test_case.document_url
-        << "; ActivationType: " << static_cast<int>(test_case.activation_type));
-
-    ASSERT_TRUE(AddSimpleWhitelistRule(test_case.url_pattern,
-                                       test_case.activation_types));
-    Finish();
-
-    EXPECT_EQ(test_case.expect_disabled,
-              ShouldDeactivate(test_case.document_url,
-                               nullptr /* parent_document_origin */,
-                               test_case.activation_type));
-    EXPECT_EQ(test_case.expect_disabled,
-              ShouldDeactivate(test_case.document_url, "http://example.com/",
-                               test_case.activation_type));
-    EXPECT_EQ(test_case.expect_disabled,
-              ShouldDeactivate(test_case.document_url, "http://xmpl.com/",
-                               test_case.activation_type));
-    Reset();
-  }
-}
-
-TEST_F(SubresourceFilterIndexedRulesetTest, RuleWithElementAndActivationTypes) {
-  auto rule = MakeUrlRule(UrlPattern("allow.ex.com", kSubstring));
-  rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
-  rule.set_activation_types(kDocument);
-
-  ASSERT_TRUE(AddUrlRule(rule));
-  ASSERT_TRUE(AddSimpleRule("ex.com"));
-  Finish();
-
-  EXPECT_FALSE(ShouldAllow("http://ex.com"));
-  EXPECT_TRUE(ShouldAllow("http://allow.ex.com"));
-  EXPECT_FALSE(ShouldDeactivate("http://allow.ex.com",
-                                nullptr /* parent_document_origin */,
-                                kGenericBlock));
-  EXPECT_TRUE(ShouldDeactivate(
-      "http://allow.ex.com", nullptr /* parent_document_origin */, kDocument));
-}
-
-TEST_F(SubresourceFilterIndexedRulesetTest, MatchWithDisableGenericRules) {
-  const struct {
-    const char* url_pattern;
-    std::vector<std::string> domains;
-  } kRules[] = {
-      // Generic rules.
-      {"some_text", std::vector<std::string>()},
-      {"another_text", {"~example.com"}},
-      {"final_text", {"~example1.com", "~example2.com"}},
-      // Domain specific rules.
-      {"some_text", {"example1.com"}},
-      {"more_text", {"example.com", "~exclude.example.com"}},
-      {"last_text", {"example1.com", "sub.example2.com"}},
-  };
-
-  for (const auto& rule_data : kRules) {
-    auto rule = MakeUrlRule(UrlPattern(rule_data.url_pattern, kSubstring));
-    AddDomains(rule_data.domains, &rule);
-    ASSERT_TRUE(AddUrlRule(rule))
-        << "UrlPattern: " << rule_data.url_pattern
-        << "; Domains: " << ::testing::PrintToString(rule_data.domains);
-  }
-
-  // Note: Some of the rules have common domains (e.g., example1.com), which are
-  // ultimately shared by FlatBuffers' CreateSharedString. The test also makes
-  // sure that the data structure works properly with such optimization.
-  Finish();
-
-  const struct {
-    const char* url;
-    const char* document_origin;
-    bool should_allow_with_disable_generic_rules;
-    bool should_allow_with_enable_all_rules;
-  } kTestCases[] = {
-      {"http://ex.com/some_text", "http://example.com", true, false},
-      {"http://ex.com/some_text", "http://example1.com", false, false},
-
-      {"http://ex.com/another_text", "http://example.com", true, true},
-      {"http://ex.com/another_text", "http://example1.com", true, false},
-
-      {"http://ex.com/final_text", "http://example.com", true, false},
-      {"http://ex.com/final_text", "http://example1.com", true, true},
-      {"http://ex.com/final_text", "http://example2.com", true, true},
-
-      {"http://ex.com/more_text", "http://example.com", false, false},
-      {"http://ex.com/more_text", "http://exclude.example.com", true, true},
-      {"http://ex.com/more_text", "http://example1.com", true, true},
-
-      {"http://ex.com/last_text", "http://example.com", true, true},
-      {"http://ex.com/last_text", "http://example1.com", false, false},
-      {"http://ex.com/last_text", "http://example2.com", true, true},
-      {"http://ex.com/last_text", "http://sub.example2.com", false, false},
-  };
-
-  constexpr bool kDisableGenericRules = true;
-  constexpr bool kEnableAllRules = false;
-  for (const auto& test_case : kTestCases) {
-    SCOPED_TRACE(::testing::Message()
-                 << "URL: " << test_case.url
-                 << "; DocumentOrigin: " << test_case.document_origin);
-
-    EXPECT_EQ(test_case.should_allow_with_disable_generic_rules,
-              ShouldAllow(test_case.url, test_case.document_origin, kOther,
-                          kDisableGenericRules));
-    EXPECT_EQ(test_case.should_allow_with_enable_all_rules,
-              ShouldAllow(test_case.url, test_case.document_origin, kOther,
-                          kEnableAllRules));
-  }
-}
-
 TEST_F(SubresourceFilterIndexedRulesetTest, EmptyRuleset) {
   Finish();
   EXPECT_TRUE(ShouldAllow(nullptr));
@@ -632,7 +127,8 @@
   EXPECT_TRUE(ShouldAllow("https://notblacklisted.com"));
 }
 
-TEST_F(SubresourceFilterIndexedRulesetTest, BlacklistAndActivationType) {
+TEST_F(SubresourceFilterIndexedRulesetTest,
+       OneBlacklistAndOneDeactivationRule) {
   ASSERT_TRUE(AddSimpleRule("example.com"));
   ASSERT_TRUE(AddSimpleWhitelistRule("example.com", kDocument));
   Finish();
@@ -643,69 +139,4 @@
   EXPECT_TRUE(ShouldAllow("https://xample.com"));
 }
 
-TEST_F(SubresourceFilterIndexedRulesetTest, RulesWithUnsupportedTypes) {
-  const struct {
-    int element_types;
-    int activation_types;
-  } kRules[] = {
-      {proto::ELEMENT_TYPE_MAX << 1, 0},
-      {0, proto::ACTIVATION_TYPE_MAX << 1},
-      {proto::ELEMENT_TYPE_MAX << 1, proto::ACTIVATION_TYPE_MAX << 1},
-
-      {kPopup, 0},
-      {0, proto::ACTIVATION_TYPE_ELEMHIDE},
-      {0, proto::ACTIVATION_TYPE_GENERICHIDE},
-      {0, proto::ACTIVATION_TYPE_ELEMHIDE | proto::ACTIVATION_TYPE_GENERICHIDE},
-      {proto::ELEMENT_TYPE_POPUP, proto::ACTIVATION_TYPE_ELEMHIDE},
-  };
-
-  for (const auto& rule_data : kRules) {
-    auto rule = MakeUrlRule(UrlPattern("example.com", kSubstring));
-    rule.set_element_types(rule_data.element_types);
-    rule.set_activation_types(rule_data.activation_types);
-    EXPECT_FALSE(AddUrlRule(rule))
-        << "ElementTypes: " << static_cast<int>(rule_data.element_types)
-        << "; ActivationTypes: "
-        << static_cast<int>(rule_data.activation_types);
-  }
-  ASSERT_TRUE(AddSimpleRule("exmpl.com"));
-  Finish();
-
-  EXPECT_TRUE(ShouldAllow("http://example.com/"));
-  EXPECT_FALSE(ShouldAllow("https://exmpl.com/"));
-}
-
-TEST_F(SubresourceFilterIndexedRulesetTest,
-       RulesWithSupportedAndUnsupportedTypes) {
-  const struct {
-    int element_types;
-    int activation_types;
-  } kRules[] = {
-      {kImage | (proto::ELEMENT_TYPE_MAX << 1), 0},
-      {kScript | kPopup, 0},
-      {0, kDocument | (proto::ACTIVATION_TYPE_MAX << 1)},
-  };
-
-  for (const auto& rule_data : kRules) {
-    auto rule = MakeUrlRule(UrlPattern("example.com", kSubstring));
-    rule.set_element_types(rule_data.element_types);
-    rule.set_activation_types(rule_data.activation_types);
-    if (rule_data.activation_types)
-      rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
-    EXPECT_TRUE(AddUrlRule(rule))
-        << "ElementTypes: " << static_cast<int>(rule_data.element_types)
-        << "; ActivationTypes: "
-        << static_cast<int>(rule_data.activation_types);
-  }
-  Finish();
-
-  EXPECT_FALSE(ShouldAllow("http://example.com/", nullptr, kImage));
-  EXPECT_FALSE(ShouldAllow("http://example.com/", nullptr, kScript));
-  EXPECT_TRUE(ShouldAllow("http://example.com/", nullptr, kPopup));
-  EXPECT_TRUE(ShouldAllow("http://example.com/"));
-
-  EXPECT_TRUE(ShouldDeactivate("http://example.com", nullptr, kDocument));
-  EXPECT_FALSE(ShouldDeactivate("http://example.com", nullptr, kGenericBlock));
-}
-
 }  // namespace subresource_filter
diff --git a/components/subresource_filter/core/common/url_pattern_index.cc b/components/subresource_filter/core/common/url_pattern_index.cc
index 49c3cb9..574f577 100644
--- a/components/subresource_filter/core/common/url_pattern_index.cc
+++ b/components/subresource_filter/core/common/url_pattern_index.cc
@@ -10,6 +10,7 @@
 
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "components/subresource_filter/core/common/ngram_extractor.h"
 #include "components/subresource_filter/core/common/url_pattern.h"
diff --git a/components/subresource_filter/core/common/url_pattern_index.h b/components/subresource_filter/core/common/url_pattern_index.h
index adeade6..30224dce 100644
--- a/components/subresource_filter/core/common/url_pattern_index.h
+++ b/components/subresource_filter/core/common/url_pattern_index.h
@@ -11,7 +11,7 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "base/strings/string_piece.h"
+#include "base/strings/string_piece_forward.h"
 #include "components/subresource_filter/core/common/closed_hash_map.h"
 #include "components/subresource_filter/core/common/flat/url_pattern_index_generated.h"
 #include "components/subresource_filter/core/common/proto/rules.pb.h"
diff --git a/components/subresource_filter/core/common/url_pattern_index_unittest.cc b/components/subresource_filter/core/common/url_pattern_index_unittest.cc
new file mode 100644
index 0000000..1052d5ba
--- /dev/null
+++ b/components/subresource_filter/core/common/url_pattern_index_unittest.cc
@@ -0,0 +1,668 @@
+// 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 "components/subresource_filter/core/common/url_pattern_index.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "components/subresource_filter/core/common/url_pattern.h"
+#include "components/subresource_filter/core/common/url_rule_test_support.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace subresource_filter {
+
+using namespace testing;
+
+class UrlPatternIndexTest : public ::testing::Test {
+ public:
+  UrlPatternIndexTest() { Reset(); }
+
+ protected:
+  bool AddUrlRule(const proto::UrlRule& rule) {
+    auto offset = SerializeUrlRule(rule, flat_builder_.get());
+    if (offset.o)
+      index_builder_->IndexUrlRule(offset);
+    return !!offset.o;
+  }
+
+  void Finish() {
+    const auto index_offset = index_builder_->Finish();
+    flat_builder_->Finish(index_offset);
+
+    const flat::UrlPatternIndex* flat_index =
+        flat::GetUrlPatternIndex(flat_builder_->GetBufferPointer());
+    index_matcher_.reset(new UrlPatternIndexMatcher(flat_index));
+  }
+
+  const flat::UrlRule* FindMatch(
+      base::StringPiece url_string,
+      base::StringPiece document_origin_string = base::StringPiece(),
+      proto::ElementType element_type = kOther,
+      proto::ActivationType activation_type = kNoActivation,
+      bool disable_generic_rules = false) {
+    const GURL url(url_string);
+    const url::Origin document_origin = GetOrigin(document_origin_string);
+    return index_matcher_->FindMatch(
+        url, document_origin, element_type, activation_type,
+        IsThirdParty(url, document_origin), disable_generic_rules);
+  }
+
+  void Reset() {
+    index_matcher_.reset();
+    index_builder_.reset();
+    flat_builder_.reset(new flatbuffers::FlatBufferBuilder());
+    index_builder_.reset(new UrlPatternIndexBuilder(flat_builder_.get()));
+  }
+
+ private:
+  std::unique_ptr<flatbuffers::FlatBufferBuilder> flat_builder_;
+  std::unique_ptr<UrlPatternIndexBuilder> index_builder_;
+  std::unique_ptr<UrlPatternIndexMatcher> index_matcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(UrlPatternIndexTest);
+};
+
+TEST_F(UrlPatternIndexTest, EmptyIndex) {
+  Finish();
+  EXPECT_FALSE(FindMatch(base::StringPiece() /* url */));
+  EXPECT_FALSE(FindMatch("http://example.com"));
+  EXPECT_FALSE(FindMatch("http://another.example.com?param=val"));
+}
+
+TEST_F(UrlPatternIndexTest, OneSimpleRule) {
+  ASSERT_TRUE(AddUrlRule(MakeUrlRule(UrlPattern("?param=", kSubstring))));
+  Finish();
+
+  EXPECT_FALSE(FindMatch("https://example.com"));
+  EXPECT_TRUE(FindMatch("http://example.org?param=image1"));
+}
+
+TEST_F(UrlPatternIndexTest, NoRuleApplies) {
+  ASSERT_TRUE(AddUrlRule(MakeUrlRule(UrlPattern("?filter_out=", kSubstring))));
+  ASSERT_TRUE(AddUrlRule(MakeUrlRule(UrlPattern("&filter_out=", kSubstring))));
+  Finish();
+
+  EXPECT_FALSE(FindMatch("http://example.com"));
+  EXPECT_FALSE(FindMatch("http://example.com?filter_not"));
+  EXPECT_FALSE(FindMatch("http://example.com?k=v&filter_not"));
+}
+
+TEST_F(UrlPatternIndexTest, OneRuleWithoutMetaInfo) {
+  const struct {
+    UrlPattern url_pattern;
+    const char* url;
+    bool expect_match;
+  } kTestCases[] = {
+      // SUBSTRING
+      {{"abcd", kSubstring}, "http://ex.com/abcd", true},
+      {{"abcd", kSubstring}, "http://ex.com/dcab", false},
+      {{"42", kSubstring}, "http://ex.com/adcd/picture42.png", true},
+      {{"&test", kSubstring},
+       "http://ex.com/params?param1=false&test=true",
+       true},
+      {{"-test-42.", kSubstring}, "http://ex.com/unit-test-42.1", true},
+      {{"/abcdtest160x600.", kSubstring},
+       "http://ex.com/abcdtest160x600.png",
+       true},
+
+      // WILDCARDED
+      {{"http://ex.com/abcd/picture*.png"},
+       "http://ex.com/abcd/picture42.png",
+       true},
+      {{"ex.com", kSubdomain, kAnchorNone}, "http://ex.com", true},
+      {{"ex.com", kSubdomain, kAnchorNone}, "http://test.ex.com", true},
+      {{"ex.com", kSubdomain, kAnchorNone}, "https://test.ex.com.com", true},
+      {{"ex.com", kSubdomain, kAnchorNone}, "https://test.rest.ex.com", true},
+      {{"ex.com", kSubdomain, kAnchorNone}, "https://test_ex.com", false},
+
+      {{"http://ex.com", kBoundary, kAnchorNone}, "http://ex.com/", true},
+      {{"http://ex.com", kBoundary, kAnchorNone}, "http://ex.com/42", true},
+      {{"http://ex.com", kBoundary, kAnchorNone},
+       "http://ex.com/42/http://ex.com/",
+       true},
+      {{"http://ex.com", kBoundary, kAnchorNone},
+       "http://ex.com/42/http://ex.info/",
+       true},
+      {{"http://ex.com/", kBoundary, kBoundary}, "http://ex.com", true},
+      {{"http://ex.com/", kBoundary, kBoundary}, "http://ex.com/42", false},
+      {{"http://ex.com/", kBoundary, kBoundary},
+       "http://ex.info/42/http://ex.com/",
+       false},
+      {{"http://ex.com/", kBoundary, kBoundary},
+       "http://ex.info/42/http://ex.com/",
+       false},
+      {{"http://ex.com/", kBoundary, kBoundary}, "http://ex.com/", true},
+      {{"http://ex.com/", kBoundary, kBoundary}, "http://ex.com/42.swf", false},
+      {{"http://ex.com/", kBoundary, kBoundary},
+       "http://ex.info/redirect/http://ex.com/",
+       false},
+      {{"pdf", kAnchorNone, kBoundary}, "http://ex.com/abcd.pdf", true},
+      {{"pdf", kAnchorNone, kBoundary}, "http://ex.com/pdfium", false},
+      {{"http://ex.com^"}, "http://ex.com/", true},
+      {{"http://ex.com^"}, "http://ex.com:8000/", true},
+      {{"http://ex.com^"}, "http://ex.com.ru", false},
+      {{"^ex.com^"},
+       "http://ex.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82",
+       true},
+      {{"^42.loss^"},
+       "http://ex.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82",
+       true},
+
+      // TODO(pkalinnikov): The '^' at the end should match end-of-string.
+      //
+      // {"^%D1%82%D0%B5%D1%81%D1%82^",
+      //  "http://ex.com:8000/42.loss?a=12&b=%D1%82%D0%B5%D1%81%D1%82",
+      //  true},
+      // {"/abcd/*/picture^", "http://ex.com/abcd/42/picture", true},
+
+      {{"/abcd/*/picture^"}, "http://ex.com/abcd/42/loss/picture?param", true},
+      {{"/abcd/*/picture^"}, "http://ex.com/abcd//picture/42", true},
+      {{"/abcd/*/picture^"}, "http://ex.com/abcd/picture", false},
+      {{"/abcd/*/picture^"}, "http://ex.com/abcd/42/pictureraph", false},
+      {{"/abcd/*/picture^"}, "http://ex.com/abcd/42/picture.swf", false},
+      {{"test.ex.com^", kSubdomain, kAnchorNone},
+       "http://test.ex.com/42.swf",
+       true},
+      {{"test.ex.com^", kSubdomain, kAnchorNone},
+       "http://server1.test.ex.com/42.swf",
+       true},
+      {{"test.ex.com^", kSubdomain, kAnchorNone},
+       "https://test.ex.com:8000/",
+       true},
+      {{"test.ex.com^", kSubdomain, kAnchorNone},
+       "http://test.ex.com.ua/42.swf",
+       false},
+      {{"test.ex.com^", kSubdomain, kAnchorNone},
+       "http://ex.com/redirect/http://test.ex.com/",
+       false},
+
+      {{"/abcd/*"}, "https://ex.com/abcd/", true},
+      {{"/abcd/*"}, "http://ex.com/abcd/picture.jpeg", true},
+      {{"/abcd/*"}, "https://ex.com/abcd", false},
+      {{"/abcd/*"}, "http://abcd.ex.com", false},
+      {{"*/abcd/"}, "https://ex.com/abcd/", true},
+      {{"*/abcd/"}, "http://ex.com/abcd/picture.jpeg", true},
+      {{"*/abcd/"}, "https://ex.com/test-abcd/", false},
+      {{"*/abcd/"}, "http://abcd.ex.com", false},
+  };
+
+  for (const auto& test_case : kTestCases) {
+    SCOPED_TRACE(::testing::Message() << "UrlPattern: " << test_case.url_pattern
+                                      << "; URL: " << test_case.url);
+
+    ASSERT_TRUE(AddUrlRule(MakeUrlRule(test_case.url_pattern)));
+    Finish();
+
+    EXPECT_EQ(test_case.expect_match, !!FindMatch(test_case.url));
+    Reset();
+  }
+}
+
+TEST_F(UrlPatternIndexTest, OneRuleWithThirdParty) {
+  const struct {
+    const char* url_pattern;
+    proto::SourceType source_type;
+
+    const char* url;
+    const char* document_origin;
+    bool expect_match;
+  } kTestCases[] = {
+      {"ex.com", kThirdParty, "http://ex.com", "http://exmpl.org", true},
+      {"ex.com", kThirdParty, "http://ex.com", "http://ex.com", false},
+      {"ex.com", kThirdParty, "http://ex.com/path?k=v", "http://exmpl.org",
+       true},
+      {"ex.com", kThirdParty, "http://ex.com/path?k=v", "http://ex.com", false},
+      {"ex.com", kFirstParty, "http://ex.com/path?k=v", "http://ex.com", true},
+      {"ex.com", kFirstParty, "http://ex.com/path?k=v", "http://exmpl.com",
+       false},
+      {"ex.com", kAnyParty, "http://ex.com/path?k=v", "http://ex.com", true},
+      {"ex.com", kAnyParty, "http://ex.com/path?k=v", "http://exmpl.com", true},
+      {"ex.com", kThirdParty, "http://subdomain.ex.com", "http://ex.com",
+       false},
+      {"ex.com", kThirdParty, "http://ex.com", nullptr, true},
+
+      // Public Suffix List tests.
+      {"ex.com", kThirdParty, "http://two.ex.com", "http://one.ex.com", false},
+      {"ex.com", kThirdParty, "http://ex.com", "http://one.ex.com", false},
+      {"ex.com", kThirdParty, "http://two.ex.com", "http://ex.com", false},
+      {"ex.com", kThirdParty, "http://ex.com", "http://example.org", true},
+      {"appspot.com", kThirdParty, "http://two.appspot.org",
+       "http://one.appspot.com", false},
+  };
+
+  for (auto test_case : kTestCases) {
+    SCOPED_TRACE(::testing::Message()
+                 << "UrlPattern: " << test_case.url_pattern
+                 << "; SourceType: " << static_cast<int>(test_case.source_type)
+                 << "; URL: " << test_case.url
+                 << "; DocumentOrigin: " << test_case.document_origin);
+
+    auto rule = MakeUrlRule(UrlPattern(test_case.url_pattern, kSubstring));
+    rule.set_source_type(test_case.source_type);
+    ASSERT_TRUE(AddUrlRule(rule));
+    Finish();
+
+    EXPECT_EQ(test_case.expect_match,
+              !!FindMatch(test_case.url, test_case.document_origin));
+    Reset();
+  }
+}
+
+TEST_F(UrlPatternIndexTest, OneRuleWithDomainList) {
+  constexpr const char* kUrl = "http://example.com";
+
+  const struct {
+    std::vector<std::string> domains;
+    const char* document_origin;
+    bool expect_match;
+  } kTestCases[] = {
+      {std::vector<std::string>(), nullptr, true},
+      {std::vector<std::string>(), "http://domain.com", true},
+
+      {{"domain.com"}, nullptr, false},
+      {{"domain.com"}, "http://domain.com", true},
+      {{"ddomain.com"}, "http://domain.com", false},
+      {{"domain.com"}, "http://ddomain.com", false},
+      {{"domain.com"}, "http://sub.domain.com", true},
+      {{"sub.domain.com"}, "http://domain.com", false},
+      {{"sub.domain.com"}, "http://sub.domain.com", true},
+      {{"sub.domain.com"}, "http://a.b.c.sub.domain.com", true},
+      {{"sub.domain.com"}, "http://sub.domain.com.com", false},
+
+      // TODO(pkalinnikov): Probably need to canonicalize domain patterns to
+      // avoid subtleties like below.
+      {{"domain.com"}, "http://domain.com.", true},
+      {{"domain.com"}, "http://.domain.com", true},
+      {{"domain.com"}, "http://.domain.com.", true},
+      {{".domain.com"}, "http://.domain.com", true},
+      {{"domain.com."}, "http://domain.com", false},
+      {{"domain.com."}, "http://domain.com.", true},
+
+      {{"domain..com"}, "http://domain.com", false},
+      {{"domain.com"}, "http://domain..com", false},
+      {{"domain..com"}, "http://domain..com", true},
+
+      {{"~domain.com"}, nullptr, true},
+      {{"~domain.com"}, "http://domain.com", false},
+      {{"~ddomain.com"}, "http://domain.com", true},
+      {{"~domain.com"}, "http://ddomain.com", true},
+      {{"~domain.com"}, "http://sub.domain.com", false},
+      {{"~sub.domain.com"}, "http://domain.com", true},
+      {{"~sub.domain.com"}, "http://sub.domain.com", false},
+      {{"~sub.domain.com"}, "http://a.b.c.sub.domain.com", false},
+      {{"~sub.domain.com"}, "http://sub.domain.com.com", true},
+
+      {{"domain1.com", "domain2.com"}, nullptr, false},
+      {{"domain1.com", "domain2.com"}, "http://domain1.com", true},
+      {{"domain1.com", "domain2.com"}, "http://domain2.com", true},
+      {{"domain1.com", "domain2.com"}, "http://domain3.com", false},
+      {{"domain1.com", "domain2.com"}, "http://not_domain1.com", false},
+      {{"domain1.com", "domain2.com"}, "http://sub.domain1.com", true},
+      {{"domain1.com", "domain2.com"}, "http://a.b.c.sub.domain2.com", true},
+
+      {{"~domain1.com", "~domain2.com"}, "http://domain1.com", false},
+      {{"~domain1.com", "~domain2.com"}, "http://domain2.com", false},
+      {{"~domain1.com", "~domain2.com"}, "http://domain3.com", true},
+
+      {{"domain.com", "~sub.domain.com"}, "http://domain.com", true},
+      {{"domain.com", "~sub.domain.com"}, "http://sub.domain.com", false},
+      {{"domain.com", "~sub.domain.com"}, "http://a.b.sub.domain.com", false},
+      {{"domain.com", "~sub.domain.com"}, "http://ssub.domain.com", true},
+
+      {{"domain.com", "~a.domain.com", "~b.domain.com"},
+       "http://domain.com",
+       true},
+      {{"domain.com", "~a.domain.com", "~b.domain.com"},
+       "http://a.domain.com",
+       false},
+      {{"domain.com", "~a.domain.com", "~b.domain.com"},
+       "http://b.domain.com",
+       false},
+
+      {{"domain.com", "~a.domain.com", "b.a.domain.com"},
+       "http://domain.com",
+       true},
+      {{"domain.com", "~a.domain.com", "b.a.domain.com"},
+       "http://a.domain.com",
+       false},
+      {{"domain.com", "~a.domain.com", "b.a.domain.com"},
+       "http://b.a.domain.com",
+       true},
+      {{"domain.com", "~a.domain.com", "b.a.domain.com"},
+       "http://c.b.a.domain.com",
+       true},
+
+      // The following test addresses a former bug in domain list matcher. When
+      // "domain.com" was matched, the positive filters lookup stopped, and the
+      // next domain was considered as a negative. The initial character was
+      // skipped (supposing it's a '~') and the remainder was considered a
+      // domain. So "ddomain.com" would be matched and thus the whole rule would
+      // be classified as non-matching, which is not correct.
+      {{"domain.com", "ddomain.com", "~sub.domain.com"},
+       "http://domain.com",
+       true},
+  };
+
+  for (const auto& test_case : kTestCases) {
+    SCOPED_TRACE(::testing::Message()
+                 << "Domains: " << ::testing::PrintToString(test_case.domains)
+                 << "; DocumentOrigin: " << test_case.document_origin);
+
+    auto rule = MakeUrlRule(UrlPattern(kUrl, kSubstring));
+    AddDomains(test_case.domains, &rule);
+    ASSERT_TRUE(AddUrlRule(rule));
+    Finish();
+
+    EXPECT_EQ(test_case.expect_match,
+              !!FindMatch(kUrl, test_case.document_origin));
+    Reset();
+  }
+}
+
+TEST_F(UrlPatternIndexTest, OneRuleWithLongDomainList) {
+  constexpr const char* kUrl = "http://example.com";
+  constexpr size_t kDomains = 200;
+
+  std::vector<std::string> domains;
+  for (size_t i = 0; i < kDomains; ++i) {
+    const std::string domain = "domain" + std::to_string(i) + ".com";
+    domains.push_back(domain);
+    domains.push_back("~sub." + domain);
+    domains.push_back("a.sub." + domain);
+    domains.push_back("b.sub." + domain);
+    domains.push_back("c.sub." + domain);
+    domains.push_back("~aa.sub." + domain);
+    domains.push_back("~ab.sub." + domain);
+    domains.push_back("~ba.sub." + domain);
+    domains.push_back("~bb.sub." + domain);
+    domains.push_back("~sub.sub.c.sub." + domain);
+  }
+
+  auto rule = MakeUrlRule(UrlPattern(kUrl, kSubstring));
+  AddDomains(domains, &rule);
+  ASSERT_TRUE(AddUrlRule(rule));
+  Finish();
+
+  for (size_t i = 0; i < kDomains; ++i) {
+    SCOPED_TRACE(::testing::Message() << "Iteration: " << i);
+    const std::string domain = "domain" + std::to_string(i) + ".com";
+
+    EXPECT_TRUE(FindMatch(kUrl, "http://" + domain));
+    EXPECT_FALSE(FindMatch(kUrl, "http://sub." + domain));
+    EXPECT_TRUE(FindMatch(kUrl, "http://a.sub." + domain));
+    EXPECT_TRUE(FindMatch(kUrl, "http://b.sub." + domain));
+    EXPECT_TRUE(FindMatch(kUrl, "http://c.sub." + domain));
+    EXPECT_FALSE(FindMatch(kUrl, "http://aa.sub." + domain));
+    EXPECT_FALSE(FindMatch(kUrl, "http://ab.sub." + domain));
+    EXPECT_FALSE(FindMatch(kUrl, "http://ba.sub." + domain));
+    EXPECT_FALSE(FindMatch(kUrl, "http://bb.sub." + domain));
+    EXPECT_TRUE(FindMatch(kUrl, "http://sub.c.sub." + domain));
+    EXPECT_FALSE(FindMatch(kUrl, "http://sub.sub.c.sub." + domain));
+  }
+}
+
+TEST_F(UrlPatternIndexTest, OneRuleWithElementTypes) {
+  constexpr auto kAll = kAllElementTypes;
+  const struct {
+    const char* url_pattern;
+    int32_t element_types;
+
+    const char* url;
+    proto::ElementType element_type;
+    bool expect_match;
+  } kTestCases[] = {
+      {"ex.com", kAll, "http://ex.com/img.jpg", kImage, true},
+      {"ex.com", kAll & ~kPopup, "http://ex.com/img", kPopup, false},
+
+      {"ex.com", kImage, "http://ex.com/img.jpg", kImage, true},
+      {"ex.com", kAll & ~kImage, "http://ex.com/img.jpg", kImage, false},
+      {"ex.com", kScript, "http://ex.com/img.jpg", kImage, false},
+      {"ex.com", kAll & ~kScript, "http://ex.com/img.jpg", kImage, true},
+
+      {"ex.com", kImage | kFont, "http://ex.com/font", kFont, true},
+      {"ex.com", kImage | kFont, "http://ex.com/image", kImage, true},
+      {"ex.com", kImage | kFont, "http://ex.com/video",
+       proto::ELEMENT_TYPE_MEDIA, false},
+      {"ex.com", kAll & ~kFont & ~kScript, "http://ex.com/font", kFont, false},
+      {"ex.com", kAll & ~kFont & ~kScript, "http://ex.com/scr", kScript, false},
+      {"ex.com", kAll & ~kFont & ~kScript, "http://ex.com/img", kImage, true},
+
+      {"ex.com", kAll, "http://ex.com", proto::ELEMENT_TYPE_OTHER, true},
+      {"ex.com", kAll, "http://ex.com", proto::ELEMENT_TYPE_UNSPECIFIED, false},
+      {"ex.com", kWebSocket, "ws://ex.com", proto::ELEMENT_TYPE_WEBSOCKET,
+       true},
+  };
+
+  for (const auto& test_case : kTestCases) {
+    SCOPED_TRACE(
+        ::testing::Message()
+        << "UrlPattern: " << test_case.url_pattern
+        << "; ElementTypes: " << static_cast<int>(test_case.element_types)
+        << "; URL: " << test_case.url
+        << "; ElementType: " << static_cast<int>(test_case.element_type));
+
+    auto rule = MakeUrlRule(UrlPattern(test_case.url_pattern, kSubstring));
+    rule.set_element_types(test_case.element_types);
+    ASSERT_TRUE(AddUrlRule(rule));
+    Finish();
+
+    EXPECT_EQ(test_case.expect_match,
+              !!FindMatch(test_case.url, nullptr /* document_origin_string */,
+                          test_case.element_type));
+    Reset();
+  }
+}
+
+TEST_F(UrlPatternIndexTest, OneRuleWithActivationTypes) {
+  const struct {
+    const char* url_pattern;
+    int32_t activation_types;
+
+    const char* document_url;
+    proto::ActivationType activation_type;
+    bool expect_match;
+  } kTestCases[] = {
+      {"example.com", kDocument, "http://example.com", kDocument, true},
+      {"xample.com", kDocument, "http://example.com", kDocument, true},
+      {"exampl.com", kDocument, "http://example.com", kDocument, false},
+
+      {"example.com", kGenericBlock, "http://example.com", kDocument, false},
+      {"example.com", kDocument, "http://example.com", kNoActivation, false},
+      {"example.com", kGenericBlock, "http://example.com", kNoActivation,
+       false},
+
+      // Invalid GURL.
+      {"example.com", kDocument, "http;//example.com", kDocument, false},
+  };
+
+  for (const auto& test_case : kTestCases) {
+    SCOPED_TRACE(
+        ::testing::Message()
+        << "UrlPattern: " << test_case.url_pattern
+        << "; ActivationTypes: " << static_cast<int>(test_case.activation_types)
+        << "; DocumentURL: " << test_case.document_url
+        << "; ActivationType: " << static_cast<int>(test_case.activation_type));
+
+    auto rule = MakeUrlRule(UrlPattern(test_case.url_pattern, kSubstring));
+    rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
+    rule.clear_element_types();
+    rule.set_activation_types(test_case.activation_types);
+    ASSERT_TRUE(AddUrlRule(rule));
+    Finish();
+
+    EXPECT_EQ(test_case.expect_match,
+              !!FindMatch(test_case.document_url,
+                          nullptr /* parent_document_origin */, kNoElement,
+                          test_case.activation_type));
+    EXPECT_EQ(test_case.expect_match,
+              !!FindMatch(test_case.document_url, "http://example.com/",
+                          kNoElement, test_case.activation_type));
+    EXPECT_EQ(test_case.expect_match,
+              !!FindMatch(test_case.document_url, "http://xmpl.com/",
+                          kNoElement, test_case.activation_type));
+    Reset();
+  }
+}
+
+TEST_F(UrlPatternIndexTest, OneRuleWithElementAndActivationTypes) {
+  auto rule = MakeUrlRule(UrlPattern("allow.ex.com", kSubstring));
+  rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
+  rule.set_element_types(kSubdocument);
+  rule.set_activation_types(kDocument);
+  ASSERT_TRUE(AddUrlRule(rule));
+  Finish();
+
+  EXPECT_FALSE(FindMatch("http://allow.ex.com"));
+  EXPECT_TRUE(FindMatch("http://allow.ex.com",
+                        nullptr /*document_origin_string */, kSubdocument));
+
+  EXPECT_FALSE(FindMatch("http://allow.ex.com",
+                         nullptr /* document_origin_string */, kNoElement,
+                         kGenericBlock));
+  EXPECT_TRUE(FindMatch("http://allow.ex.com",
+                        nullptr /* document_origin_string */, kNoElement,
+                        kDocument));
+}
+
+TEST_F(UrlPatternIndexTest, MatchWithDisableGenericRules) {
+  const struct {
+    const char* url_pattern;
+    std::vector<std::string> domains;
+  } kRules[] = {
+      // Generic rules.
+      {"some_text", std::vector<std::string>()},
+      {"another_text", {"~example.com"}},
+      {"final_text", {"~example1.com", "~example2.com"}},
+      // Domain specific rules.
+      {"some_text", {"example1.com"}},
+      {"more_text", {"example.com", "~exclude.example.com"}},
+      {"last_text", {"example1.com", "sub.example2.com"}},
+  };
+
+  for (const auto& rule_data : kRules) {
+    auto rule = MakeUrlRule(UrlPattern(rule_data.url_pattern, kSubstring));
+    AddDomains(rule_data.domains, &rule);
+    ASSERT_TRUE(AddUrlRule(rule))
+        << "UrlPattern: " << rule_data.url_pattern
+        << "; Domains: " << ::testing::PrintToString(rule_data.domains);
+  }
+
+  // Note: Some of the rules have common domains (e.g., example1.com), which are
+  // ultimately shared by FlatBuffers' CreateSharedString. The test also makes
+  // sure that the data structure works properly with such optimization.
+  Finish();
+
+  const struct {
+    const char* url;
+    const char* document_origin;
+    bool expect_match_with_enable_all_rules;
+    bool expect_match_with_disable_generic_rules;
+  } kTestCases[] = {
+      {"http://ex.com/some_text", "http://example.com", true, false},
+      {"http://ex.com/some_text", "http://example1.com", true, true},
+
+      {"http://ex.com/another_text", "http://example.com", false, false},
+      {"http://ex.com/another_text", "http://example1.com", true, false},
+
+      {"http://ex.com/final_text", "http://example.com", true, false},
+      {"http://ex.com/final_text", "http://example1.com", false, false},
+      {"http://ex.com/final_text", "http://example2.com", false, false},
+
+      {"http://ex.com/more_text", "http://example.com", true, true},
+      {"http://ex.com/more_text", "http://exclude.example.com", false, false},
+      {"http://ex.com/more_text", "http://example1.com", false, false},
+
+      {"http://ex.com/last_text", "http://example.com", false, false},
+      {"http://ex.com/last_text", "http://example1.com", true, true},
+      {"http://ex.com/last_text", "http://example2.com", false, false},
+      {"http://ex.com/last_text", "http://sub.example2.com", true, true},
+  };
+
+  constexpr bool kDisableGenericRules = true;
+  constexpr bool kEnableAllRules = false;
+  for (const auto& test_case : kTestCases) {
+    SCOPED_TRACE(::testing::Message()
+                 << "UrlPattern: " << test_case.url
+                 << "; DocumentOrigin: " << test_case.document_origin);
+
+    EXPECT_EQ(test_case.expect_match_with_disable_generic_rules,
+              !!FindMatch(test_case.url, test_case.document_origin, kOther,
+                          kNoActivation, kDisableGenericRules));
+    EXPECT_EQ(test_case.expect_match_with_enable_all_rules,
+              !!FindMatch(test_case.url, test_case.document_origin, kOther,
+                          kNoActivation, kEnableAllRules));
+  }
+}
+
+TEST_F(UrlPatternIndexTest, RulesWithUnsupportedTypes) {
+  const struct {
+    int element_types;
+    int activation_types;
+  } kRules[] = {
+      {proto::ELEMENT_TYPE_MAX << 1, 0},
+      {0, proto::ACTIVATION_TYPE_MAX << 1},
+      {proto::ELEMENT_TYPE_MAX << 1, proto::ACTIVATION_TYPE_MAX << 1},
+
+      {kPopup, 0},
+      {0, proto::ACTIVATION_TYPE_ELEMHIDE},
+      {0, proto::ACTIVATION_TYPE_GENERICHIDE},
+      {0, proto::ACTIVATION_TYPE_ELEMHIDE | proto::ACTIVATION_TYPE_GENERICHIDE},
+      {proto::ELEMENT_TYPE_POPUP, proto::ACTIVATION_TYPE_ELEMHIDE},
+  };
+
+  for (const auto& rule_data : kRules) {
+    auto rule = MakeUrlRule(UrlPattern("example.com", kSubstring));
+    rule.set_element_types(rule_data.element_types);
+    rule.set_activation_types(rule_data.activation_types);
+    EXPECT_FALSE(AddUrlRule(rule))
+        << "ElementTypes: " << static_cast<int>(rule_data.element_types)
+        << "; ActivationTypes: "
+        << static_cast<int>(rule_data.activation_types);
+  }
+  ASSERT_TRUE(AddUrlRule(MakeUrlRule(UrlPattern("exmpl.com", kSubstring))));
+  Finish();
+
+  EXPECT_FALSE(FindMatch("http://example.com/"));
+  EXPECT_TRUE(FindMatch("https://exmpl.com/"));
+}
+
+TEST_F(UrlPatternIndexTest, RulesWithSupportedAndUnsupportedTypes) {
+  const struct {
+    int element_types;
+    int activation_types;
+  } kRules[] = {
+      {kImage | (proto::ELEMENT_TYPE_MAX << 1), 0},
+      {kScript | kPopup, 0},
+      {0, kDocument | (proto::ACTIVATION_TYPE_MAX << 1)},
+  };
+
+  for (const auto& rule_data : kRules) {
+    auto rule = MakeUrlRule(UrlPattern("example.com", kSubstring));
+    rule.set_semantics(proto::RULE_SEMANTICS_WHITELIST);
+    rule.set_element_types(rule_data.element_types);
+    rule.set_activation_types(rule_data.activation_types);
+    EXPECT_TRUE(AddUrlRule(rule))
+        << "ElementTypes: " << static_cast<int>(rule_data.element_types)
+        << "; ActivationTypes: "
+        << static_cast<int>(rule_data.activation_types);
+  }
+  Finish();
+
+  EXPECT_TRUE(FindMatch("http://example.com/", nullptr, kImage));
+  EXPECT_TRUE(FindMatch("http://example.com/", nullptr, kScript));
+  EXPECT_FALSE(FindMatch("http://example.com/", nullptr, kPopup));
+  EXPECT_FALSE(FindMatch("http://example.com/"));
+
+  EXPECT_TRUE(FindMatch("http://example.com", nullptr, kNoElement, kDocument));
+  EXPECT_FALSE(
+      FindMatch("http://example.com", nullptr, kNoElement, kGenericBlock));
+}
+
+}  // namespace subresource_filter
diff --git a/components/suggestions/suggestions_service_impl.h b/components/suggestions/suggestions_service_impl.h
index ff31fc8..dac972d 100644
--- a/components/suggestions/suggestions_service_impl.h
+++ b/components/suggestions/suggestions_service_impl.h
@@ -99,7 +99,8 @@
   FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest, BlacklistURLRequestFails);
   FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest, ClearBlacklist);
   FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest, UndoBlacklistURL);
-  FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest, GetBlacklistedUrl);
+  FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest,
+                           GetBlacklistedUrlBlacklistRequest);
   FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest, UpdateBlacklistDelay);
   FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest, CheckDefaultTimeStamps);
 
diff --git a/components/suggestions/suggestions_service_impl_unittest.cc b/components/suggestions/suggestions_service_impl_unittest.cc
index 829c053..217303e 100644
--- a/components/suggestions/suggestions_service_impl_unittest.cc
+++ b/components/suggestions/suggestions_service_impl_unittest.cc
@@ -159,14 +159,13 @@
 class MockBlacklistStore : public suggestions::BlacklistStore {
  public:
   MOCK_METHOD1(BlacklistUrl, bool(const GURL&));
-  MOCK_METHOD0(IsEmpty, bool());
+  MOCK_METHOD0(ClearBlacklist, void());
   MOCK_METHOD1(GetTimeUntilReadyForUpload, bool(base::TimeDelta*));
   MOCK_METHOD2(GetTimeUntilURLReadyForUpload,
                bool(const GURL&, base::TimeDelta*));
   MOCK_METHOD1(GetCandidateForUpload, bool(GURL*));
   MOCK_METHOD1(RemoveUrl, bool(const GURL&));
   MOCK_METHOD1(FilterSuggestions, void(SuggestionsProfile*));
-  MOCK_METHOD0(ClearBlacklist, void());
 };
 
 class SuggestionsServiceTest : public testing::Test {
@@ -177,27 +176,13 @@
       ++suggestions_empty_data_count_;
   }
 
-  void CheckSuggestionsData() {
-    SuggestionsProfile suggestions_profile;
-    test_suggestions_store_->LoadSuggestions(&suggestions_profile);
-    EXPECT_EQ(1, suggestions_profile.suggestions_size());
-    EXPECT_EQ(kTestTitle, suggestions_profile.suggestions(0).title());
-    EXPECT_EQ(kTestUrl, suggestions_profile.suggestions(0).url());
-    EXPECT_EQ(kTestFaviconUrl,
-              suggestions_profile.suggestions(0).favicon_url());
-  }
-
   int suggestions_data_callback_count_;
   int suggestions_empty_data_count_;
-  bool blacklisting_failed_;
-  bool undo_blacklisting_failed_;
 
  protected:
   SuggestionsServiceTest()
       : suggestions_data_callback_count_(0),
         suggestions_empty_data_count_(0),
-        blacklisting_failed_(false),
-        undo_blacklisting_failed_(false),
         signin_client_(&pref_service_),
         signin_manager_(&signin_client_, &account_tracker_),
         factory_(nullptr, base::Bind(&CreateURLFetcher)),
@@ -221,7 +206,7 @@
   }
 
   std::unique_ptr<SuggestionsServiceImpl> CreateSuggestionsServiceWithMocks() {
-    mock_sync_service_.reset(new MockSyncService);
+    mock_sync_service_ = base::MakeUnique<MockSyncService>();
     EXPECT_CALL(*mock_sync_service_, CanSyncStart())
         .Times(AnyNumber())
         .WillRepeatedly(Return(true));
@@ -238,6 +223,9 @@
 
     // These objects are owned by the returned SuggestionsService, but we keep
     // the pointer around for testing.
+    // TODO(treib): This is broken - if the test destroys the SuggestionsService
+    // (which it can easily do, since it has an owning pointer), we'll be left
+    // with dangling pointers here.
     test_suggestions_store_ = new TestSuggestionsStore();
     mock_thumbnail_manager_ = new StrictMock<MockImageManager>();
     mock_blacklist_store_ = new StrictMock<MockBlacklistStore>();
@@ -248,21 +236,12 @@
         base::WrapUnique(mock_blacklist_store_));
   }
 
-  void Blacklist(SuggestionsService* suggestions_service, GURL url) {
-    blacklisting_failed_ = !suggestions_service->BlacklistURL(url);
-  }
-
-  void UndoBlacklist(SuggestionsService* suggestions_service, GURL url) {
-    undo_blacklisting_failed_ = !suggestions_service->UndoBlacklistURL(url);
-  }
-
   // Helper for Undo failure tests. Depending on |is_uploaded|, tests either
   // the case where the URL is no longer in the local blacklist or the case
   // in which it's not yet candidate for upload.
   void UndoBlacklistURLFailsHelper(bool is_uploaded) {
     std::unique_ptr<SuggestionsServiceImpl> suggestions_service(
         CreateSuggestionsServiceWithMocks());
-    EXPECT_TRUE(suggestions_service != nullptr);
     // Ensure scheduling the request doesn't happen before undo.
     base::TimeDelta delay = base::TimeDelta::FromHours(1);
     suggestions_service->set_blacklist_delay(delay);
@@ -295,12 +274,10 @@
           .WillOnce(DoAll(SetArgPointee<1>(negative_delay), Return(true)));
     }
 
-    Blacklist(suggestions_service.get(), blacklisted_url);
-    UndoBlacklist(suggestions_service.get(), blacklisted_url);
+    EXPECT_TRUE(suggestions_service->BlacklistURL(blacklisted_url));
+    EXPECT_FALSE(suggestions_service->UndoBlacklistURL(blacklisted_url));
 
     EXPECT_EQ(1, suggestions_data_callback_count_);
-    EXPECT_FALSE(blacklisting_failed_);
-    EXPECT_TRUE(undo_blacklisting_failed_);
   }
 
   bool HasPendingSuggestionsRequest(
@@ -330,7 +307,6 @@
 TEST_F(SuggestionsServiceTest, FetchSuggestionsData) {
   std::unique_ptr<SuggestionsService> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  ASSERT_TRUE(suggestions_service != nullptr);
   auto subscription = suggestions_service->AddCallback(base::Bind(
       &SuggestionsServiceTest::CheckCallback, base::Unretained(this)));
 
@@ -356,13 +332,16 @@
   // Ensure that CheckCallback() ran once.
   EXPECT_EQ(1, suggestions_data_callback_count_);
 
-  CheckSuggestionsData();
+  test_suggestions_store_->LoadSuggestions(&suggestions_profile);
+  ASSERT_EQ(1, suggestions_profile.suggestions_size());
+  EXPECT_EQ(kTestTitle, suggestions_profile.suggestions(0).title());
+  EXPECT_EQ(kTestUrl, suggestions_profile.suggestions(0).url());
+  EXPECT_EQ(kTestFaviconUrl, suggestions_profile.suggestions(0).favicon_url());
 }
 
 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataSyncNotInitializedEnabled) {
   std::unique_ptr<SuggestionsService> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  ASSERT_TRUE(suggestions_service != nullptr);
   EXPECT_CALL(*mock_sync_service_, IsSyncActive())
       .WillRepeatedly(Return(false));
 
@@ -389,7 +368,6 @@
 TEST_F(SuggestionsServiceTest, FetchSuggestionsDataSyncDisabled) {
   std::unique_ptr<SuggestionsServiceImpl> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  ASSERT_TRUE(suggestions_service != nullptr);
   EXPECT_CALL(*mock_sync_service_, CanSyncStart())
       .WillRepeatedly(Return(false));
 
@@ -420,7 +398,6 @@
 
   std::unique_ptr<SuggestionsServiceImpl> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  ASSERT_TRUE(suggestions_service != nullptr);
 
   auto subscription = suggestions_service->AddCallback(base::Bind(
       &SuggestionsServiceTest::CheckCallback, base::Unretained(this)));
@@ -442,7 +419,6 @@
 TEST_F(SuggestionsServiceTest, IssueRequestIfNoneOngoingError) {
   std::unique_ptr<SuggestionsServiceImpl> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  ASSERT_TRUE(suggestions_service != nullptr);
 
   // Fake a request error.
   factory_.SetFakeResponse(SuggestionsServiceImpl::BuildSuggestionsURL(),
@@ -463,7 +439,6 @@
 TEST_F(SuggestionsServiceTest, IssueRequestIfNoneOngoingResponseNotOK) {
   std::unique_ptr<SuggestionsServiceImpl> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  ASSERT_TRUE(suggestions_service != nullptr);
 
   // Fake a non-200 response code.
   factory_.SetFakeResponse(SuggestionsServiceImpl::BuildSuggestionsURL(),
@@ -489,7 +464,6 @@
 TEST_F(SuggestionsServiceTest, BlacklistURL) {
   std::unique_ptr<SuggestionsServiceImpl> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  EXPECT_TRUE(suggestions_service != nullptr);
   base::TimeDelta no_delay = base::TimeDelta::FromSeconds(0);
   suggestions_service->set_blacklist_delay(no_delay);
 
@@ -516,7 +490,7 @@
   EXPECT_CALL(*mock_blacklist_store_, RemoveUrl(Eq(blacklisted_url)))
       .WillOnce(Return(true));
 
-  Blacklist(suggestions_service.get(), blacklisted_url);
+  EXPECT_TRUE(suggestions_service->BlacklistURL(blacklisted_url));
   EXPECT_EQ(1, suggestions_data_callback_count_);
 
   // Wait on the upload task, the blacklist request and the next blacklist
@@ -526,14 +500,17 @@
   base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(2, suggestions_data_callback_count_);
-  EXPECT_FALSE(blacklisting_failed_);
-  CheckSuggestionsData();
+
+  test_suggestions_store_->LoadSuggestions(&suggestions_profile);
+  ASSERT_EQ(1, suggestions_profile.suggestions_size());
+  EXPECT_EQ(kTestTitle, suggestions_profile.suggestions(0).title());
+  EXPECT_EQ(kTestUrl, suggestions_profile.suggestions(0).url());
+  EXPECT_EQ(kTestFaviconUrl, suggestions_profile.suggestions(0).favicon_url());
 }
 
 TEST_F(SuggestionsServiceTest, BlacklistURLFails) {
   std::unique_ptr<SuggestionsService> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  ASSERT_TRUE(suggestions_service != nullptr);
 
   auto subscription = suggestions_service->AddCallback(base::Bind(
       &SuggestionsServiceTest::CheckCallback, base::Unretained(this)));
@@ -542,9 +519,8 @@
   EXPECT_CALL(*mock_blacklist_store_, BlacklistUrl(Eq(blacklisted_url)))
       .WillOnce(Return(false));
 
-  Blacklist(suggestions_service.get(), blacklisted_url);
+  EXPECT_FALSE(suggestions_service->BlacklistURL(blacklisted_url));
 
-  EXPECT_TRUE(blacklisting_failed_);
   EXPECT_EQ(0, suggestions_data_callback_count_);
 }
 
@@ -552,7 +528,6 @@
 TEST_F(SuggestionsServiceTest, BlacklistURLRequestFails) {
   std::unique_ptr<SuggestionsServiceImpl> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  ASSERT_TRUE(suggestions_service != nullptr);
   base::TimeDelta no_delay = base::TimeDelta::FromSeconds(0);
   suggestions_service->set_blacklist_delay(no_delay);
 
@@ -593,22 +568,25 @@
       .WillOnce(Return(true));
 
   // Blacklist call, first request attempt.
-  Blacklist(suggestions_service.get(), blacklisted_url);
+  EXPECT_TRUE(suggestions_service->BlacklistURL(blacklisted_url));
   EXPECT_EQ(1, suggestions_data_callback_count_);
-  EXPECT_FALSE(blacklisting_failed_);
 
   // Wait for the first scheduling, the first request, the second scheduling,
   // second request and the third scheduling. Again, note that calling
   // RunUntilIdle on the MessageLoop only works when the task is not posted for
   // the future.
   base::RunLoop().RunUntilIdle();
-  CheckSuggestionsData();
+
+  test_suggestions_store_->LoadSuggestions(&suggestions_profile);
+  ASSERT_EQ(1, suggestions_profile.suggestions_size());
+  EXPECT_EQ(kTestTitle, suggestions_profile.suggestions(0).title());
+  EXPECT_EQ(kTestUrl, suggestions_profile.suggestions(0).url());
+  EXPECT_EQ(kTestFaviconUrl, suggestions_profile.suggestions(0).favicon_url());
 }
 
 TEST_F(SuggestionsServiceTest, UndoBlacklistURL) {
   std::unique_ptr<SuggestionsServiceImpl> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  ASSERT_TRUE(suggestions_service != nullptr);
   // Ensure scheduling the request doesn't happen before undo.
   base::TimeDelta delay = base::TimeDelta::FromHours(1);
   suggestions_service->set_blacklist_delay(delay);
@@ -635,18 +613,15 @@
   EXPECT_CALL(*mock_blacklist_store_, RemoveUrl(Eq(blacklisted_url)))
       .WillOnce(Return(true));
 
-  Blacklist(suggestions_service.get(), blacklisted_url);
-  UndoBlacklist(suggestions_service.get(), blacklisted_url);
+  EXPECT_TRUE(suggestions_service->BlacklistURL(blacklisted_url));
+  EXPECT_TRUE(suggestions_service->UndoBlacklistURL(blacklisted_url));
 
   EXPECT_EQ(2, suggestions_data_callback_count_);
-  EXPECT_FALSE(blacklisting_failed_);
-  EXPECT_FALSE(undo_blacklisting_failed_);
 }
 
 TEST_F(SuggestionsServiceTest, ClearBlacklist) {
   std::unique_ptr<SuggestionsServiceImpl> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  ASSERT_TRUE(suggestions_service != nullptr);
   // Ensure scheduling the request doesn't happen before undo.
   base::TimeDelta delay = base::TimeDelta::FromHours(1);
   suggestions_service->set_blacklist_delay(delay);
@@ -673,11 +648,10 @@
       .WillOnce(DoAll(SetArgPointee<0>(delay), Return(true)));
   EXPECT_CALL(*mock_blacklist_store_, ClearBlacklist());
 
-  Blacklist(suggestions_service.get(), blacklisted_url);
+  EXPECT_TRUE(suggestions_service->BlacklistURL(blacklisted_url));
   suggestions_service->ClearBlacklist();
 
   EXPECT_EQ(2, suggestions_data_callback_count_);
-  EXPECT_FALSE(blacklisting_failed_);
 }
 
 TEST_F(SuggestionsServiceTest, UndoBlacklistURLFailsIfNotInBlacklist) {
@@ -688,29 +662,27 @@
   UndoBlacklistURLFailsHelper(false);
 }
 
-TEST_F(SuggestionsServiceTest, GetBlacklistedUrl) {
-  std::unique_ptr<GURL> request_url;
-  std::unique_ptr<net::FakeURLFetcher> fetcher;
-  GURL retrieved_url;
-
+TEST_F(SuggestionsServiceTest, GetBlacklistedUrlNotBlacklistRequest) {
   // Not a blacklist request.
-  request_url.reset(new GURL("http://not-blacklisting.com/a?b=c"));
-  fetcher = CreateURLFetcher(*request_url, nullptr, "", net::HTTP_OK,
-                             net::URLRequestStatus::SUCCESS);
+  std::unique_ptr<net::FakeURLFetcher> fetcher(
+      CreateURLFetcher(GURL("http://not-blacklisting.com/a?b=c"), nullptr, "",
+                       net::HTTP_OK, net::URLRequestStatus::SUCCESS));
+  GURL retrieved_url;
   EXPECT_FALSE(
       SuggestionsServiceImpl::GetBlacklistedUrl(*fetcher, &retrieved_url));
+}
 
+TEST_F(SuggestionsServiceTest, GetBlacklistedUrlBlacklistRequest) {
   // An actual blacklist request.
   std::string blacklisted_url = "http://blacklisted.com/a?b=c&d=e";
   std::string encoded_blacklisted_url =
       "http%3A%2F%2Fblacklisted.com%2Fa%3Fb%3Dc%26d%3De";
   std::string blacklist_request_prefix(
       SuggestionsServiceImpl::BuildSuggestionsBlacklistURLPrefix());
-  request_url.reset(
-      new GURL(blacklist_request_prefix + encoded_blacklisted_url));
-  fetcher.reset();
-  fetcher = CreateURLFetcher(*request_url, nullptr, "", net::HTTP_OK,
-                             net::URLRequestStatus::SUCCESS);
+  std::unique_ptr<net::FakeURLFetcher> fetcher(CreateURLFetcher(
+      GURL(blacklist_request_prefix + encoded_blacklisted_url), nullptr, "",
+      net::HTTP_OK, net::URLRequestStatus::SUCCESS));
+  GURL retrieved_url;
   EXPECT_TRUE(
       SuggestionsServiceImpl::GetBlacklistedUrl(*fetcher, &retrieved_url));
   EXPECT_EQ(blacklisted_url, retrieved_url.spec());
@@ -748,7 +720,6 @@
 TEST_F(SuggestionsServiceTest, GetPageThumbnail) {
   std::unique_ptr<SuggestionsService> suggestions_service(
       CreateSuggestionsServiceWithMocks());
-  ASSERT_TRUE(suggestions_service != nullptr);
 
   GURL test_url(kTestUrl);
   GURL thumbnail_url("https://www.thumbnails.com/thumb.jpg");
diff --git a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
index da14eed1..a62d45c 100644
--- a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
@@ -310,7 +310,7 @@
 
 ACTION_P2(RecordSyncShare, times, success) {
   RecordSyncShareImpl(times);
-  if (base::MessageLoop::current()->is_running())
+  if (base::RunLoop::IsRunningOnCurrentThread())
     QuitLoopNow();
   return success;
 }
@@ -319,7 +319,7 @@
   RecordSyncShareImpl(times);
   EXPECT_LE(times->size(), quit_after);
   if (times->size() >= quit_after &&
-      base::MessageLoop::current()->is_running()) {
+      base::RunLoop::IsRunningOnCurrentThread()) {
     QuitLoopNow();
   }
   return success;
diff --git a/content/browser/accessibility/accessibility_event_recorder_win.cc b/content/browser/accessibility/accessibility_event_recorder_win.cc
index 32fd6ae..7d435d7 100644
--- a/content/browser/accessibility/accessibility_event_recorder_win.cc
+++ b/content/browser/accessibility/accessibility_event_recorder_win.cc
@@ -187,7 +187,7 @@
   }
 
   base::win::ScopedComPtr<IAccessible> iaccessible;
-  hr = dispatch.QueryInterface(iaccessible.Receive());
+  hr = dispatch.CopyTo(iaccessible.Receive());
   if (!SUCCEEDED(hr)) {
     VLOG(1) << "Ignoring result " << hr << " from QueryInterface";
     return;
diff --git a/content/browser/accessibility/accessibility_tree_formatter_win.cc b/content/browser/accessibility/accessibility_tree_formatter_win.cc
index b7c2ce5..9bb710991 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_win.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_win.cc
@@ -132,7 +132,7 @@
           index_of_embed, embedded_object.Receive());
       DCHECK(SUCCEEDED(hr));
       base::win::ScopedComPtr<IAccessible2> ax_embed;
-      hr = embedded_object.QueryInterface(ax_embed.Receive());
+      hr = embedded_object.CopyTo(ax_embed.Receive());
       DCHECK(SUCCEEDED(hr));
       hr = ax_embed->get_indexInParent(&child_index);
       DCHECK(SUCCEEDED(hr));
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc
index 2b31d4e..07121ba 100644
--- a/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -161,7 +161,7 @@
   ASSERT_EQ(ROLE_SYSTEM_TEXT, input_role);
 
   // Retrieve the IAccessibleText interface for the field.
-  ASSERT_HRESULT_SUCCEEDED(input.QueryInterface(input_text->Receive()));
+  ASSERT_HRESULT_SUCCEEDED(input.CopyTo(input_text->Receive()));
 
   // Set the caret on the last character.
   AccessibilityNotificationWaiter waiter(shell()->web_contents(),
@@ -213,7 +213,7 @@
   ASSERT_EQ(ROLE_SYSTEM_TEXT, textarea_role);
 
   // Retrieve the IAccessibleText interface for the field.
-  ASSERT_HRESULT_SUCCEEDED(textarea.QueryInterface(textarea_text->Receive()));
+  ASSERT_HRESULT_SUCCEEDED(textarea.CopyTo(textarea_text->Receive()));
 
   // Set the caret on the last character.
   AccessibilityNotificationWaiter waiter(shell()->web_contents(),
@@ -257,7 +257,7 @@
   LONG paragraph_role = 0;
   ASSERT_HRESULT_SUCCEEDED(paragraph->role(&paragraph_role));
   ASSERT_EQ(IA2_ROLE_PARAGRAPH, paragraph_role);
-  ASSERT_HRESULT_SUCCEEDED(paragraph.QueryInterface(
+  ASSERT_HRESULT_SUCCEEDED(paragraph.CopyTo(
       accessible_text->Receive()));
 }
 
@@ -281,7 +281,7 @@
       HRESULT hr = parent->get_accChild(*var, dispatch.Receive());
       EXPECT_TRUE(SUCCEEDED(hr));
       if (dispatch.Get())
-        dispatch.QueryInterface(ptr.Receive());
+        dispatch.CopyTo(ptr.Receive());
       break;
     }
   }
@@ -1122,7 +1122,7 @@
   SetUpSampleParagraph(&accessible_text);
   base::win::ScopedComPtr<IAccessible2> paragraph;
   ASSERT_HRESULT_SUCCEEDED(
-      accessible_text.QueryInterface(IID_PPV_ARGS(&paragraph)));
+      accessible_text.CopyTo(IID_PPV_ARGS(&paragraph)));
 
   LONG prev_x, prev_y, x, y, width, height;
   base::win::ScopedVariant childid_self(CHILDID_SELF);
@@ -1881,7 +1881,7 @@
   ASSERT_EQ(ROLE_SYSTEM_GRAPHIC, image_role);
 
   base::win::ScopedComPtr<IAccessibleAction> image_action;
-  ASSERT_HRESULT_SUCCEEDED(image.QueryInterface(image_action.Receive()));
+  ASSERT_HRESULT_SUCCEEDED(image.CopyTo(image_action.Receive()));
 
   LONG n_actions = 0;
   EXPECT_HRESULT_SUCCEEDED(image_action->nActions(&n_actions));
@@ -1978,9 +1978,9 @@
   base::win::ScopedComPtr<IAccessibleTable2> table2;
   base::win::ScopedComPtr<IUnknown> cell;
   base::win::ScopedComPtr<IAccessible2> cell1;
-  EXPECT_HRESULT_SUCCEEDED(table.QueryInterface(table2.Receive()));
+  EXPECT_HRESULT_SUCCEEDED(table.CopyTo(table2.Receive()));
   EXPECT_HRESULT_SUCCEEDED(table2->get_cellAt(0, 0, cell.Receive()));
-  EXPECT_HRESULT_SUCCEEDED(cell.QueryInterface(cell1.Receive()));
+  EXPECT_HRESULT_SUCCEEDED(cell.CopyTo(cell1.Receive()));
 
   base::win::ScopedBstr name;
   base::win::ScopedVariant childid_self(CHILDID_SELF);
@@ -1991,7 +1991,7 @@
   EXPECT_EQ(ROLE_SYSTEM_CELL, role);
   EXPECT_HRESULT_SUCCEEDED(cell1->get_accName(childid_self, name.Receive()));
   // EXPECT_STREQ(L"AD", name);
-  EXPECT_HRESULT_SUCCEEDED(cell1.QueryInterface(accessible_cell.Receive()));
+  EXPECT_HRESULT_SUCCEEDED(cell1.CopyTo(accessible_cell.Receive()));
   EXPECT_HRESULT_SUCCEEDED(accessible_cell->get_rowIndex(&row_index));
   EXPECT_HRESULT_SUCCEEDED(accessible_cell->get_columnIndex(&column_index));
   EXPECT_EQ(0, row_index);
@@ -2017,7 +2017,7 @@
   EXPECT_EQ(ROLE_SYSTEM_CELL, role);
   EXPECT_HRESULT_SUCCEEDED(cell2->get_accName(childid_self, name.Receive()));
   // EXPECT_STREQ(L"BC", name);
-  EXPECT_HRESULT_SUCCEEDED(cell2.QueryInterface(accessible_cell.Receive()));
+  EXPECT_HRESULT_SUCCEEDED(cell2.CopyTo(accessible_cell.Receive()));
   EXPECT_HRESULT_SUCCEEDED(accessible_cell->get_rowIndex(&row_index));
   EXPECT_HRESULT_SUCCEEDED(accessible_cell->get_columnIndex(&column_index));
   EXPECT_EQ(0, row_index);
@@ -2037,7 +2037,7 @@
   EXPECT_EQ(ROLE_SYSTEM_CELL, role);
   EXPECT_HRESULT_SUCCEEDED(cell3->get_accName(childid_self, name.Receive()));
   // EXPECT_STREQ(L"EF", name);
-  EXPECT_HRESULT_SUCCEEDED(cell3.QueryInterface(accessible_cell.Receive()));
+  EXPECT_HRESULT_SUCCEEDED(cell3.CopyTo(accessible_cell.Receive()));
   EXPECT_HRESULT_SUCCEEDED(accessible_cell->get_rowIndex(&row_index));
   EXPECT_HRESULT_SUCCEEDED(accessible_cell->get_columnIndex(&column_index));
   EXPECT_EQ(1, row_index);
diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc
index 8fcfa6be..bad00f3 100644
--- a/content/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -222,7 +222,7 @@
   ASSERT_EQ(S_OK, hr);
 
   base::win::ScopedComPtr<IAccessible> text_accessible;
-  hr = text_dispatch.QueryInterface(text_accessible.Receive());
+  hr = text_dispatch.CopyTo(text_accessible.Receive());
   ASSERT_EQ(S_OK, hr);
 
   base::win::ScopedVariant childid_self(CHILDID_SELF);
@@ -254,7 +254,7 @@
       one, text_dispatch.Receive());
   ASSERT_EQ(S_OK, hr);
 
-  hr = text_dispatch.QueryInterface(text_accessible.Receive());
+  hr = text_dispatch.CopyTo(text_accessible.Receive());
   ASSERT_EQ(S_OK, hr);
 
   hr = text_accessible->get_accName(childid_self, name.Receive());
@@ -669,7 +669,7 @@
   // Get the text of the combo box.
   // It should be its value.
   EXPECT_EQ(S_OK, root_obj->get_hyperlink(0, hyperlink.Receive()));
-  EXPECT_EQ(S_OK, hyperlink.QueryInterface(hypertext.Receive()));
+  EXPECT_EQ(S_OK, hyperlink.CopyTo(hypertext.Receive()));
   EXPECT_EQ(S_OK,
             hypertext->get_text(0, IA2_TEXT_OFFSET_LENGTH, text.Receive()));
   EXPECT_STREQ(combo_box_value.c_str(), text);
@@ -680,7 +680,7 @@
   // Get the text of the check box.
   // It should be its name.
   EXPECT_EQ(S_OK, root_obj->get_hyperlink(1, hyperlink.Receive()));
-  EXPECT_EQ(S_OK, hyperlink.QueryInterface(hypertext.Receive()));
+  EXPECT_EQ(S_OK, hyperlink.CopyTo(hypertext.Receive()));
   EXPECT_EQ(S_OK,
             hypertext->get_text(0, IA2_TEXT_OFFSET_LENGTH, text.Receive()));
   EXPECT_STREQ(check_box_name.c_str(), text);
@@ -690,7 +690,7 @@
 
   // Get the text of the button.
   EXPECT_EQ(S_OK, root_obj->get_hyperlink(2, hyperlink.Receive()));
-  EXPECT_EQ(S_OK, hyperlink.QueryInterface(hypertext.Receive()));
+  EXPECT_EQ(S_OK, hyperlink.CopyTo(hypertext.Receive()));
   EXPECT_EQ(S_OK,
             hypertext->get_text(0, IA2_TEXT_OFFSET_LENGTH, text.Receive()));
   EXPECT_STREQ(button_text_name.c_str(), text);
@@ -700,7 +700,7 @@
 
   // Get the text of the link.
   EXPECT_EQ(S_OK, root_obj->get_hyperlink(3, hyperlink.Receive()));
-  EXPECT_EQ(S_OK, hyperlink.QueryInterface(hypertext.Receive()));
+  EXPECT_EQ(S_OK, hyperlink.CopyTo(hypertext.Receive()));
   EXPECT_EQ(S_OK, hypertext->get_text(0, 4, text.Receive()));
   EXPECT_STREQ(link_text_name.c_str(), text);
   text.Reset();
@@ -2419,7 +2419,7 @@
 
   EXPECT_HRESULT_SUCCEEDED(
       describedby_relation->get_target(0, target.Receive()));
-  target.QueryInterface(ax_target.Receive());
+  target.CopyTo(ax_target.Receive());
   EXPECT_HRESULT_SUCCEEDED(ax_target->get_uniqueID(&unique_id));
   EXPECT_EQ(-ax_child1->unique_id(), unique_id);
   ax_target.Reset();
@@ -2427,7 +2427,7 @@
 
   EXPECT_HRESULT_SUCCEEDED(
       describedby_relation->get_target(1, target.Receive()));
-  target.QueryInterface(ax_target.Receive());
+  target.CopyTo(ax_target.Receive());
   EXPECT_HRESULT_SUCCEEDED(ax_target->get_uniqueID(&unique_id));
   EXPECT_EQ(-ax_child2->unique_id(), unique_id);
   ax_target.Reset();
@@ -2450,7 +2450,7 @@
 
   EXPECT_HRESULT_SUCCEEDED(
       description_for_relation->get_target(0, target.Receive()));
-  target.QueryInterface(ax_target.Receive());
+  target.CopyTo(ax_target.Receive());
   EXPECT_HRESULT_SUCCEEDED(ax_target->get_uniqueID(&unique_id));
   EXPECT_EQ(-ax_root->unique_id(), unique_id);
   ax_target.Reset();
@@ -2472,7 +2472,7 @@
 
   EXPECT_HRESULT_SUCCEEDED(
       description_for_relation->get_target(0, target.Receive()));
-  target.QueryInterface(ax_target.Receive());
+  target.CopyTo(ax_target.Receive());
   EXPECT_HRESULT_SUCCEEDED(ax_target->get_uniqueID(&unique_id));
   EXPECT_EQ(-ax_root->unique_id(), unique_id);
   ax_target.Reset();
diff --git a/content/browser/browser_main_runner.cc b/content/browser/browser_main_runner.cc
index 0d986c0..2499e1b 100644
--- a/content/browser/browser_main_runner.cc
+++ b/content/browser/browser_main_runner.cc
@@ -14,6 +14,7 @@
 #include "base/metrics/statistics_recorder.h"
 #include "base/profiler/scoped_profile.h"
 #include "base/profiler/scoped_tracker.h"
+#include "base/run_loop.h"
 #include "base/time/time.h"
 #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
 #include "base/trace_event/trace_event.h"
@@ -207,7 +208,7 @@
       // Forcefully terminates the RunLoop inside MessagePumpForUI, ensuring
       // proper shutdown for content_browsertests. Shutdown() is not used by
       // the actual browser.
-      if (base::MessageLoop::current()->is_running())
+      if (base::RunLoop::IsRunningOnCurrentThread())
         base::MessageLoop::current()->QuitNow();
   #endif
       main_loop_.reset(NULL);
diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc
index 2cd2eff..b1b96b7 100644
--- a/content/browser/browser_thread_impl.cc
+++ b/content/browser/browser_thread_impl.cc
@@ -218,7 +218,7 @@
       identifier_ == BrowserThread::PROCESS_LAUNCHER ||
       identifier_ == BrowserThread::CACHE) {
     // Nesting and task observers are not allowed on redirected threads.
-    message_loop()->DisallowNesting();
+    base::RunLoop::DisallowNestingOnCurrentThread();
     message_loop()->DisallowTaskObservers();
   }
 
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index bd2747b..7c618b6 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -661,6 +661,8 @@
       "media/webrtc/rtc_rtp_contributing_source.h",
       "media/webrtc/rtc_rtp_receiver.cc",
       "media/webrtc/rtc_rtp_receiver.h",
+      "media/webrtc/rtc_rtp_sender.cc",
+      "media/webrtc/rtc_rtp_sender.h",
       "media/webrtc/rtc_stats.cc",
       "media/webrtc/rtc_stats.h",
       "media/webrtc/stun_field_trial.cc",
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc
index 46194b1..86939123 100644
--- a/content/renderer/media/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -30,6 +30,7 @@
 #include "content/renderer/media/rtc_dtmf_sender_handler.h"
 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
 #include "content/renderer/media/webrtc/rtc_rtp_receiver.h"
+#include "content/renderer/media/webrtc/rtc_rtp_sender.h"
 #include "content/renderer/media/webrtc/rtc_stats.h"
 #include "content/renderer/media/webrtc/webrtc_media_stream_adapter.h"
 #include "content/renderer/media/webrtc_audio_device_impl.h"
@@ -44,6 +45,7 @@
 #include "third_party/WebKit/public/platform/WebRTCICECandidate.h"
 #include "third_party/WebKit/public/platform/WebRTCLegacyStats.h"
 #include "third_party/WebKit/public/platform/WebRTCOfferOptions.h"
+#include "third_party/WebKit/public/platform/WebRTCRtpSender.h"
 #include "third_party/WebKit/public/platform/WebRTCSessionDescription.h"
 #include "third_party/WebKit/public/platform/WebRTCSessionDescriptionRequest.h"
 #include "third_party/WebKit/public/platform/WebRTCVoidRequest.h"
@@ -1651,6 +1653,47 @@
           base::Passed(&callback)));
 }
 
+blink::WebVector<std::unique_ptr<blink::WebRTCRtpSender>>
+RTCPeerConnectionHandler::GetSenders() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::getSenders");
+  std::vector<rtc::scoped_refptr<webrtc::RtpSenderInterface>> webrtc_senders =
+      native_peer_connection_->GetSenders();
+  blink::WebVector<std::unique_ptr<blink::WebRTCRtpSender>> web_senders(
+      webrtc_senders.size());
+  for (size_t i = 0; i < web_senders.size(); ++i) {
+    rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track =
+        webrtc_senders[i]->track();
+    std::unique_ptr<blink::WebMediaStreamTrack> web_track;
+
+    if (webrtc_track) {
+      std::string track_id = webrtc_track->id();
+      bool is_audio_track = (webrtc_track->kind() ==
+                             webrtc::MediaStreamTrackInterface::kAudioKind);
+      for (const auto& stream_adapter : local_streams_) {
+        blink::WebVector<blink::WebMediaStreamTrack> tracks;
+        if (is_audio_track)
+          stream_adapter->web_stream().AudioTracks(tracks);
+        else
+          stream_adapter->web_stream().VideoTracks(tracks);
+        for (const blink::WebMediaStreamTrack& track : tracks) {
+          if (track.Id() == track_id.c_str()) {
+            web_track.reset(new blink::WebMediaStreamTrack(track));
+            break;
+          }
+        }
+        if (web_track)
+          break;
+      }
+      DCHECK(web_track);
+    }
+
+    web_senders[i] = base::MakeUnique<RTCRtpSender>(webrtc_senders[i].get(),
+                                                    std::move(web_track));
+  }
+  return web_senders;
+}
+
 blink::WebVector<std::unique_ptr<blink::WebRTCRtpReceiver>>
 RTCPeerConnectionHandler::GetReceivers() {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/content/renderer/media/rtc_peer_connection_handler.h b/content/renderer/media/rtc_peer_connection_handler.h
index 3595db8..dfa37cc 100644
--- a/content/renderer/media/rtc_peer_connection_handler.h
+++ b/content/renderer/media/rtc_peer_connection_handler.h
@@ -147,6 +147,8 @@
   void GetStats(const blink::WebRTCStatsRequest& request) override;
   void GetStats(
       std::unique_ptr<blink::WebRTCStatsReportCallback> callback) override;
+  blink::WebVector<std::unique_ptr<blink::WebRTCRtpSender>> GetSenders()
+      override;
   blink::WebVector<std::unique_ptr<blink::WebRTCRtpReceiver>> GetReceivers()
       override;
   blink::WebRTCDataChannelHandler* CreateDataChannel(
diff --git a/content/renderer/media/webrtc/rtc_rtp_sender.cc b/content/renderer/media/webrtc/rtc_rtp_sender.cc
new file mode 100644
index 0000000..2d61389
--- /dev/null
+++ b/content/renderer/media/webrtc/rtc_rtp_sender.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 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 "content/renderer/media/webrtc/rtc_rtp_sender.h"
+
+#include "base/logging.h"
+#include "third_party/webrtc/base/scoped_ref_ptr.h"
+
+namespace content {
+
+namespace {
+
+inline bool operator==(
+    const std::unique_ptr<blink::WebMediaStreamTrack>& web_track,
+    const webrtc::MediaStreamTrackInterface* webrtc_track) {
+  if (!web_track)
+    return !webrtc_track;
+  return webrtc_track && web_track->Id() == webrtc_track->id().c_str();
+}
+
+}  // namespace
+
+uintptr_t RTCRtpSender::getId(
+    const webrtc::RtpSenderInterface* webrtc_rtp_sender) {
+  return reinterpret_cast<uintptr_t>(webrtc_rtp_sender);
+}
+
+RTCRtpSender::RTCRtpSender(
+    webrtc::RtpSenderInterface* webrtc_rtp_sender,
+    std::unique_ptr<blink::WebMediaStreamTrack> web_track)
+    : webrtc_rtp_sender_(webrtc_rtp_sender), web_track_(std::move(web_track)) {
+  DCHECK(webrtc_rtp_sender_);
+  DCHECK(web_track_ == webrtc_track());
+}
+
+RTCRtpSender::~RTCRtpSender() {}
+
+uintptr_t RTCRtpSender::Id() const {
+  return getId(webrtc_rtp_sender_.get());
+}
+
+const blink::WebMediaStreamTrack* RTCRtpSender::Track() const {
+  DCHECK(web_track_ == webrtc_track());
+  return web_track_.get();
+}
+
+const webrtc::MediaStreamTrackInterface* RTCRtpSender::webrtc_track() const {
+  return webrtc_rtp_sender_->track();
+}
+
+}  // namespace content
diff --git a/content/renderer/media/webrtc/rtc_rtp_sender.h b/content/renderer/media/webrtc/rtc_rtp_sender.h
new file mode 100644
index 0000000..716e0b0
--- /dev/null
+++ b/content/renderer/media/webrtc/rtc_rtp_sender.h
@@ -0,0 +1,39 @@
+// Copyright (c) 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.
+
+#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_RTC_RTP_SENDER_H_
+#define CONTENT_RENDERER_MEDIA_WEBRTC_RTC_RTP_SENDER_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebRTCRtpSender.h"
+#include "third_party/webrtc/api/rtpsenderinterface.h"
+
+namespace content {
+
+// Used to surface |webrtc::RtpSenderInterface| to blink. Multiple
+// |RTCRtpSender|s could reference the same webrtc receiver; |id| is the value
+// of the pointer to the webrtc sender.
+class CONTENT_EXPORT RTCRtpSender : public blink::WebRTCRtpSender {
+ public:
+  static uintptr_t getId(const webrtc::RtpSenderInterface* webrtc_rtp_sender);
+
+  RTCRtpSender(webrtc::RtpSenderInterface* webrtc_rtp_sender,
+               std::unique_ptr<blink::WebMediaStreamTrack> web_track);
+  ~RTCRtpSender() override;
+
+  uintptr_t Id() const override;
+  const blink::WebMediaStreamTrack* Track() const override;
+
+  const webrtc::MediaStreamTrackInterface* webrtc_track() const;
+
+ private:
+  const scoped_refptr<webrtc::RtpSenderInterface> webrtc_rtp_sender_;
+  std::unique_ptr<blink::WebMediaStreamTrack> web_track_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MEDIA_WEBRTC_RTC_RTP_SENDER_H_
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_adapter.h b/content/renderer/media/webrtc/webrtc_media_stream_adapter.h
index 4680cff..7b7816e9 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_adapter.h
+++ b/content/renderer/media/webrtc/webrtc_media_stream_adapter.h
@@ -44,6 +44,8 @@
     return webrtc_media_stream_.get();
   }
 
+  const blink::WebMediaStream& web_stream() const { return web_stream_; }
+
  protected:
   // MediaStreamObserver implementation.
   void TrackAdded(const blink::WebMediaStreamTrack& track) override;
diff --git a/content/shell/test_runner/mock_webrtc_peer_connection_handler.cc b/content/shell/test_runner/mock_webrtc_peer_connection_handler.cc
index e4988a4..61082718 100644
--- a/content/shell/test_runner/mock_webrtc_peer_connection_handler.cc
+++ b/content/shell/test_runner/mock_webrtc_peer_connection_handler.cc
@@ -26,6 +26,7 @@
 #include "third_party/WebKit/public/platform/WebRTCPeerConnectionHandlerClient.h"
 #include "third_party/WebKit/public/platform/WebRTCRtpContributingSource.h"
 #include "third_party/WebKit/public/platform/WebRTCRtpReceiver.h"
+#include "third_party/WebKit/public/platform/WebRTCRtpSender.h"
 #include "third_party/WebKit/public/platform/WebRTCStatsResponse.h"
 #include "third_party/WebKit/public/platform/WebRTCVoidRequest.h"
 #include "third_party/WebKit/public/platform/WebString.h"
@@ -37,13 +38,12 @@
 
 namespace {
 
-uintptr_t GetReceiverIDByTrack(
-    const std::string& track_id,
-    std::map<std::string, uintptr_t>* receiver_id_by_track) {
-  const auto& it = receiver_id_by_track->find(track_id);
-  if (it == receiver_id_by_track->end()) {
-    uintptr_t id = static_cast<uintptr_t>(receiver_id_by_track->size()) + 1;
-    receiver_id_by_track->insert(std::make_pair(track_id, id));
+uintptr_t GetIDByTrack(const std::string& track_id,
+                       std::map<std::string, uintptr_t>* id_by_track) {
+  const auto& it = id_by_track->find(track_id);
+  if (it == id_by_track->end()) {
+    uintptr_t id = static_cast<uintptr_t>(id_by_track->size()) + 1;
+    id_by_track->insert(std::make_pair(track_id, id));
     return id;
   }
   return it->second;
@@ -240,6 +240,22 @@
   size_t i_;
 };
 
+class MockWebRTCRtpSender : public blink::WebRTCRtpSender {
+ public:
+  MockWebRTCRtpSender(uintptr_t id,
+                      std::unique_ptr<blink::WebMediaStreamTrack> track)
+      : id_(id), track_(std::move(track)) {}
+
+  uintptr_t Id() const override { return id_; }
+  const blink::WebMediaStreamTrack* Track() const override {
+    return track_.get();
+  }
+
+ private:
+  uintptr_t id_;
+  std::unique_ptr<blink::WebMediaStreamTrack> track_;
+};
+
 class MockWebRTCRtpContributingSource
     : public blink::WebRTCRtpContributingSource {
  public:
@@ -619,6 +635,35 @@
       std::unique_ptr<blink::WebRTCStatsReport>(report.release()));
 }
 
+blink::WebVector<std::unique_ptr<blink::WebRTCRtpSender>>
+MockWebRTCPeerConnectionHandler::GetSenders() {
+  std::vector<std::unique_ptr<blink::WebRTCRtpSender>> senders;
+  for (const auto& pair : local_streams_) {
+    const auto& local_stream = pair.second;
+    blink::WebVector<blink::WebMediaStreamTrack> local_tracks;
+    local_stream.AudioTracks(local_tracks);
+    for (const auto& local_track : local_tracks) {
+      senders.push_back(
+          std::unique_ptr<blink::WebRTCRtpSender>(new MockWebRTCRtpSender(
+              GetIDByTrack(local_track.Id().Utf8(), &id_by_track_),
+              base::MakeUnique<WebMediaStreamTrack>(local_track))));
+    }
+    local_stream.VideoTracks(local_tracks);
+    for (const auto& local_track : local_tracks) {
+      senders.push_back(
+          std::unique_ptr<blink::WebRTCRtpSender>(new MockWebRTCRtpSender(
+              GetIDByTrack(local_track.Id().Utf8(), &id_by_track_),
+              base::MakeUnique<WebMediaStreamTrack>(local_track))));
+    }
+  }
+  blink::WebVector<std::unique_ptr<blink::WebRTCRtpSender>> web_vector(
+      senders.size());
+  for (size_t i = 0; i < senders.size(); ++i) {
+    web_vector[i] = std::move(senders[i]);
+  }
+  return web_vector;
+}
+
 blink::WebVector<std::unique_ptr<blink::WebRTCRtpReceiver>>
 MockWebRTCPeerConnectionHandler::GetReceivers() {
   std::vector<std::unique_ptr<blink::WebRTCRtpReceiver>> receivers;
@@ -629,16 +674,14 @@
     for (const auto& remote_track : remote_tracks) {
       receivers.push_back(
           std::unique_ptr<blink::WebRTCRtpReceiver>(new MockWebRTCRtpReceiver(
-              GetReceiverIDByTrack(remote_track.Id().Utf8(),
-                                   &receiver_id_by_track_),
+              GetIDByTrack(remote_track.Id().Utf8(), &id_by_track_),
               remote_track)));
     }
     remote_stream.VideoTracks(remote_tracks);
     for (const auto& remote_track : remote_tracks) {
       receivers.push_back(
           std::unique_ptr<blink::WebRTCRtpReceiver>(new MockWebRTCRtpReceiver(
-              GetReceiverIDByTrack(remote_track.Id().Utf8(),
-                                   &receiver_id_by_track_),
+              GetIDByTrack(remote_track.Id().Utf8(), &id_by_track_),
               remote_track)));
     }
   }
diff --git a/content/shell/test_runner/mock_webrtc_peer_connection_handler.h b/content/shell/test_runner/mock_webrtc_peer_connection_handler.h
index e1ceca8d..415bee21 100644
--- a/content/shell/test_runner/mock_webrtc_peer_connection_handler.h
+++ b/content/shell/test_runner/mock_webrtc_peer_connection_handler.h
@@ -61,6 +61,8 @@
   void RemoveStream(const blink::WebMediaStream& stream) override;
   void GetStats(const blink::WebRTCStatsRequest& request) override;
   void GetStats(std::unique_ptr<blink::WebRTCStatsReportCallback>) override;
+  blink::WebVector<std::unique_ptr<blink::WebRTCRtpSender>> GetSenders()
+      override;
   blink::WebVector<std::unique_ptr<blink::WebRTCRtpReceiver>> GetReceivers()
       override;
   blink::WebRTCDataChannelHandler* CreateDataChannel(
@@ -99,7 +101,7 @@
   typedef std::map<std::string, blink::WebMediaStream> StreamMap;
   StreamMap local_streams_;
   StreamMap remote_streams_;
-  std::map<std::string, uintptr_t> receiver_id_by_track_;
+  std::map<std::string, uintptr_t> id_by_track_;
 
   base::WeakPtrFactory<MockWebRTCPeerConnectionHandler> weak_factory_;
 
diff --git a/device/bluetooth/bluez/bluetooth_adapter_profile_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_adapter_profile_bluez_unittest.cc
index 779e9b70..bc8d0c1 100644
--- a/device/bluetooth/bluez/bluetooth_adapter_profile_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_adapter_profile_bluez_unittest.cc
@@ -78,10 +78,8 @@
 
   void AdapterCallback(scoped_refptr<BluetoothAdapter> adapter) {
     adapter_ = adapter;
-    if (base::MessageLoop::current() &&
-        base::MessageLoop::current()->is_running()) {
+    if (base::RunLoop::IsRunningOnCurrentThread())
       base::MessageLoop::current()->QuitWhenIdle();
-    }
   }
 
   class FakeDelegate : public bluez::BluetoothProfileServiceProvider::Delegate {
diff --git a/device/bluetooth/bluez/bluetooth_advertisement_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_advertisement_bluez_unittest.cc
index 1d220053..3c7addf 100644
--- a/device/bluetooth/bluez/bluetooth_advertisement_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_advertisement_bluez_unittest.cc
@@ -93,10 +93,8 @@
     adapter_ = adapter;
     ASSERT_NE(adapter_.get(), nullptr);
     ASSERT_TRUE(adapter_->IsInitialized());
-    if (base::MessageLoop::current() &&
-        base::MessageLoop::current()->is_running()) {
+    if (base::RunLoop::IsRunningOnCurrentThread())
       base::MessageLoop::current()->QuitWhenIdle();
-    }
   }
 
   std::unique_ptr<BluetoothAdvertisement::Data> CreateAdvertisementData() {
diff --git a/device/bluetooth/bluez/bluetooth_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
index 74d8801..6632d54 100644
--- a/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
@@ -164,10 +164,8 @@
   // Some tests use a message loop since background processing is simulated;
   // break out of those loops.
   void QuitMessageLoop() {
-    if (base::MessageLoop::current() &&
-        base::MessageLoop::current()->is_running()) {
+    if (base::RunLoop::IsRunningOnCurrentThread())
       base::MessageLoop::current()->QuitWhenIdle();
-    }
   }
 };
 
@@ -362,10 +360,8 @@
   // Some tests use a message loop since background processing is simulated;
   // break out of those loops.
   void QuitMessageLoop() {
-    if (base::MessageLoop::current() &&
-        base::MessageLoop::current()->is_running()) {
+    if (base::RunLoop::IsRunningOnCurrentThread())
       base::MessageLoop::current()->QuitWhenIdle();
-    }
   }
 };
 const char BluetoothBlueZTest::kGapUuid[] =
diff --git a/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc
index 30eed1b..fb0a052 100644
--- a/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc
@@ -238,10 +238,8 @@
 
   void AdapterCallback(scoped_refptr<BluetoothAdapter> adapter) {
     adapter_ = adapter;
-    if (base::MessageLoop::current() &&
-        base::MessageLoop::current()->is_running()) {
+    if (base::RunLoop::IsRunningOnCurrentThread())
       base::MessageLoop::current()->QuitWhenIdle();
-    }
   }
 
   void SuccessCallback() { ++success_callback_count_; }
@@ -281,8 +279,7 @@
 
  protected:
   void QuitMessageLoop() {
-    if (base::MessageLoop::current() &&
-        base::MessageLoop::current()->is_running())
+    if (base::RunLoop::IsRunningOnCurrentThread())
       base::MessageLoop::current()->QuitWhenIdle();
   }
 
diff --git a/device/bluetooth/bluez/bluetooth_socket_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_socket_bluez_unittest.cc
index 74ac10a..d536eb08 100644
--- a/device/bluetooth/bluez/bluetooth_socket_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_socket_bluez_unittest.cc
@@ -81,10 +81,13 @@
     BluetoothSocketThread::Get();
 
     // Grab a pointer to the adapter.
-    device::BluetoothAdapterFactory::GetAdapter(base::Bind(
-        &BluetoothSocketBlueZTest::AdapterCallback, base::Unretained(this)));
-
-    base::RunLoop().Run();
+    {
+      base::RunLoop run_loop;
+      device::BluetoothAdapterFactory::GetAdapter(
+          base::Bind(&BluetoothSocketBlueZTest::AdapterCallback,
+                     base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+      run_loop.Run();
+    }
 
     ASSERT_TRUE(adapter_.get() != nullptr);
     ASSERT_TRUE(adapter_->IsInitialized());
@@ -102,74 +105,69 @@
     bluez::BluezDBusManager::Shutdown();
   }
 
-  void AdapterCallback(scoped_refptr<BluetoothAdapter> adapter) {
+  void AdapterCallback(base::OnceClosure continuation,
+                       scoped_refptr<BluetoothAdapter> adapter) {
     adapter_ = adapter;
-    if (base::MessageLoop::current() &&
-        base::MessageLoop::current()->is_running()) {
-      base::MessageLoop::current()->QuitWhenIdle();
-    }
+    std::move(continuation).Run();
   }
 
-  void SuccessCallback() {
+  void SuccessCallback(base::OnceClosure continuation) {
     ++success_callback_count_;
-    message_loop_.QuitWhenIdle();
+    std::move(continuation).Run();
   }
 
-  void ErrorCallback(const std::string& message) {
+  void ErrorCallback(base::OnceClosure continuation,
+                     const std::string& message) {
     ++error_callback_count_;
     last_message_ = message;
-
-    if (message_loop_.is_running())
-      message_loop_.QuitWhenIdle();
+    std::move(continuation).Run();
   }
 
-  void ConnectToServiceSuccessCallback(scoped_refptr<BluetoothSocket> socket) {
+  void ConnectToServiceSuccessCallback(base::OnceClosure continuation,
+                                       scoped_refptr<BluetoothSocket> socket) {
     ++success_callback_count_;
     last_socket_ = socket;
-
-    message_loop_.QuitWhenIdle();
+    std::move(continuation).Run();
   }
 
-  void SendSuccessCallback(int bytes_sent) {
+  void SendSuccessCallback(base::OnceClosure continuation, int bytes_sent) {
     ++success_callback_count_;
     last_bytes_sent_ = bytes_sent;
-
-    message_loop_.QuitWhenIdle();
+    std::move(continuation).Run();
   }
 
-  void ReceiveSuccessCallback(int bytes_received,
+  void ReceiveSuccessCallback(base::OnceClosure continuation,
+                              int bytes_received,
                               scoped_refptr<net::IOBuffer> io_buffer) {
     ++success_callback_count_;
     last_bytes_received_ = bytes_received;
     last_io_buffer_ = io_buffer;
-
-    message_loop_.QuitWhenIdle();
+    std::move(continuation).Run();
   }
 
-  void ReceiveErrorCallback(BluetoothSocket::ErrorReason reason,
+  void ReceiveErrorCallback(base::OnceClosure continuation,
+                            BluetoothSocket::ErrorReason reason,
                             const std::string& error_message) {
     ++error_callback_count_;
     last_reason_ = reason;
     last_message_ = error_message;
-
-    message_loop_.QuitWhenIdle();
+    std::move(continuation).Run();
   }
 
-  void CreateServiceSuccessCallback(scoped_refptr<BluetoothSocket> socket) {
+  void CreateServiceSuccessCallback(base::OnceClosure continuation,
+                                    scoped_refptr<BluetoothSocket> socket) {
     ++success_callback_count_;
     last_socket_ = socket;
-
-    if (message_loop_.is_running())
-      message_loop_.QuitWhenIdle();
+    std::move(continuation).Run();
   }
 
-  void AcceptSuccessCallback(const BluetoothDevice* device,
+  void AcceptSuccessCallback(base::OnceClosure continuation,
+                             const BluetoothDevice* device,
                              scoped_refptr<BluetoothSocket> socket) {
     ++success_callback_count_;
     last_device_ = device;
     last_socket_ = socket;
-
-    message_loop_.QuitWhenIdle();
+    std::move(continuation).Run();
   }
 
   void ImmediateSuccessCallback() { ++success_callback_count_; }
@@ -197,13 +195,16 @@
       bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress);
   ASSERT_TRUE(device != nullptr);
 
-  device->ConnectToService(
-      BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
-      base::Bind(&BluetoothSocketBlueZTest::ConnectToServiceSuccessCallback,
-                 base::Unretained(this)),
-      base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
-                 base::Unretained(this)));
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    device->ConnectToService(
+        BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
+        base::Bind(&BluetoothSocketBlueZTest::ConnectToServiceSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
   EXPECT_EQ(0U, error_callback_count_);
@@ -219,12 +220,16 @@
   scoped_refptr<net::StringIOBuffer> write_buffer(
       new net::StringIOBuffer("test"));
 
-  socket->Send(write_buffer.get(), write_buffer->size(),
-               base::Bind(&BluetoothSocketBlueZTest::SendSuccessCallback,
-                          base::Unretained(this)),
-               base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
-                          base::Unretained(this)));
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    socket->Send(
+        write_buffer.get(), write_buffer->size(),
+        base::Bind(&BluetoothSocketBlueZTest::SendSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
   EXPECT_EQ(0U, error_callback_count_);
@@ -235,12 +240,16 @@
 
   // Receive data from the socket, and fetch the buffer from the callback; since
   // the fake is an echo server, we expect to receive what we wrote.
-  socket->Receive(4096,
-                  base::Bind(&BluetoothSocketBlueZTest::ReceiveSuccessCallback,
-                             base::Unretained(this)),
-                  base::Bind(&BluetoothSocketBlueZTest::ReceiveErrorCallback,
-                             base::Unretained(this)));
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    socket->Receive(
+        4096,
+        base::Bind(&BluetoothSocketBlueZTest::ReceiveSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ReceiveErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
   EXPECT_EQ(0U, error_callback_count_);
@@ -260,12 +269,16 @@
 
   // Receive data again; the socket will have been closed, this should cause a
   // disconnected error to be returned via the error callback.
-  socket->Receive(4096,
-                  base::Bind(&BluetoothSocketBlueZTest::ReceiveSuccessCallback,
-                             base::Unretained(this)),
-                  base::Bind(&BluetoothSocketBlueZTest::ReceiveErrorCallback,
-                             base::Unretained(this)));
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    socket->Receive(
+        4096,
+        base::Bind(&BluetoothSocketBlueZTest::ReceiveSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ReceiveErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(0U, success_callback_count_);
   EXPECT_EQ(1U, error_callback_count_);
@@ -279,12 +292,16 @@
   // equivalent to the connection reset error.
   write_buffer = new net::StringIOBuffer("second test");
 
-  socket->Send(write_buffer.get(), write_buffer->size(),
-               base::Bind(&BluetoothSocketBlueZTest::SendSuccessCallback,
-                          base::Unretained(this)),
-               base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
-                          base::Unretained(this)));
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    socket->Send(
+        write_buffer.get(), write_buffer->size(),
+        base::Bind(&BluetoothSocketBlueZTest::SendSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(0U, success_callback_count_);
   EXPECT_EQ(1U, error_callback_count_);
@@ -294,23 +311,28 @@
   error_callback_count_ = 0;
 
   // Close our end of the socket.
-  socket->Disconnect(base::Bind(&BluetoothSocketBlueZTest::SuccessCallback,
-                                base::Unretained(this)));
-
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    socket->Disconnect(base::Bind(&BluetoothSocketBlueZTest::SuccessCallback,
+                                  base::Unretained(this),
+                                  run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
   EXPECT_EQ(1U, success_callback_count_);
 }
 
 TEST_F(BluetoothSocketBlueZTest, Listen) {
-  adapter_->CreateRfcommService(
-      BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
-      BluetoothAdapter::ServiceOptions(),
-      base::Bind(&BluetoothSocketBlueZTest::CreateServiceSuccessCallback,
-                 base::Unretained(this)),
-      base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
-                 base::Unretained(this)));
-
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    adapter_->CreateRfcommService(
+        BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
+        BluetoothAdapter::ServiceOptions(),
+        base::Bind(&BluetoothSocketBlueZTest::CreateServiceSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
   EXPECT_EQ(0U, error_callback_count_);
@@ -334,20 +356,23 @@
   BluetoothDevice* device = adapter_->GetDevice(
       bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress);
   ASSERT_TRUE(device != nullptr);
-  fake_bluetooth_device_client->ConnectProfile(
-      static_cast<BluetoothDeviceBlueZ*>(device)->object_path(),
-      bluez::FakeBluetoothProfileManagerClient::kRfcommUuid,
-      base::Bind(&base::DoNothing), base::Bind(&DoNothingDBusErrorCallback));
-
-  base::RunLoop().RunUntilIdle();
-
-  server_socket->Accept(
-      base::Bind(&BluetoothSocketBlueZTest::AcceptSuccessCallback,
-                 base::Unretained(this)),
-      base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
-                 base::Unretained(this)));
-
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    fake_bluetooth_device_client->ConnectProfile(
+        static_cast<BluetoothDeviceBlueZ*>(device)->object_path(),
+        bluez::FakeBluetoothProfileManagerClient::kRfcommUuid,
+        base::Bind(&base::DoNothing), base::Bind(&DoNothingDBusErrorCallback));
+    run_loop.RunUntilIdle();
+  }
+  {
+    base::RunLoop run_loop;
+    server_socket->Accept(
+        base::Bind(&BluetoothSocketBlueZTest::AcceptSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
   EXPECT_EQ(0U, error_callback_count_);
@@ -360,10 +385,13 @@
   error_callback_count_ = 0;
 
   // Close our end of the client socket.
-  client_socket->Disconnect(base::Bind(
-      &BluetoothSocketBlueZTest::SuccessCallback, base::Unretained(this)));
-
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    client_socket->Disconnect(
+        base::Bind(&BluetoothSocketBlueZTest::SuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
   client_socket = nullptr;
@@ -372,20 +400,25 @@
 
   // Run a second connection test, this time calling Accept() before the
   // incoming connection comes in.
-  server_socket->Accept(
-      base::Bind(&BluetoothSocketBlueZTest::AcceptSuccessCallback,
-                 base::Unretained(this)),
-      base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
-                 base::Unretained(this)));
+  {
+    base::RunLoop run_loop1;
+    // |run_loop2| is expected to be quit in ConnectProfile() through the quit
+    // closures saved in the Accept() call.
+    base::RunLoop run_loop2;
 
-  base::RunLoop().RunUntilIdle();
+    server_socket->Accept(
+        base::Bind(&BluetoothSocketBlueZTest::AcceptSuccessCallback,
+                   base::Unretained(this), run_loop2.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
+                   base::Unretained(this), run_loop2.QuitWhenIdleClosure()));
+    run_loop1.RunUntilIdle();
 
-  fake_bluetooth_device_client->ConnectProfile(
-      static_cast<BluetoothDeviceBlueZ*>(device)->object_path(),
-      bluez::FakeBluetoothProfileManagerClient::kRfcommUuid,
-      base::Bind(&base::DoNothing), base::Bind(&DoNothingDBusErrorCallback));
-
-  base::RunLoop().Run();
+    fake_bluetooth_device_client->ConnectProfile(
+        static_cast<BluetoothDeviceBlueZ*>(device)->object_path(),
+        bluez::FakeBluetoothProfileManagerClient::kRfcommUuid,
+        base::Bind(&base::DoNothing), base::Bind(&DoNothingDBusErrorCallback));
+    run_loop2.Run();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
   EXPECT_EQ(0U, error_callback_count_);
@@ -398,10 +431,13 @@
   error_callback_count_ = 0;
 
   // Close our end of the client socket.
-  client_socket->Disconnect(base::Bind(
-      &BluetoothSocketBlueZTest::SuccessCallback, base::Unretained(this)));
-
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    client_socket->Disconnect(
+        base::Bind(&BluetoothSocketBlueZTest::SuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
   client_socket = nullptr;
@@ -409,11 +445,13 @@
   error_callback_count_ = 0;
 
   // Now close the server socket.
-  server_socket->Disconnect(
-      base::Bind(&BluetoothSocketBlueZTest::ImmediateSuccessCallback,
-                 base::Unretained(this)));
-
-  base::RunLoop().RunUntilIdle();
+  {
+    base::RunLoop run_loop;
+    server_socket->Disconnect(
+        base::Bind(&BluetoothSocketBlueZTest::ImmediateSuccessCallback,
+                   base::Unretained(this)));
+    run_loop.RunUntilIdle();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
 }
@@ -426,14 +464,17 @@
           bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient());
   fake_bluetooth_adapter_client->SetVisible(false);
 
-  adapter_->CreateRfcommService(
-      BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
-      BluetoothAdapter::ServiceOptions(),
-      base::Bind(&BluetoothSocketBlueZTest::CreateServiceSuccessCallback,
-                 base::Unretained(this)),
-      base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
-                 base::Unretained(this)));
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    adapter_->CreateRfcommService(
+        BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
+        BluetoothAdapter::ServiceOptions(),
+        base::Bind(&BluetoothSocketBlueZTest::CreateServiceSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
   EXPECT_EQ(0U, error_callback_count_);
@@ -457,9 +498,11 @@
   EXPECT_TRUE(profile_service_provider == nullptr);
 
   // Make the adapter visible. This should register a profile.
-  fake_bluetooth_adapter_client->SetVisible(true);
-
-  base::RunLoop().RunUntilIdle();
+  {
+    base::RunLoop run_loop;
+    fake_bluetooth_adapter_client->SetVisible(true);
+    run_loop.RunUntilIdle();
+  }
 
   profile_service_provider =
       fake_bluetooth_profile_manager_client->GetProfileServiceProvider(
@@ -467,11 +510,13 @@
   EXPECT_TRUE(profile_service_provider != nullptr);
 
   // Cleanup the socket.
-  socket->Disconnect(
-      base::Bind(&BluetoothSocketBlueZTest::ImmediateSuccessCallback,
-                 base::Unretained(this)));
-
-  base::RunLoop().RunUntilIdle();
+  {
+    base::RunLoop run_loop;
+    socket->Disconnect(
+        base::Bind(&BluetoothSocketBlueZTest::ImmediateSuccessCallback,
+                   base::Unretained(this)));
+    run_loop.RunUntilIdle();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
 }
@@ -482,14 +527,17 @@
       static_cast<bluez::FakeBluetoothAdapterClient*>(
           bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient());
 
-  adapter_->CreateRfcommService(
-      BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
-      BluetoothAdapter::ServiceOptions(),
-      base::Bind(&BluetoothSocketBlueZTest::CreateServiceSuccessCallback,
-                 base::Unretained(this)),
-      base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
-                 base::Unretained(this)));
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    adapter_->CreateRfcommService(
+        BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
+        BluetoothAdapter::ServiceOptions(),
+        base::Bind(&BluetoothSocketBlueZTest::CreateServiceSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
   EXPECT_EQ(0U, error_callback_count_);
@@ -514,14 +562,18 @@
 
   // Make the adapter invisible, and fiddle with the profile fake to unregister
   // the profile since this doesn't happen automatically.
-  fake_bluetooth_adapter_client->SetVisible(false);
-
-  base::RunLoop().RunUntilIdle();
+  {
+    base::RunLoop run_loop;
+    fake_bluetooth_adapter_client->SetVisible(false);
+    run_loop.RunUntilIdle();
+  }
 
   // Then make the adapter visible again. This should re-register the profile.
-  fake_bluetooth_adapter_client->SetVisible(true);
-
-  base::RunLoop().RunUntilIdle();
+  {
+    base::RunLoop run_loop;
+    fake_bluetooth_adapter_client->SetVisible(true);
+    run_loop.RunUntilIdle();
+  }
 
   profile_service_provider =
       fake_bluetooth_profile_manager_client->GetProfileServiceProvider(
@@ -529,11 +581,13 @@
   EXPECT_TRUE(profile_service_provider != nullptr);
 
   // Cleanup the socket.
-  socket->Disconnect(
-      base::Bind(&BluetoothSocketBlueZTest::ImmediateSuccessCallback,
-                 base::Unretained(this)));
-
-  base::RunLoop().RunUntilIdle();
+  {
+    base::RunLoop run_loop;
+    socket->Disconnect(
+        base::Bind(&BluetoothSocketBlueZTest::ImmediateSuccessCallback,
+                   base::Unretained(this)));
+    run_loop.RunUntilIdle();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
 }
@@ -543,25 +597,31 @@
       bluez::FakeBluetoothDeviceClient::kPairedUnconnectableDeviceAddress);
   ASSERT_TRUE(device != nullptr);
 
-  device->ConnectToService(
-      BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
-      base::Bind(&BluetoothSocketBlueZTest::ConnectToServiceSuccessCallback,
-                 base::Unretained(this)),
-      base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
-                 base::Unretained(this)));
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    device->ConnectToService(
+        BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
+        base::Bind(&BluetoothSocketBlueZTest::ConnectToServiceSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(0U, success_callback_count_);
   EXPECT_EQ(1U, error_callback_count_);
   EXPECT_TRUE(last_socket_.get() == nullptr);
 
-  device->ConnectToService(
-      BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
-      base::Bind(&BluetoothSocketBlueZTest::ConnectToServiceSuccessCallback,
-                 base::Unretained(this)),
-      base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
-                 base::Unretained(this)));
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    device->ConnectToService(
+        BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
+        base::Bind(&BluetoothSocketBlueZTest::ConnectToServiceSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(0U, success_callback_count_);
   EXPECT_EQ(2U, error_callback_count_);
@@ -569,15 +629,17 @@
 }
 
 TEST_F(BluetoothSocketBlueZTest, SocketListenTwice) {
-  adapter_->CreateRfcommService(
-      BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
-      BluetoothAdapter::ServiceOptions(),
-      base::Bind(&BluetoothSocketBlueZTest::CreateServiceSuccessCallback,
-                 base::Unretained(this)),
-      base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
-                 base::Unretained(this)));
-
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    adapter_->CreateRfcommService(
+        BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
+        BluetoothAdapter::ServiceOptions(),
+        base::Bind(&BluetoothSocketBlueZTest::CreateServiceSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
   EXPECT_EQ(0U, error_callback_count_);
@@ -587,30 +649,34 @@
   scoped_refptr<BluetoothSocket> server_socket;
   server_socket.swap(last_socket_);
 
-  server_socket->Accept(
-      base::Bind(&BluetoothSocketBlueZTest::AcceptSuccessCallback,
-                 base::Unretained(this)),
-      base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
-                 base::Unretained(this)));
+  {
+    base::RunLoop run_loop;
+    server_socket->Accept(
+        base::Bind(&BluetoothSocketBlueZTest::AcceptSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
 
-  server_socket->Close();
+    server_socket->Close();
 
-  server_socket = nullptr;
-
-  base::RunLoop().RunUntilIdle();
+    server_socket = nullptr;
+    run_loop.RunUntilIdle();
+  }
 
   EXPECT_EQ(1U, success_callback_count_);
   EXPECT_EQ(1U, error_callback_count_);
 
-  adapter_->CreateRfcommService(
-      BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
-      BluetoothAdapter::ServiceOptions(),
-      base::Bind(&BluetoothSocketBlueZTest::CreateServiceSuccessCallback,
-                 base::Unretained(this)),
-      base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
-                 base::Unretained(this)));
-
-  base::RunLoop().Run();
+  {
+    base::RunLoop run_loop;
+    adapter_->CreateRfcommService(
+        BluetoothUUID(bluez::FakeBluetoothProfileManagerClient::kRfcommUuid),
+        BluetoothAdapter::ServiceOptions(),
+        base::Bind(&BluetoothSocketBlueZTest::CreateServiceSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
+    run_loop.Run();
+  }
 
   EXPECT_EQ(2U, success_callback_count_);
   EXPECT_EQ(1U, error_callback_count_);
@@ -619,17 +685,19 @@
   // Take control of this socket.
   server_socket.swap(last_socket_);
 
-  server_socket->Accept(
-      base::Bind(&BluetoothSocketBlueZTest::AcceptSuccessCallback,
-                 base::Unretained(this)),
-      base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
-                 base::Unretained(this)));
+  {
+    base::RunLoop run_loop;
+    server_socket->Accept(
+        base::Bind(&BluetoothSocketBlueZTest::AcceptSuccessCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()),
+        base::Bind(&BluetoothSocketBlueZTest::ErrorCallback,
+                   base::Unretained(this), run_loop.QuitWhenIdleClosure()));
 
-  server_socket->Close();
+    server_socket->Close();
 
-  server_socket = nullptr;
-
-  base::RunLoop().RunUntilIdle();
+    server_socket = nullptr;
+    run_loop.RunUntilIdle();
+  }
 
   EXPECT_EQ(2U, success_callback_count_);
   EXPECT_EQ(2U, error_callback_count_);
diff --git a/device/bluetooth/test/test_bluetooth_adapter_observer.cc b/device/bluetooth/test/test_bluetooth_adapter_observer.cc
index 1ab08306..ed01c509 100644
--- a/device/bluetooth/test/test_bluetooth_adapter_observer.cc
+++ b/device/bluetooth/test/test_bluetooth_adapter_observer.cc
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
 #include "device/bluetooth/bluetooth_remote_gatt_service.h"
@@ -333,8 +334,7 @@
 }
 
 void TestBluetoothAdapterObserver::QuitMessageLoop() {
-  if (base::MessageLoop::current() &&
-      base::MessageLoop::current()->is_running())
+  if (base::RunLoop::IsRunningOnCurrentThread())
     base::MessageLoop::current()->QuitWhenIdle();
 }
 
diff --git a/extensions/browser/api/alarms/alarms_api_unittest.cc b/extensions/browser/api/alarms/alarms_api_unittest.cc
index 20ef94d..dfaac4a 100644
--- a/extensions/browser/api/alarms/alarms_api_unittest.cc
+++ b/extensions/browser/api/alarms/alarms_api_unittest.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 
 #include "base/json/json_reader.h"
+#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/test/simple_test_clock.h"
 #include "base/values.h"
@@ -36,7 +37,7 @@
   ~AlarmDelegate() override {}
   void OnAlarm(const std::string& extension_id, const Alarm& alarm) override {
     alarms_seen.push_back(alarm.js_alarm->name);
-    if (base::MessageLoop::current()->is_running())
+    if (base::RunLoop::IsRunningOnCurrentThread())
       base::MessageLoop::current()->QuitWhenIdle();
   }
 
diff --git a/gpu/ipc/service/direct_composition_surface_win.cc b/gpu/ipc/service/direct_composition_surface_win.cc
index 91f77e1..2939535 100644
--- a/gpu/ipc/service/direct_composition_surface_win.cc
+++ b/gpu/ipc/service/direct_composition_surface_win.cc
@@ -126,7 +126,7 @@
   DCHECK(d3d11_device);
 
   base::win::ScopedComPtr<IDXGIDevice> dxgi_device;
-  d3d11_device.QueryInterface(dxgi_device.Receive());
+  d3d11_device.CopyTo(dxgi_device.Receive());
   base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter;
   dxgi_device->GetAdapter(dxgi_adapter.Receive());
 
@@ -136,7 +136,7 @@
     if (FAILED(dxgi_adapter->EnumOutputs(i++, output.Receive())))
       break;
     base::win::ScopedComPtr<IDXGIOutput3> output3;
-    if (FAILED(output.QueryInterface(output3.Receive())))
+    if (FAILED(output.CopyTo(output3.Receive())))
       continue;
 
     UINT flags = 0;
@@ -303,13 +303,13 @@
 };
 
 bool DCLayerTree::Initialize(HWND window) {
-  d3d11_device_.QueryInterface(video_device_.Receive());
+  d3d11_device_.CopyTo(video_device_.Receive());
   base::win::ScopedComPtr<ID3D11DeviceContext> context;
   d3d11_device_->GetImmediateContext(context.Receive());
-  context.QueryInterface(video_context_.Receive());
+  context.CopyTo(video_context_.Receive());
 
   base::win::ScopedComPtr<IDCompositionDesktopDevice> desktop_device;
-  dcomp_device_.QueryInterface(desktop_device.Receive());
+  dcomp_device_.CopyTo(desktop_device.Receive());
 
   HRESULT hr = desktop_device->CreateTargetForHwnd(window, TRUE,
                                                    dcomp_target_.Receive());
@@ -365,10 +365,10 @@
     DCLayerTree* surface,
     base::win::ScopedComPtr<ID3D11Device> d3d11_device)
     : surface_(surface), d3d11_device_(d3d11_device) {
-  d3d11_device_.QueryInterface(video_device_.Receive());
+  d3d11_device_.CopyTo(video_device_.Receive());
   base::win::ScopedComPtr<ID3D11DeviceContext> context;
   d3d11_device_->GetImmediateContext(context.Receive());
-  context.QueryInterface(video_context_.Receive());
+  context.CopyTo(video_context_.Receive());
   HMODULE dcomp = ::GetModuleHandleA("dcomp.dll");
   CHECK(dcomp);
   create_surface_handle_function_ =
@@ -547,7 +547,7 @@
   // TODO(jbauman): Use correct colorspace.
   gfx::ColorSpace src_color_space = gfx::ColorSpace::CreateREC709();
   base::win::ScopedComPtr<ID3D11VideoContext1> context1;
-  if (SUCCEEDED(video_context_.QueryInterface(context1.Receive()))) {
+  if (SUCCEEDED(video_context_.CopyTo(context1.Receive()))) {
     context1->VideoProcessorSetStreamColorSpace1(
         video_processor_.Get(), 0,
         gfx::ColorSpaceWin::GetDXGIColorSpace(src_color_space));
@@ -568,7 +568,7 @@
   }
 
   base::win::ScopedComPtr<IDXGISwapChain3> swap_chain3;
-  if (SUCCEEDED(swap_chain_.QueryInterface(swap_chain3.Receive()))) {
+  if (SUCCEEDED(swap_chain_.CopyTo(swap_chain3.Receive()))) {
     DXGI_COLOR_SPACE_TYPE color_space =
         gfx::ColorSpaceWin::GetDXGIColorSpace(output_color_space);
     HRESULT hr = swap_chain3->SetColorSpace1(color_space);
@@ -649,7 +649,7 @@
   frames_since_color_space_change_++;
 
   base::win::ScopedComPtr<IDXGISwapChainMedia> swap_chain_media;
-  if (SUCCEEDED(swap_chain_.QueryInterface(swap_chain_media.Receive()))) {
+  if (SUCCEEDED(swap_chain_.CopyTo(swap_chain_media.Receive()))) {
     DXGI_FRAME_STATISTICS_MEDIA stats = {};
     if (SUCCEEDED(swap_chain_media->GetFrameStatisticsMedia(&stats))) {
       UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.DirectComposition.CompositionMode",
@@ -682,14 +682,14 @@
   DCHECK(!swap_chain_);
 
   base::win::ScopedComPtr<IDXGIDevice> dxgi_device;
-  d3d11_device_.QueryInterface(dxgi_device.Receive());
+  d3d11_device_.CopyTo(dxgi_device.Receive());
   base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter;
   dxgi_device->GetAdapter(dxgi_adapter.Receive());
   base::win::ScopedComPtr<IDXGIFactory2> dxgi_factory;
   dxgi_adapter->GetParent(IID_PPV_ARGS(dxgi_factory.Receive()));
 
   base::win::ScopedComPtr<IDXGIFactoryMedia> media_factory;
-  dxgi_factory.QueryInterface(media_factory.Receive());
+  dxgi_factory.CopyTo(media_factory.Receive());
   DXGI_SWAP_CHAIN_DESC1 desc = {};
   desc.Width = swap_chain_size_.width();
   desc.Height = swap_chain_size_.height();
@@ -1021,7 +1021,7 @@
     DXGI_ALPHA_MODE alpha_mode =
         has_alpha_ ? DXGI_ALPHA_MODE_PREMULTIPLIED : DXGI_ALPHA_MODE_IGNORE;
     base::win::ScopedComPtr<IDXGIDevice> dxgi_device;
-    d3d11_device_.QueryInterface(dxgi_device.Receive());
+    d3d11_device_.CopyTo(dxgi_device.Receive());
     base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter;
     dxgi_device->GetAdapter(dxgi_adapter.Receive());
     base::win::ScopedComPtr<IDXGIFactory2> dxgi_factory;
@@ -1068,7 +1068,7 @@
         // committing the DirectComposition tree, or else the swapchain
         // may flicker black when it's first presented.
         base::win::ScopedComPtr<IDXGIDevice2> dxgi_device2;
-        HRESULT hr = d3d11_device_.QueryInterface(dxgi_device2.Receive());
+        HRESULT hr = d3d11_device_.CopyTo(dxgi_device2.Receive());
         DCHECK(SUCCEEDED(hr));
         base::WaitableEvent event(
             base::WaitableEvent::ResetPolicy::AUTOMATIC,
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
index a37ea1c7..185abc0d 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
@@ -808,6 +808,8 @@
     case CELL_OTHER_DEVICES_SIGNED_OUT:
       subview = [[SignedOutView alloc] initWithFrame:CGRectZero];
       [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
+      base::RecordAction(
+          base::UserMetricsAction("Signin_Impression_FromRecentTabs"));
       break;
     case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF:
       subview = [[SignedInSyncOffView alloc] initWithFrame:CGRectZero
@@ -837,6 +839,8 @@
       [configurator configureSigninPromoView:signinPromoView];
       subview = signinPromoView;
       [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
+      base::RecordAction(
+          base::UserMetricsAction("Signin_Impression_FromRecentTabs"));
       break;
     }
     case CELL_OTHER_DEVICES_SYNC_IN_PROGRESS:
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_out_view.mm b/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_out_view.mm
index ba0c22e2..c6f6d6d8 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_out_view.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_out_view.mm
@@ -64,11 +64,6 @@
     // clang-format on
     ApplyVisualConstraintsWithOptions(constraints, viewsDictionary,
                                       LayoutOptionForRTLSupport(), self);
-
-    // SignedOutView is always shown directly when created, and its parent view
-    // |reloadData| isn't called when the user is not signed-in.
-    base::RecordAction(
-        base::UserMetricsAction("Signin_Impression_FromRecentTabs"));
   }
   return self;
 }
diff --git a/ios/chrome/browser/ui/payments/payment_request_view_controller.mm b/ios/chrome/browser/ui/payments/payment_request_view_controller.mm
index 773752a..032aa18 100644
--- a/ios/chrome/browser/ui/payments/payment_request_view_controller.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_view_controller.mm
@@ -155,7 +155,7 @@
                 forState:UIControlStateNormal];
     [_payButton setCustomTitleColor:[UIColor whiteColor]];
     [_payButton setInkColor:[UIColor colorWithWhite:1 alpha:0.2]];
-    [_payButton addTarget:nil
+    [_payButton addTarget:self
                    action:@selector(onConfirm)
          forControlEvents:UIControlEventTouchUpInside];
     [_payButton sizeToFit];
diff --git a/mash/quick_launch/quick_launch.cc b/mash/quick_launch/quick_launch.cc
index d10ce06..9b586ac 100644
--- a/mash/quick_launch/quick_launch.cc
+++ b/mash/quick_launch/quick_launch.cc
@@ -7,6 +7,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -165,7 +166,7 @@
   auto it = std::find(windows_.begin(), windows_.end(), window);
   DCHECK(it != windows_.end());
   windows_.erase(it);
-  if (windows_.empty() && base::MessageLoop::current()->is_running())
+  if (windows_.empty() && base::RunLoop::IsRunningOnCurrentThread())
     base::MessageLoop::current()->QuitWhenIdle();
 }
 
diff --git a/media/capture/video/win/video_capture_device_factory_win.cc b/media/capture/video/win/video_capture_device_factory_win.cc
index 4eaa387..c88bed3 100644
--- a/media/capture/video/win/video_capture_device_factory_win.cc
+++ b/media/capture/video/win/video_capture_device_factory_win.cc
@@ -278,7 +278,7 @@
   }
 
   ScopedComPtr<IAMStreamConfig> stream_config;
-  hr = output_capture_pin.QueryInterface(stream_config.Receive());
+  hr = output_capture_pin.CopyTo(stream_config.Receive());
   if (FAILED(hr)) {
     DLOG(ERROR) << "Failed to get IAMStreamConfig interface from "
                    "capture device: " << logging::SystemErrorCodeToString(hr);
diff --git a/media/capture/video/win/video_capture_device_win.cc b/media/capture/video/win/video_capture_device_win.cc
index f7ca4ef..b244df7 100644
--- a/media/capture/video/win/video_capture_device_win.cc
+++ b/media/capture/video/win/video_capture_device_win.cc
@@ -294,7 +294,7 @@
   if (FAILED(hr))
     return false;
 
-  hr = graph_builder_.QueryInterface(media_control_.Receive());
+  hr = graph_builder_.CopyTo(media_control_.Receive());
   DLOG_IF_FAILED_WITH_HRESULT("Failed to create media control builder", hr);
   if (FAILED(hr))
     return false;
@@ -350,7 +350,7 @@
                found_capability.supported_format.frame_rate);
 
   ScopedComPtr<IAMStreamConfig> stream_config;
-  HRESULT hr = output_capture_pin_.QueryInterface(stream_config.Receive());
+  HRESULT hr = output_capture_pin_.CopyTo(stream_config.Receive());
   if (FAILED(hr)) {
     SetErrorState(FROM_HERE, "Can't get the Capture format settings", hr);
     return;
@@ -482,7 +482,7 @@
 bool VideoCaptureDeviceWin::CreateCapabilityMap() {
   DCHECK(thread_checker_.CalledOnValidThread());
   ScopedComPtr<IAMStreamConfig> stream_config;
-  HRESULT hr = output_capture_pin_.QueryInterface(stream_config.Receive());
+  HRESULT hr = output_capture_pin_.CopyTo(stream_config.Receive());
   DLOG_IF_FAILED_WITH_HRESULT(
       "Failed to get IAMStreamConfig from capture device", hr);
   if (FAILED(hr))
@@ -490,7 +490,7 @@
 
   // Get interface used for getting the frame rate.
   ScopedComPtr<IAMVideoControl> video_control;
-  hr = capture_filter_.QueryInterface(video_control.Receive());
+  hr = capture_filter_.CopyTo(video_control.Receive());
 
   int count = 0, size = 0;
   hr = stream_config->GetNumberOfCapabilities(&count, &size);
diff --git a/media/gpu/d3d11_video_decode_accelerator_win.cc b/media/gpu/d3d11_video_decode_accelerator_win.cc
index e778931..31acce7 100644
--- a/media/gpu/d3d11_video_decode_accelerator_win.cc
+++ b/media/gpu/d3d11_video_decode_accelerator_win.cc
@@ -50,10 +50,10 @@
   device_ = gl::QueryD3D11DeviceObjectFromANGLE();
   device_->GetImmediateContext(device_context_.Receive());
 
-  HRESULT hr = device_context_.QueryInterface(video_context_.Receive());
+  HRESULT hr = device_context_.CopyTo(video_context_.Receive());
   CHECK(SUCCEEDED(hr));
 
-  hr = device_.QueryInterface(video_device_.Receive());
+  hr = device_.CopyTo(video_device_.Receive());
   CHECK(SUCCEEDED(hr));
 
   bool is_h264 =
diff --git a/media/gpu/dxva_video_decode_accelerator_win.cc b/media/gpu/dxva_video_decode_accelerator_win.cc
index ff7fc4b..aac2695 100644
--- a/media/gpu/dxva_video_decode_accelerator_win.cc
+++ b/media/gpu/dxva_video_decode_accelerator_win.cc
@@ -849,10 +849,10 @@
       RETURN_ON_HR_FAILURE(hr, "Failed to create DX11 device", false);
     }
 
-    hr = d3d11_device_.QueryInterface(video_device_.Receive());
+    hr = d3d11_device_.CopyTo(video_device_.Receive());
     RETURN_ON_HR_FAILURE(hr, "Failed to get video device", false);
 
-    hr = d3d11_device_context_.QueryInterface(video_context_.Receive());
+    hr = d3d11_device_context_.CopyTo(video_context_.Receive());
     RETURN_ON_HR_FAILURE(hr, "Failed to get video context", false);
   }
 
@@ -1313,7 +1313,7 @@
   }
 
   base::win::ScopedComPtr<ID3D11VideoDevice> video_device;
-  hr = device.QueryInterface(IID_PPV_ARGS(&video_device));
+  hr = device.CopyTo(IID_PPV_ARGS(&video_device));
   if (FAILED(hr))
     return max_resolution;
 
@@ -2861,7 +2861,7 @@
     dx11_converter_output_color_space_ = gfx::ColorSpace::CreateSRGB();
     if (use_color_info_ || use_fp16_) {
       base::win::ScopedComPtr<ID3D11VideoContext1> video_context1;
-      HRESULT hr = video_context_.QueryInterface(video_context1.Receive());
+      HRESULT hr = video_context_.CopyTo(video_context1.Receive());
       if (SUCCEEDED(hr)) {
         if (use_fp16_ &&
             base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/media/gpu/media_foundation_video_encode_accelerator_win.cc b/media/gpu/media_foundation_video_encode_accelerator_win.cc
index 0ad8ba0..c70e301 100644
--- a/media/gpu/media_foundation_video_encode_accelerator_win.cc
+++ b/media/gpu/media_foundation_video_encode_accelerator_win.cc
@@ -444,7 +444,7 @@
   RETURN_ON_FAILURE((encoder_.Get() != nullptr),
                     "No HW encoder instance created", false);
 
-  HRESULT hr = encoder_.QueryInterface(codec_api_.Receive());
+  HRESULT hr = encoder_.CopyTo(codec_api_.Receive());
   RETURN_ON_HR_FAILURE(hr, "Couldn't get ICodecAPI", false);
   VARIANT var;
   var.vt = VT_UI4;
diff --git a/mojo/public/cpp/bindings/connector.h b/mojo/public/cpp/bindings/connector.h
index cb065c17..e0bbabd 100644
--- a/mojo/public/cpp/bindings/connector.h
+++ b/mojo/public/cpp/bindings/connector.h
@@ -157,7 +157,7 @@
 
  private:
   class ActiveDispatchTracker;
-  class MessageLoopNestingObserver;
+  class RunLoopNestingObserver;
 
   // Callback of mojo::SimpleWatcher.
   void OnWatcherHandleReady(MojoResult result);
@@ -218,9 +218,9 @@
   // notification.
   const char* heap_profiler_tag_ = nullptr;
 
-  // A cached pointer to the MessageLoopNestingObserver for the MessageLoop on
-  // which this Connector was created.
-  MessageLoopNestingObserver* const nesting_observer_;
+  // A cached pointer to the RunLoopNestingObserver for the thread on which this
+  // Connector was created.
+  RunLoopNestingObserver* const nesting_observer_;
 
   // |true| iff the Connector is currently dispatching a message. Used to detect
   // nested dispatch operations.
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc
index d93e45ed..c97b37d 100644
--- a/mojo/public/cpp/bindings/lib/connector.cc
+++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_local.h"
 #include "mojo/public/cpp/bindings/lib/may_auto_lock.h"
@@ -25,11 +26,10 @@
 namespace {
 
 // The NestingObserver for each thread. Note that this is always a
-// Connector::MessageLoopNestingObserver; we use the base type here because that
+// Connector::RunLoopNestingObserver; we use the base type here because that
 // subclass is private to Connector.
-base::LazyInstance<
-    base::ThreadLocalPointer<base::MessageLoop::NestingObserver>>::Leaky
-    g_tls_nesting_observer = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::ThreadLocalPointer<base::RunLoop::NestingObserver>>::
+    Leaky g_tls_nesting_observer = LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
 
@@ -44,7 +44,7 @@
 
  private:
   const base::WeakPtr<Connector> connector_;
-  MessageLoopNestingObserver* const nesting_observer_;
+  RunLoopNestingObserver* const nesting_observer_;
   ActiveDispatchTracker* outer_tracker_ = nullptr;
   ActiveDispatchTracker* inner_tracker_ = nullptr;
 
@@ -53,40 +53,41 @@
 
 // Watches the MessageLoop on the current thread. Notifies the current chain of
 // ActiveDispatchTrackers when a nested message loop is started.
-class Connector::MessageLoopNestingObserver
-    : public base::MessageLoop::NestingObserver,
+class Connector::RunLoopNestingObserver
+    : public base::RunLoop::NestingObserver,
       public base::MessageLoop::DestructionObserver {
  public:
-  MessageLoopNestingObserver() {
-    base::MessageLoop::current()->AddNestingObserver(this);
+  RunLoopNestingObserver() {
+    base::RunLoop::AddNestingObserverOnCurrentThread(this);
     base::MessageLoop::current()->AddDestructionObserver(this);
   }
 
-  ~MessageLoopNestingObserver() override {}
+  ~RunLoopNestingObserver() override {}
 
-  // base::MessageLoop::NestingObserver:
-  void OnBeginNestedMessageLoop() override {
+  // base::RunLoop::NestingObserver:
+  void OnBeginNestedRunLoop() override {
     if (top_tracker_)
       top_tracker_->NotifyBeginNesting();
   }
 
   // base::MessageLoop::DestructionObserver:
   void WillDestroyCurrentMessageLoop() override {
-    base::MessageLoop::current()->RemoveNestingObserver(this);
+    base::RunLoop::RemoveNestingObserverOnCurrentThread(this);
     base::MessageLoop::current()->RemoveDestructionObserver(this);
     DCHECK_EQ(this, g_tls_nesting_observer.Get().Get());
     g_tls_nesting_observer.Get().Set(nullptr);
     delete this;
   }
 
-  static MessageLoopNestingObserver* GetForThread() {
+  static RunLoopNestingObserver* GetForThread() {
     if (!base::MessageLoop::current() ||
-        !base::MessageLoop::current()->nesting_allowed())
+        !base::RunLoop::IsNestingAllowedOnCurrentThread()) {
       return nullptr;
-    auto* observer = static_cast<MessageLoopNestingObserver*>(
+    }
+    auto* observer = static_cast<RunLoopNestingObserver*>(
         g_tls_nesting_observer.Get().Get());
     if (!observer) {
-      observer = new MessageLoopNestingObserver;
+      observer = new RunLoopNestingObserver;
       g_tls_nesting_observer.Get().Set(observer);
     }
     return observer;
@@ -97,7 +98,7 @@
 
   ActiveDispatchTracker* top_tracker_ = nullptr;
 
-  DISALLOW_COPY_AND_ASSIGN(MessageLoopNestingObserver);
+  DISALLOW_COPY_AND_ASSIGN(RunLoopNestingObserver);
 };
 
 Connector::ActiveDispatchTracker::ActiveDispatchTracker(
@@ -132,7 +133,7 @@
                      scoped_refptr<base::SingleThreadTaskRunner> runner)
     : message_pipe_(std::move(message_pipe)),
       task_runner_(std::move(runner)),
-      nesting_observer_(MessageLoopNestingObserver::GetForThread()),
+      nesting_observer_(RunLoopNestingObserver::GetForThread()),
       weak_factory_(this) {
   if (config == MULTI_THREADED_SEND)
     lock_.emplace();
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h
index 3acd9ad..199df68 100644
--- a/net/quic/core/quic_flags_list.h
+++ b/net/quic/core/quic_flags_list.h
@@ -168,7 +168,7 @@
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_38, true)
 
 // If true, enable QUIC v39.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_39, false)
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_39, true)
 
 // If true, on client side, 8-byte connection ID in public header is read and
 // written in big endian.
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 4e41ba4..6e016bf 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -1271,7 +1271,7 @@
     ASSERT_TRUE(SUCCEEDED(shell.CreateInstance(CLSID_ShellLink, NULL,
                                                CLSCTX_INPROC_SERVER)));
     base::win::ScopedComPtr<IPersistFile> persist;
-    ASSERT_TRUE(SUCCEEDED(shell.QueryInterface(persist.Receive())));
+    ASSERT_TRUE(SUCCEEDED(shell.CopyTo(persist.Receive())));
     EXPECT_TRUE(SUCCEEDED(shell->SetPath(app_path.value().c_str())));
     EXPECT_TRUE(SUCCEEDED(shell->SetDescription(L"ResolveShortcutTest")));
     EXPECT_TRUE(SUCCEEDED(persist->Save(lnk_path.c_str(), TRUE)));
diff --git a/remoting/host/native_messaging/log_message_handler.cc b/remoting/host/native_messaging/log_message_handler.cc
index 70f744b..02c4f757 100644
--- a/remoting/host/native_messaging/log_message_handler.cc
+++ b/remoting/host/native_messaging/log_message_handler.cc
@@ -125,9 +125,13 @@
   dictionary->SetString("file", file);
   dictionary->SetInteger("line", line);
 
+  // Protect against this instance being torn down after the delegate is run.
+  base::WeakPtr<LogMessageHandler> self = weak_ptr_factory_.GetWeakPtr();
   delegate_.Run(std::move(dictionary));
 
-  suppress_logging_ = false;
+  if (self) {
+    suppress_logging_ = false;
+  }
 }
 
 }  // namespace remoting
diff --git a/remoting/host/win/rdp_client_window.cc b/remoting/host/win/rdp_client_window.cc
index bf58ec5..02ccc66 100644
--- a/remoting/host/win/rdp_client_window.cc
+++ b/remoting/host/win/rdp_client_window.cc
@@ -287,7 +287,7 @@
   if (FAILED(result))
     return LogOnCreateError(result);
 
-  result = control.QueryInterface(client_.Receive());
+  result = control.CopyTo(client_.Receive());
   if (FAILED(result))
     return LogOnCreateError(result);
 
@@ -305,7 +305,7 @@
     return LogOnCreateError(result);
 
   // Check to see if the platform exposes the interface used for resizing.
-  result = client_.QueryInterface(client_9_.Receive());
+  result = client_.CopyTo(client_9_.Receive());
   if (FAILED(result) && result != E_NOINTERFACE) {
     return LogOnCreateError(result);
   }
@@ -469,7 +469,7 @@
   // Get the error message as well.
   base::win::ScopedBstr error_message;
   base::win::ScopedComPtr<mstsc::IMsRdpClient5> client5;
-  result = client_.QueryInterface(client5.Receive());
+  result = client_.CopyTo(client5.Receive());
   if (SUCCEEDED(result)) {
     result = client5->GetErrorDescription(reason, extended_code,
                                           error_message.Receive());
diff --git a/services/service_manager/tests/lifecycle/package.cc b/services/service_manager/tests/lifecycle/package.cc
index ece551b..8e5be519 100644
--- a/services/service_manager/tests/lifecycle/package.cc
+++ b/services/service_manager/tests/lifecycle/package.cc
@@ -8,6 +8,8 @@
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/service_manager/public/c/main.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
@@ -152,7 +154,7 @@
     DCHECK(it != contexts_.end());
     contexts_.erase(it);
     id_to_context_.erase(id_it);
-    if (contexts_.empty() && base::MessageLoop::current()->is_running())
+    if (contexts_.empty() && base::RunLoop::IsRunningOnCurrentThread())
       base::MessageLoop::current()->QuitWhenIdle();
   }
 
diff --git a/services/ui/service.cc b/services/ui/service.cc
index c3fbf99..673110c 100644
--- a/services/ui/service.cc
+++ b/services/ui/service.cc
@@ -10,6 +10,7 @@
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
+#include "base/run_loop.h"
 #include "base/threading/platform_thread.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
@@ -268,10 +269,8 @@
 
 void Service::OnNoMoreDisplays() {
   // We may get here from the destructor, in which case there is no messageloop.
-  if (base::MessageLoop::current() &&
-      base::MessageLoop::current()->is_running()) {
+  if (base::RunLoop::IsRunningOnCurrentThread())
     base::MessageLoop::current()->QuitWhenIdle();
-  }
 }
 
 bool Service::IsTestConfig() const {
diff --git a/storage/browser/fileapi/file_system_operation_impl_write_unittest.cc b/storage/browser/fileapi/file_system_operation_impl_write_unittest.cc
index ebc48d74..ab682226 100644
--- a/storage/browser/fileapi/file_system_operation_impl_write_unittest.cc
+++ b/storage/browser/fileapi/file_system_operation_impl_write_unittest.cc
@@ -139,7 +139,7 @@
       EXPECT_EQ(status_, base::File::FILE_OK);
       complete_ = true;
       status_ = status;
-      if (base::MessageLoop::current()->is_running())
+      if (base::RunLoop::IsRunningOnCurrentThread())
         base::MessageLoop::current()->QuitWhenIdle();
     }
   }
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations
index ffe44fe..8bc977b3 100644
--- a/third_party/WebKit/LayoutTests/W3CImportExpectations
+++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -270,7 +270,8 @@
 # external/wpt/gamepad [ Pass ]
 ## Owners: alexander.shalamov@intel.com,mikhail.pozdnyakov@intel.com,rijubrata.bhaumik@intel.com,timvolodine@chromium.org
 # external/wpt/generic-sensor [ Pass ]
-external/wpt/geolocation-API [ Skip ]
+## Owners: mcasas@chromium.org
+# external/wpt/geolocation-API [ Pass ]
 ## Owners: jsbell@chromium.org
 # external/wpt/hr-time [ Pass ]
 ## Owners: dom-dev@chromium.org
@@ -372,7 +373,8 @@
 external/wpt/url [ Skip ]
 ## Owners: jsbell@chromium.org
 # external/wpt/user-timing [ Pass ]
-external/wpt/vibration [ Skip ]
+## Owners: platform-capabilities@chromium.org
+# external/wpt/vibration [ Pass ]
 ## Owners: bsheedy@chromium.org
 # external/wpt/webvr [ Pass ]
 external/wpt/wai-aria [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-idl-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-idl-expected.txt
index 939e230..a1bfa22 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-idl-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-idl-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 116 tests; 64 PASS, 52 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 116 tests; 66 PASS, 50 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS EventTarget interface: existence and properties of interface object 
 PASS EventTarget interface object length 
 PASS EventTarget interface object name 
@@ -52,7 +52,7 @@
             fn.apply(obj, args);
         }" did not throw
 PASS RTCPeerConnection interface: operation generateCertificate(AlgorithmIdentifier) 
-FAIL RTCPeerConnection interface: operation getSenders() assert_own_property: interface prototype object missing non-static operation expected property "getSenders" missing
+PASS RTCPeerConnection interface: operation getSenders() 
 PASS RTCPeerConnection interface: operation getReceivers() 
 FAIL RTCPeerConnection interface: operation addTrack(MediaStreamTrack,MediaStream) assert_own_property: interface prototype object missing non-static operation expected property "addTrack" missing
 FAIL RTCPeerConnection interface: operation removeTrack(RTCRtpSender) assert_own_property: interface prototype object missing non-static operation expected property "removeTrack" missing
@@ -116,7 +116,7 @@
 PASS RTCPeerConnection interface: calling getStats(MediaStreamTrack,RTCStatsCallback,RTCPeerConnectionErrorCallback) on pc with too few arguments must throw TypeError 
 PASS RTCPeerConnection interface: pc must inherit property "generateCertificate" with the proper type (29) 
 FAIL RTCPeerConnection interface: calling generateCertificate(AlgorithmIdentifier) on pc with too few arguments must throw TypeError assert_unreached: Throws "TypeError: Cannot read property 'apply' of undefined" instead of rejecting promise Reached unreachable code
-FAIL RTCPeerConnection interface: pc must inherit property "getSenders" with the proper type (30) assert_inherits: property "getSenders" not found in prototype chain
+PASS RTCPeerConnection interface: pc must inherit property "getSenders" with the proper type (30) 
 PASS RTCPeerConnection interface: pc must inherit property "getReceivers" with the proper type (31) 
 FAIL RTCPeerConnection interface: pc must inherit property "addTrack" with the proper type (32) assert_inherits: property "addTrack" not found in prototype chain
 FAIL RTCPeerConnection interface: calling addTrack(MediaStreamTrack,MediaStream) on pc with too few arguments must throw TypeError assert_inherits: property "addTrack" not found in prototype chain
diff --git a/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-getSenders.html b/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-getSenders.html
new file mode 100644
index 0000000..eb2f509
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-getSenders.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>RTCPeerConnection.getSenders</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+</head>
+<body>
+<script>
+promise_test(function() {
+  let pc = new RTCPeerConnection();
+  return createStreams({audio:true}, 1)
+    .then(function(streams) {
+      for (let i = 0; i < streams.length; ++i) {
+        pc.addStream(streams[i]);
+      }
+      verifyStreamAndTrackCounts(pc.getLocalStreams(), 1, true, false);
+      verifyLocalTracksHaveSenders(pc);
+      // Make sure object identities are preserved between calls.
+      assert_array_equals(pc.getSenders(), pc.getSenders());
+    });
+}, 'getSenders() for a single audio track.');
+
+promise_test(function() {
+  let pc = new RTCPeerConnection();
+  return createStreams({video:true}, 1)
+    .then(function(streams) {
+      for (let i = 0; i < streams.length; ++i) {
+        pc.addStream(streams[i]);
+      }
+      verifyStreamAndTrackCounts(pc.getLocalStreams(), 1, false, true);
+      verifyLocalTracksHaveSenders(pc);
+      // Make sure object identities are preserved between calls.
+      assert_array_equals(pc.getSenders(), pc.getSenders());
+    });
+}, 'getSenders() for a single video track.');
+
+promise_test(function() {
+  let pc = new RTCPeerConnection();
+  return createStreams({audio:true, video:true}, 1)
+    .then(function(streams) {
+      for (let i = 0; i < streams.length; ++i) {
+        pc.addStream(streams[i]);
+      }
+      verifyStreamAndTrackCounts(pc.getLocalStreams(), 1, true, true);
+      verifyLocalTracksHaveSenders(pc);
+      // Make sure object identities are preserved between calls.
+      assert_array_equals(pc.getSenders(), pc.getSenders());
+    });
+}, 'getSenders() for a single stream with an audio and video track.');
+
+promise_test(function() {
+  let pc = new RTCPeerConnection();
+  return createStreams({audio:true, video:true}, 2)
+    .then(function(streams) {
+      for (let i = 0; i < streams.length; ++i) {
+        pc.addStream(streams[i]);
+      }
+      verifyStreamAndTrackCounts(pc.getLocalStreams(), 2, true, true);
+      verifyLocalTracksHaveSenders(pc);
+      // Make sure object identities are preserved between calls.
+      assert_array_equals(pc.getSenders(), pc.getSenders());
+    });
+}, 'getSenders() for a multiple audio-video streams.');
+
+promise_test(function() {
+  let pc = new RTCPeerConnection();
+  let senders = new Set();
+  return createStreams({audio:true, video:true}, 2)
+    .then(function(streams) {
+      for (let i = 0; i < streams.length; ++i) {
+        pc.addStream(streams[i]);
+      }
+      verifyStreamAndTrackCounts(pc.getLocalStreams(), 2, true, true);
+      verifyLocalTracksHaveSenders(pc);
+      // Make sure object identities are preserved between calls.
+      assert_array_equals(pc.getSenders(), pc.getSenders());
+
+      for (let i = 0; i < pc.getSenders().length; ++i)
+        senders.add(pc.getSenders()[i]);
+      // 2 senders per stream, one for audio and one for video
+      assert_equals(senders.size, 4);
+
+      pc.removeStream(pc.getLocalStreams()[0]);
+      verifyStreamAndTrackCounts(pc.getLocalStreams(), 1, true, true);
+      verifyLocalTracksHaveSenders(pc);
+      // Make sure object identities are preserved between calls.
+      assert_array_equals(pc.getSenders(), pc.getSenders());
+
+      for (let i = 0; i < pc.getSenders().length; ++i)
+        assert_true(senders.has(pc.getSenders()[i]));
+
+      return createStreams({audio:true, video:true}, 1);
+    })
+    .then(function(streams) {
+      for (let i = 0; i < streams.length; ++i) {
+        pc.addStream(streams[i]);
+      }
+      verifyStreamAndTrackCounts(pc.getLocalStreams(), 2, true, true);
+      verifyLocalTracksHaveSenders(pc);
+      // Make sure object identities are preserved between calls.
+      assert_array_equals(pc.getSenders(), pc.getSenders());
+
+      // |senders| contains all senders so far (4), including the ones for
+      // the removed streams. The set does not contain duplicates, so adding all
+      // senders here should only increase the size for the new stream (2 new
+      // senders).
+      for (let i = 0; i < pc.getSenders().length; ++i)
+        senders.add(pc.getSenders()[i]);
+      assert_equals(senders.size, 6);
+
+      while (pc.getLocalStreams().length > 0) {
+        pc.removeStream(pc.getLocalStreams()[0]);
+      }
+      assert_equals(pc.getLocalStreams().length, 0);
+      assert_equals(pc.getSenders().length, 0);
+    });
+}, 'getSenders() for streams being added and removed.');
+
+/**
+ * Helper functions to tests.
+ */
+
+function createStreams(constraints, numStreams, streamsSoFar = []) {
+  if (numStreams == 0) {
+    return Promise.resolve(streamsSoFar);;
+  }
+  return navigator.mediaDevices.getUserMedia(constraints)
+    .then(function(stream) {
+      return createStreams(constraints,
+                           numStreams - 1,
+                           streamsSoFar.concat([stream]));
+    });
+}
+
+function verifyStreamAndTrackCounts(streams, streamCount, audio, video) {
+  assert_equals(streams.length, streamCount);
+  for (let i = 0; i < streams.length; ++i) {
+    assert_equals(streams[i].getAudioTracks().length, audio ? 1 : 0);
+    assert_equals(streams[i].getVideoTracks().length, video ? 1 : 0);
+  }
+}
+
+function verifyLocalTracksHaveSenders(pc) {
+  let localTracks = new Set();
+  let localStreams = pc.getLocalStreams();
+  for (let i = 0; i < localStreams.length; ++i) {
+    let localStreamTracks = localStreams[i].getTracks();
+    for (let j = 0; j < localStreamTracks.length; ++j) {
+      localTracks.add(localStreamTracks[j]);
+    }
+  }
+
+  let senderTracks = new Set();
+  let senders = pc.getSenders();
+  for (let i = 0; i < senders.length; ++i) {
+    assert_true(senders[i] != null);
+    assert_true(senders[i].track != null);
+    assert_true(localTracks.has(senders[i].track));
+    assert_false(senderTracks.has(senders[i].track));
+    senderTracks.add(senders[i].track);
+  }
+  assert_equals(senderTracks.size, localTracks.size);
+}
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/isolated-filesystem-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/isolated-filesystem-test.js
index 0b5e807d..37d72808 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/isolated-filesystem-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/isolated-filesystem-test.js
@@ -189,10 +189,31 @@
         this.getEntry(path, noop, callback, errorCallback);
     },
 
-    getEntry: function(path, noop, callback, errorCallback)
+    _createEntry: function(path, options, callback, errorCallback)
+    {
+        var tokens = path.split('/');
+        var name = tokens.pop();
+        var parentEntry = this;
+        for (var token of tokens)
+            parentEntry = parentEntry._childrenMap[token];
+        var entry = parentEntry._childrenMap[name];
+        if (entry && options.exclusive) {
+            errorCallback(new DOMException('File exists: ' + path, 'InvalidModificationError'));
+            return;
+        }
+        if (!entry)
+            entry = parentEntry.addFile(name, '');
+        callback(entry);
+    },
+
+    getEntry: function(path, options, callback, errorCallback)
     {
         if (path.startsWith("/"))
             path = path.substring(1);
+        if (options && options.create) {
+            this._createEntry(path, options, callback, errorCallback);
+            return;
+        }
         if (!path) {
             callback(this);
             return;
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/navigator-create-file-copy-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/navigator-create-file-copy-expected.txt
new file mode 100644
index 0000000..127a3caf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/navigator-create-file-copy-expected.txt
@@ -0,0 +1,11 @@
+Verify that navigator's 'Make a copy' works as expected.
+
+BEFORE:
+file:///var/www
+    script.js
+
+AFTER:
+file:///var/www
+    script.js
+    NewFile
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/navigator-create-file-copy.html b/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/navigator-create-file-copy.html
new file mode 100644
index 0000000..dff703e4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/navigator-create-file-copy.html
@@ -0,0 +1,31 @@
+<html>
+<head>
+<script src="../inspector-test.js"></script>
+<script src="../isolated-filesystem-test.js"></script>
+<script src="./persistence-test.js"></script>
+<script src="./automapping-test.js"></script>
+<script>
+
+async function test()
+{
+    var fs = new InspectorTest.TestFileSystem("file:///var/www");
+    InspectorTest.addFiles(fs, {
+        "script.js": { content: "testme" },
+    });
+    fs.reportCreated(function() { });
+    var uiSourceCode = await InspectorTest.waitForUISourceCode("script.js");
+
+    var sourcesNavigator = new Sources.SourcesNavigatorView();
+    sourcesNavigator.show(UI.inspectorView.element);
+    InspectorTest.addResult("BEFORE:\n" + fs.dumpAsText());
+    sourcesNavigator._handleContextMenuCreate(uiSourceCode.project(), '', uiSourceCode);
+    await InspectorTest.waitForUISourceCode("NewFile");
+    InspectorTest.addResult("\nAFTER:\n" + fs.dumpAsText());
+    InspectorTest.completeTest();
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Verify that navigator's 'Make a copy' works as expected.</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
index 7fe4d666..06583ef73 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
@@ -5079,6 +5079,7 @@
     method getLocalStreams
     method getReceivers
     method getRemoteStreams
+    method getSenders
     method getStats
     method getStreamById
     method removeStream
@@ -5107,6 +5108,10 @@
     getter track
     method constructor
     method getContributingSources
+interface RTCRtpSender
+    attribute @@toStringTag
+    getter track
+    method constructor
 interface RTCSessionDescription
     attribute @@toStringTag
     getter sdp
@@ -8715,6 +8720,7 @@
     method getLocalStreams
     method getReceivers
     method getRemoteStreams
+    method getSenders
     method getStats
     method getStreamById
     method removeStream
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index c3d44eb..c555517 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -5086,6 +5086,7 @@
     method getLocalStreams
     method getReceivers
     method getRemoteStreams
+    method getSenders
     method getStats
     method getStreamById
     method removeStream
@@ -5114,6 +5115,10 @@
     getter track
     method constructor
     method getContributingSources
+interface RTCRtpSender
+    attribute @@toStringTag
+    getter track
+    method constructor
 interface RTCSessionDescription
     attribute @@toStringTag
     getter sdp
@@ -8723,6 +8728,7 @@
     method getLocalStreams
     method getReceivers
     method getRemoteStreams
+    method getSenders
     method getStats
     method getStreamById
     method removeStream
diff --git a/third_party/WebKit/Source/core/frame/PerformanceMonitor.h b/third_party/WebKit/Source/core/frame/PerformanceMonitor.h
index 9a667ff..7679eb1b 100644
--- a/third_party/WebKit/Source/core/frame/PerformanceMonitor.h
+++ b/third_party/WebKit/Source/core/frame/PerformanceMonitor.h
@@ -120,7 +120,7 @@
   void DidProcessTask(scheduler::TaskQueue*,
                       double start_time,
                       double end_time) override;
-  void OnBeginNestedMessageLoop() override {}
+  void OnBeginNestedRunLoop() override {}
   void WillExecuteScript(ExecutionContext*);
   void DidExecuteScript();
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
index 62a35a08..7942168 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
@@ -579,6 +579,11 @@
    * @param {!Workspace.UISourceCode=} uiSourceCode
    */
   _handleContextMenuCreate(project, path, uiSourceCode) {
+    if (uiSourceCode) {
+      var relativePath = Persistence.FileSystemWorkspaceBinding.relativePath(uiSourceCode);
+      relativePath.pop();
+      path = relativePath.join('/');
+    }
     this.create(project, path, uiSourceCode);
   }
 
@@ -623,11 +628,9 @@
 
     var project = uiSourceCode.project();
     if (project.type() === Workspace.projectTypes.FileSystem) {
-      var parentURL = uiSourceCode.parentURL();
       contextMenu.appendItem(Common.UIString('Rename\u2026'), this._handleContextMenuRename.bind(this, node));
       contextMenu.appendItem(
-          Common.UIString('Make a copy\u2026'),
-          this._handleContextMenuCreate.bind(this, project, parentURL, uiSourceCode));
+          Common.UIString('Make a copy\u2026'), this._handleContextMenuCreate.bind(this, project, '', uiSourceCode));
       contextMenu.appendItem(Common.UIString('Delete'), this._handleContextMenuDelete.bind(this, uiSourceCode));
       contextMenu.appendSeparator();
     }
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystem.js b/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystem.js
index 594f826a..9d01ea1 100644
--- a/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystem.js
+++ b/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystem.js
@@ -210,7 +210,6 @@
           dirEntryLoaded.call(this, dirEntry);
           return;
         }
-
         var errorMessage = Workspace.IsolatedFileSystem.errorMessage(error);
         console.error(
             errorMessage + ' when testing if file exists \'' + (this._path + '/' + path + '/' + nameCandidate) + '\'');
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni
index 8253adb..25cabb6 100644
--- a/third_party/WebKit/Source/modules/modules_idl_files.gni
+++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -197,6 +197,7 @@
                     "peerconnection/RTCPeerConnectionIceEvent.idl",
                     "peerconnection/RTCRtpContributingSource.idl",
                     "peerconnection/RTCRtpReceiver.idl",
+                    "peerconnection/RTCRtpSender.idl",
                     "peerconnection/RTCSessionDescription.idl",
                     "peerconnection/RTCSessionDescriptionCallback.idl",
                     "peerconnection/RTCStatsCallback.idl",
diff --git a/third_party/WebKit/Source/modules/peerconnection/BUILD.gn b/third_party/WebKit/Source/modules/peerconnection/BUILD.gn
index 247f6ab..9eabaa5 100644
--- a/third_party/WebKit/Source/modules/peerconnection/BUILD.gn
+++ b/third_party/WebKit/Source/modules/peerconnection/BUILD.gn
@@ -29,6 +29,8 @@
     "RTCRtpContributingSource.h",
     "RTCRtpReceiver.cpp",
     "RTCRtpReceiver.h",
+    "RTCRtpSender.cpp",
+    "RTCRtpSender.h",
     "RTCSessionDescription.cpp",
     "RTCSessionDescription.h",
     "RTCSessionDescriptionCallback.h",
diff --git a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp
index c1f8016b..1ac6751 100644
--- a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp
+++ b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp
@@ -68,6 +68,7 @@
 #include "modules/peerconnection/RTCPeerConnectionErrorCallback.h"
 #include "modules/peerconnection/RTCPeerConnectionIceEvent.h"
 #include "modules/peerconnection/RTCRtpReceiver.h"
+#include "modules/peerconnection/RTCRtpSender.h"
 #include "modules/peerconnection/RTCSessionDescription.h"
 #include "modules/peerconnection/RTCSessionDescriptionCallback.h"
 #include "modules/peerconnection/RTCSessionDescriptionInit.h"
@@ -1123,6 +1124,9 @@
   local_streams_.erase(pos);
 
   peer_handler_->RemoveStream(stream->Descriptor());
+
+  // The senders of removed tracks will have become inactive.
+  RemoveInactiveSenders();
 }
 
 MediaStreamVector RTCPeerConnection::getLocalStreams() const {
@@ -1178,6 +1182,32 @@
   return promise;
 }
 
+HeapVector<Member<RTCRtpSender>> RTCPeerConnection::getSenders() {
+  WebVector<std::unique_ptr<WebRTCRtpSender>> web_rtp_senders =
+      peer_handler_->GetSenders();
+  HeapVector<Member<RTCRtpSender>> rtp_senders(web_rtp_senders.size());
+  for (size_t i = 0; i < web_rtp_senders.size(); ++i) {
+    uintptr_t id = web_rtp_senders[i]->Id();
+    const auto it = rtp_senders_.find(id);
+    if (it != rtp_senders_.end()) {
+      rtp_senders[i] = it->value;
+    } else {
+      // There does not exist an |RTCRtpSender| for this |WebRTCRtpSender|
+      // yet, create it.
+      MediaStreamTrack* track = nullptr;
+      if (web_rtp_senders[i]->Track()) {
+        track = GetLocalTrackById(web_rtp_senders[i]->Track()->Id());
+        DCHECK(track);
+      }
+      RTCRtpSender* rtp_sender =
+          new RTCRtpSender(std::move(web_rtp_senders[i]), track);
+      rtp_senders_.insert(id, rtp_sender);
+      rtp_senders[i] = rtp_sender;
+    }
+  }
+  return rtp_senders;
+}
+
 HeapVector<Member<RTCRtpReceiver>> RTCPeerConnection::getReceivers() {
   WebVector<std::unique_ptr<WebRTCRtpReceiver>> web_rtp_receivers =
       peer_handler_->GetReceivers();
@@ -1243,13 +1273,14 @@
   return channel;
 }
 
-bool RTCPeerConnection::HasLocalStreamWithTrackId(const String& track_id) {
-  for (MediaStreamVector::iterator iter = local_streams_.begin();
-       iter != local_streams_.end(); ++iter) {
-    if ((*iter)->getTrackById(track_id))
-      return true;
+MediaStreamTrack* RTCPeerConnection::GetLocalTrackById(
+    const String& track_id) const {
+  for (const auto& local_stream : local_streams_) {
+    MediaStreamTrack* track = local_stream->getTrackById(track_id);
+    if (track)
+      return track;
   }
-  return false;
+  return nullptr;
 }
 
 MediaStreamTrack* RTCPeerConnection::GetRemoteTrackById(
@@ -1262,6 +1293,19 @@
   return nullptr;
 }
 
+void RTCPeerConnection::RemoveInactiveSenders() {
+  std::set<uintptr_t> inactive_sender_ids;
+  for (uintptr_t id : rtp_senders_.Keys()) {
+    inactive_sender_ids.insert(id);
+  }
+  for (const auto& web_rtp_sender : peer_handler_->GetSenders()) {
+    inactive_sender_ids.erase(web_rtp_sender->Id());
+  }
+  for (uintptr_t id : inactive_sender_ids) {
+    rtp_senders_.erase(id);
+  }
+}
+
 void RTCPeerConnection::RemoveInactiveReceivers() {
   std::set<uintptr_t> inactive_receiver_ids;
   for (uintptr_t id : rtp_receivers_.Keys()) {
@@ -1283,7 +1327,7 @@
 
   DCHECK(track);
 
-  if (!HasLocalStreamWithTrackId(track->id())) {
+  if (!GetLocalTrackById(track->id())) {
     exception_state.ThrowDOMException(
         kSyntaxError, "No local stream is available for the track provided.");
     return nullptr;
@@ -1551,6 +1595,7 @@
 DEFINE_TRACE(RTCPeerConnection) {
   visitor->Trace(local_streams_);
   visitor->Trace(remote_streams_);
+  visitor->Trace(rtp_senders_);
   visitor->Trace(rtp_receivers_);
   visitor->Trace(dispatch_scheduled_event_runner_);
   visitor->Trace(scheduled_events_);
diff --git a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.h b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.h
index d90e314..765b7e4 100644
--- a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.h
+++ b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.h
@@ -58,6 +58,7 @@
 class RTCOfferOptions;
 class RTCPeerConnectionErrorCallback;
 class RTCRtpReceiver;
+class RTCRtpSender;
 class RTCSessionDescription;
 class RTCSessionDescriptionCallback;
 class RTCSessionDescriptionInit;
@@ -150,6 +151,7 @@
                          MediaStreamTrack* selector = nullptr);
   ScriptPromise getStats(ScriptState*);
 
+  HeapVector<Member<RTCRtpSender>> getSenders();
   HeapVector<Member<RTCRtpReceiver>> getReceivers();
 
   RTCDataChannel* createDataChannel(ScriptState*,
@@ -227,11 +229,13 @@
   void ScheduleDispatchEvent(Event*);
   void ScheduleDispatchEvent(Event*, std::unique_ptr<BoolFunction>);
   void DispatchScheduledEvent();
-  bool HasLocalStreamWithTrackId(const String& track_id);
+  MediaStreamTrack* GetLocalTrackById(const String& track_id) const;
   MediaStreamTrack* GetRemoteTrackById(const String& track_id) const;
-  // Receivers returned by the handler are in use by the peer connection, a
-  // receiver that is no longer in use is permanently inactive and does not need
-  // to be referenced anymore. Removes such receivers from |m_rtpReceivers|.
+  // Senders and receivers returned by the handler are in use by the peer
+  // connection, a sender or receiver that is no longer in use is permanently
+  // inactive and does not need to be referenced anymore. These methods removes
+  // such senders/receivers from |rtp_senders_|/|rtp_receivers_|.
+  void RemoveInactiveSenders();
   void RemoveInactiveReceivers();
 
   void ChangeSignalingState(WebRTCPeerConnectionHandlerClient::SignalingState);
@@ -259,6 +263,7 @@
   // relevant events. https://crbug.com/705901
   MediaStreamVector local_streams_;
   MediaStreamVector remote_streams_;
+  HeapHashMap<uintptr_t, Member<RTCRtpSender>> rtp_senders_;
   HeapHashMap<uintptr_t, Member<RTCRtpReceiver>> rtp_receivers_;
 
   std::unique_ptr<WebRTCPeerConnectionHandler> peer_handler_;
diff --git a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.idl b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.idl
index 47d1413..262ab9f 100644
--- a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.idl
+++ b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.idl
@@ -112,6 +112,8 @@
     // spec, remove it or change it?): https://github.com/w3c/webrtc-stats/issues/116
     [CallWith=ScriptState] Promise<RTCStatsReport> getStats();
 
+    // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-getsenders
+    [RuntimeEnabled=RTCRtpSender] sequence<RTCRtpSender> getSenders();
     // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-getreceivers
     sequence<RTCRtpReceiver> getReceivers();
 
diff --git a/third_party/WebKit/Source/modules/peerconnection/RTCRtpSender.cpp b/third_party/WebKit/Source/modules/peerconnection/RTCRtpSender.cpp
new file mode 100644
index 0000000..c31fd2c7
--- /dev/null
+++ b/third_party/WebKit/Source/modules/peerconnection/RTCRtpSender.cpp
@@ -0,0 +1,29 @@
+// 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 "modules/peerconnection/RTCRtpSender.h"
+
+#include "modules/mediastream/MediaStreamTrack.h"
+
+namespace blink {
+
+RTCRtpSender::RTCRtpSender(std::unique_ptr<WebRTCRtpSender> sender,
+                           MediaStreamTrack* track)
+    : sender_(std::move(sender)), track_(track) {
+  DCHECK(sender_);
+  DCHECK(track_);
+}
+
+MediaStreamTrack* RTCRtpSender::track() {
+  DCHECK((track_ && sender_->Track() &&
+          sender_->Track()->Id() == static_cast<WebString>(track_->id())) ||
+         (!track_ && !sender_->Track()));
+  return track_;
+}
+
+DEFINE_TRACE(RTCRtpSender) {
+  visitor->Trace(track_);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/peerconnection/RTCRtpSender.h b/third_party/WebKit/Source/modules/peerconnection/RTCRtpSender.h
new file mode 100644
index 0000000..ce79a2c
--- /dev/null
+++ b/third_party/WebKit/Source/modules/peerconnection/RTCRtpSender.h
@@ -0,0 +1,38 @@
+// 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.
+
+#ifndef RTCRtpSender_h
+#define RTCRtpSender_h
+
+#include "platform/bindings/ScriptWrappable.h"
+#include "platform/heap/GarbageCollected.h"
+#include "platform/heap/Member.h"
+#include "platform/heap/Visitor.h"
+#include "platform/wtf/text/WTFString.h"
+#include "public/platform/WebRTCRtpSender.h"
+
+namespace blink {
+
+class MediaStreamTrack;
+
+// https://w3c.github.io/webrtc-pc/#rtcrtpsender-interface
+class RTCRtpSender final : public GarbageCollectedFinalized<RTCRtpSender>,
+                           public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  RTCRtpSender(std::unique_ptr<WebRTCRtpSender>, MediaStreamTrack*);
+
+  MediaStreamTrack* track();
+
+  DECLARE_VIRTUAL_TRACE();
+
+ private:
+  std::unique_ptr<WebRTCRtpSender> sender_;
+  Member<MediaStreamTrack> track_;
+};
+
+}  // namespace blink
+
+#endif  // RTCRtpSender_h
diff --git a/third_party/WebKit/Source/modules/peerconnection/RTCRtpSender.idl b/third_party/WebKit/Source/modules/peerconnection/RTCRtpSender.idl
new file mode 100644
index 0000000..9b653b9a
--- /dev/null
+++ b/third_party/WebKit/Source/modules/peerconnection/RTCRtpSender.idl
@@ -0,0 +1,11 @@
+// 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.
+
+// https://w3c.github.io/webrtc-pc/#rtcrtpsender-interface
+[
+    RuntimeEnabled=RTCRtpSender,
+] interface RTCRtpSender {
+    readonly attribute MediaStreamTrack? track;
+    // TODO(hbos): Implement the rest of RTCRtpSender, https://crbug.com/700916.
+};
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index ae3facb..c95ffab 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -599,6 +599,7 @@
     "exported/WebRTCOfferOptions.cpp",
     "exported/WebRTCRtpContributingSource.cpp",
     "exported/WebRTCRtpReceiver.cpp",
+    "exported/WebRTCRtpSender.cpp",
     "exported/WebRTCSessionDescription.cpp",
     "exported/WebRTCSessionDescriptionRequest.cpp",
     "exported/WebRTCStats.cpp",
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
index bb729b10..dee8f3c 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -827,6 +827,10 @@
       name: "RootLayerScrolling",
     },
     {
+      name: "RTCRtpSender",
+      status: "experimental",
+    },
+    {
       name: "ScriptedSpeech",
       status: "stable",
     },
diff --git a/third_party/WebKit/Source/platform/exported/WebRTCRtpSender.cpp b/third_party/WebKit/Source/platform/exported/WebRTCRtpSender.cpp
new file mode 100644
index 0000000..54393666
--- /dev/null
+++ b/third_party/WebKit/Source/platform/exported/WebRTCRtpSender.cpp
@@ -0,0 +1,11 @@
+// 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 "public/platform/WebRTCRtpSender.h"
+
+namespace blink {
+
+WebRTCRtpSender::~WebRTCRtpSender() {}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.cc b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.cc
index 4ec835b..526122d 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.cc
@@ -77,8 +77,8 @@
   state_.OnTopLevelTaskCompleted(client_, task_end_time);
 }
 
-void QueueingTimeEstimator::OnBeginNestedMessageLoop() {
-  state_.OnBeginNestedMessageLoop();
+void QueueingTimeEstimator::OnBeginNestedRunLoop() {
+  state_.OnBeginNestedRunLoop();
 }
 
 void QueueingTimeEstimator::State::OnTopLevelTaskStarted(
@@ -124,7 +124,7 @@
   current_task_start_time = base::TimeTicks();
 }
 
-void QueueingTimeEstimator::State::OnBeginNestedMessageLoop() {
+void QueueingTimeEstimator::State::OnBeginNestedRunLoop() {
   in_nested_message_loop_ = true;
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.h b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.h
index 4bdd475..aea0e6b 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.h
@@ -31,7 +31,7 @@
    public:
     void OnTopLevelTaskStarted(base::TimeTicks task_start_time);
     void OnTopLevelTaskCompleted(Client* client, base::TimeTicks task_end_time);
-    void OnBeginNestedMessageLoop();
+    void OnBeginNestedRunLoop();
 
     base::TimeDelta current_expected_queueing_time;
     base::TimeDelta window_duration;
@@ -48,7 +48,7 @@
 
   void OnTopLevelTaskStarted(base::TimeTicks task_start_time);
   void OnTopLevelTaskCompleted(base::TimeTicks task_end_time);
-  void OnBeginNestedMessageLoop();
+  void OnBeginNestedRunLoop();
 
   // Returns all state except for the current |client_|.
   const State& GetState() const { return state_; }
diff --git a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator_unittest.cc
index 2baaa9d2..83f6d48 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator_unittest.cc
@@ -160,7 +160,7 @@
 
   estimator.OnTopLevelTaskStarted(time);
   time += base::TimeDelta::FromMilliseconds(20000);
-  estimator.OnBeginNestedMessageLoop();
+  estimator.OnBeginNestedRunLoop();
   estimator.OnTopLevelTaskCompleted(time);
 
   // Perform an additional task after the nested message loop. A 1 second task
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
index 487b7f4..7a2a92ba5 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
@@ -172,7 +172,7 @@
   }
 }
 
-void TaskQueueManager::OnBeginNestedMessageLoop() {
+void TaskQueueManager::OnBeginNestedRunLoop() {
   // We just entered a nested message loop, make sure there's a DoWork posted or
   // the system will grind to a halt.
   {
@@ -184,7 +184,7 @@
   // When a nested message loop starts, task time observers may want to ignore
   // the current task.
   for (auto& observer : task_time_observers_)
-    observer.OnBeginNestedMessageLoop();
+    observer.OnBeginNestedRunLoop();
 
   delegate_->PostTask(FROM_HERE, immediate_do_work_closure_);
 }
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
index 9ff0333..d193c56 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
@@ -14,6 +14,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/pending_task.h"
+#include "base/run_loop.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
 #include "platform/scheduler/base/enqueue_order.h"
@@ -53,7 +54,7 @@
 //
 class PLATFORM_EXPORT TaskQueueManager
     : public internal::TaskQueueSelector::Observer,
-      public base::MessageLoop::NestingObserver {
+      public base::RunLoop::NestingObserver {
  public:
   // Create a task queue manager where |delegate| identifies the thread
   // on which where the tasks are  eventually run. Category strings must have
@@ -233,8 +234,8 @@
   void OnTriedToSelectBlockedWorkQueue(
       internal::WorkQueue* work_queue) override;
 
-  // base::MessageLoop::NestingObserver implementation:
-  void OnBeginNestedMessageLoop() override;
+  // base::RunLoop::NestingObserver implementation:
+  void OnBeginNestedRunLoop() override;
 
   // Called by the task queue to register a new pending task.
   void DidQueueTask(const internal::TaskQueueImpl::Task& pending_task);
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate.h
index 988a24e..5d2dc5a 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate.h
@@ -7,7 +7,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "base/time/tick_clock.h"
 #include "platform/PlatformExport.h"
 
@@ -26,11 +26,10 @@
 
   // A NestingObserver is notified when a nested message loop begins. The
   // observers are notified before the first task is processed.
-  virtual void AddNestingObserver(
-      base::MessageLoop::NestingObserver* observer) = 0;
+  virtual void AddNestingObserver(base::RunLoop::NestingObserver* observer) = 0;
 
   virtual void RemoveNestingObserver(
-      base::MessageLoop::NestingObserver* observer) = 0;
+      base::RunLoop::NestingObserver* observer) = 0;
 
  protected:
   ~TaskQueueManagerDelegate() override {}
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate_for_test.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate_for_test.cc
index b22d977..46565d1 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate_for_test.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate_for_test.cc
@@ -52,10 +52,10 @@
 }
 
 void TaskQueueManagerDelegateForTest::AddNestingObserver(
-    base::MessageLoop::NestingObserver* observer) {}
+    base::RunLoop::NestingObserver* observer) {}
 
 void TaskQueueManagerDelegateForTest::RemoveNestingObserver(
-    base::MessageLoop::NestingObserver* observer) {}
+    base::RunLoop::NestingObserver* observer) {}
 
 base::TimeTicks TaskQueueManagerDelegateForTest::NowTicks() {
   return time_source_->NowTicks();
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate_for_test.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate_for_test.h
index 81495a4..b666826 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate_for_test.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate_for_test.h
@@ -21,7 +21,7 @@
       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
       std::unique_ptr<base::TickClock> time_source);
 
-  // NestableSingleThreadTaskRunner implementation
+  // SingleThreadTaskRunner:
   bool PostDelayedTask(const tracked_objects::Location& from_here,
                        base::OnceClosure task,
                        base::TimeDelta delay) override;
@@ -29,11 +29,13 @@
                                   base::OnceClosure task,
                                   base::TimeDelta delay) override;
   bool RunsTasksOnCurrentThread() const override;
+
+  // TaskQueueManagerDelegate:
   bool IsNested() const override;
-  void AddNestingObserver(
-      base::MessageLoop::NestingObserver* observer) override;
-  void RemoveNestingObserver(
-      base::MessageLoop::NestingObserver* observer) override;
+  void AddNestingObserver(base::RunLoop::NestingObserver* observer) override;
+  void RemoveNestingObserver(base::RunLoop::NestingObserver* observer) override;
+
+  // TickClock:
   base::TimeTicks NowTicks() override;
 
  protected:
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
index a282c4e2..9ad442b 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
@@ -60,19 +60,19 @@
     return make_scoped_refptr(new MessageLoopTaskRunner(std::move(tick_clock)));
   }
 
-  // NestableTaskRunner implementation.
+  // TaskQueueManagerDelegateForTest:
   bool IsNested() const override {
-    return base::MessageLoop::current()->IsNested();
+    DCHECK(RunsTasksOnCurrentThread());
+    return base::RunLoop::IsNestedOnCurrentThread();
   }
 
-  void AddNestingObserver(
-      base::MessageLoop::NestingObserver* observer) override {
-    base::MessageLoop::current()->AddNestingObserver(observer);
+  void AddNestingObserver(base::RunLoop::NestingObserver* observer) override {
+    base::RunLoop::AddNestingObserverOnCurrentThread(observer);
   }
 
   void RemoveNestingObserver(
-      base::MessageLoop::NestingObserver* observer) override {
-    base::MessageLoop::current()->RemoveNestingObserver(observer);
+      base::RunLoop::NestingObserver* observer) override {
+    base::RunLoop::RemoveNestingObserverOnCurrentThread(observer);
   }
 
  private:
@@ -1251,7 +1251,7 @@
 }
 
 void CheckIsNested(bool* is_nested) {
-  *is_nested = base::MessageLoop::current()->IsNested();
+  *is_nested = base::RunLoop::IsNestedOnCurrentThread();
 }
 
 void PostAndQuitFromNestedRunloop(base::RunLoop* run_loop,
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_time_observer.h b/third_party/WebKit/Source/platform/scheduler/base/task_time_observer.h
index 47ae3b94..34ab845 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_time_observer.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_time_observer.h
@@ -33,7 +33,7 @@
                               double end_time) = 0;
 
   // Callback to be called when we enter a nested message loop.
-  virtual void OnBeginNestedMessageLoop() = 0;
+  virtual void OnBeginNestedRunLoop() = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TaskTimeObserver);
diff --git a/third_party/WebKit/Source/platform/scheduler/base/test_task_time_observer.h b/third_party/WebKit/Source/platform/scheduler/base/test_task_time_observer.h
index 0af92aa..53538b9 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/test_task_time_observer.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/test_task_time_observer.h
@@ -17,7 +17,7 @@
   void DidProcessTask(TaskQueue* task_queue,
                       double start_time,
                       double end_time) override {}
-  void OnBeginNestedMessageLoop() override {}
+  void OnBeginNestedRunLoop() override {}
 };
 
 }  // namespace scheduler
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_for_test.cc b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_for_test.cc
index e296540..125ed8e7 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_for_test.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_for_test.cc
@@ -63,10 +63,10 @@
 }
 
 void SchedulerTqmDelegateForTest::AddNestingObserver(
-    base::MessageLoop::NestingObserver* observer) {}
+    base::RunLoop::NestingObserver* observer) {}
 
 void SchedulerTqmDelegateForTest::RemoveNestingObserver(
-    base::MessageLoop::NestingObserver* observer) {}
+    base::RunLoop::NestingObserver* observer) {}
 
 base::TimeTicks SchedulerTqmDelegateForTest::NowTicks() {
   return task_runner_->NowTicks();
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_for_test.h b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_for_test.h
index 5946dbc..167f3b9 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_for_test.h
+++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_for_test.h
@@ -35,10 +35,8 @@
                                   base::TimeDelta delay) override;
   bool RunsTasksOnCurrentThread() const override;
   bool IsNested() const override;
-  void AddNestingObserver(
-      base::MessageLoop::NestingObserver* observer) override;
-  void RemoveNestingObserver(
-      base::MessageLoop::NestingObserver* observer) override;
+  void AddNestingObserver(base::RunLoop::NestingObserver* observer) override;
+  void RemoveNestingObserver(base::RunLoop::NestingObserver* observer) override;
   base::TimeTicks NowTicks() override;
 
   base::SingleThreadTaskRunner* default_task_runner() const {
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl.cc b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl.cc
index 007dd53..ffbdb775 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl.cc
@@ -6,6 +6,8 @@
 
 #include <utility>
 
+#include "base/run_loop.h"
+
 namespace blink {
 namespace scheduler {
 
@@ -59,17 +61,18 @@
 }
 
 bool SchedulerTqmDelegateImpl::IsNested() const {
-  return message_loop_->IsNested();
+  DCHECK(RunsTasksOnCurrentThread());
+  return base::RunLoop::IsNestedOnCurrentThread();
 }
 
 void SchedulerTqmDelegateImpl::AddNestingObserver(
-    base::MessageLoop::NestingObserver* observer) {
-  message_loop_->AddNestingObserver(observer);
+    base::RunLoop::NestingObserver* observer) {
+  base::RunLoop::AddNestingObserverOnCurrentThread(observer);
 }
 
 void SchedulerTqmDelegateImpl::RemoveNestingObserver(
-    base::MessageLoop::NestingObserver* observer) {
-  message_loop_->RemoveNestingObserver(observer);
+    base::RunLoop::NestingObserver* observer) {
+  base::RunLoop::RemoveNestingObserverOnCurrentThread(observer);
 }
 
 base::TimeTicks SchedulerTqmDelegateImpl::NowTicks() {
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl.h b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl.h
index 2d34af4c..11579c3 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl.h
@@ -35,10 +35,8 @@
                                   base::TimeDelta delay) override;
   bool RunsTasksOnCurrentThread() const override;
   bool IsNested() const override;
-  void AddNestingObserver(
-      base::MessageLoop::NestingObserver* observer) override;
-  void RemoveNestingObserver(
-      base::MessageLoop::NestingObserver* observer) override;
+  void AddNestingObserver(base::RunLoop::NestingObserver* observer) override;
+  void RemoveNestingObserver(base::RunLoop::NestingObserver* observer) override;
   base::TimeTicks NowTicks() override;
 
  protected:
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc
index 8d616a4..51d629e 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc
@@ -154,7 +154,7 @@
   load_tracker_.RecordTaskTime(start_time_ticks, end_time_ticks);
 }
 
-void WorkerSchedulerImpl::OnBeginNestedMessageLoop() {}
+void WorkerSchedulerImpl::OnBeginNestedRunLoop() {}
 
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.h
index 945e125..1a895af 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.h
@@ -42,7 +42,7 @@
   void DidProcessTask(TaskQueue* task_queue,
                       double start_time,
                       double end_time) override;
-  void OnBeginNestedMessageLoop() override;
+  void OnBeginNestedRunLoop() override;
 
   SchedulerHelper* GetSchedulerHelperForTesting();
   base::TimeTicks CurrentIdleTaskDeadlineForTesting() const;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
index 1dd4c106..95439dc 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -1835,9 +1835,9 @@
                             static_cast<int>(TaskQueue::QueueType::COUNT));
 }
 
-void RendererSchedulerImpl::OnBeginNestedMessageLoop() {
+void RendererSchedulerImpl::OnBeginNestedRunLoop() {
   seqlock_queueing_time_estimator_.seqlock.WriteBegin();
-  seqlock_queueing_time_estimator_.data.OnBeginNestedMessageLoop();
+  seqlock_queueing_time_estimator_.data.OnBeginNestedRunLoop();
   seqlock_queueing_time_estimator_.seqlock.WriteEnd();
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
index 01ac87f..c7db139 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
@@ -136,7 +136,7 @@
   void DidProcessTask(TaskQueue* task_queue,
                       double start_time,
                       double end_time) override;
-  void OnBeginNestedMessageLoop() override;
+  void OnBeginNestedRunLoop() override;
 
   // QueueingTimeEstimator::Client implementation:
   void OnQueueingTimeForWindowEstimated(base::TimeDelta queueing_time) override;
diff --git a/third_party/WebKit/Source/platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc b/third_party/WebKit/Source/platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc
index bd41c59f..2dd45a8 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc
+++ b/third_party/WebKit/Source/platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
 #include "base/time/default_tick_clock.h"
 
 namespace blink {
@@ -44,7 +45,7 @@
   if (pending_task_runner_)
     message_loop_->SetTaskRunner(std::move(pending_task_runner_));
   if (pending_observer_)
-    message_loop_->AddNestingObserver(pending_observer_);
+    base::RunLoop::AddNestingObserverOnCurrentThread(pending_observer_);
   return message_loop_;
 }
 
@@ -90,26 +91,51 @@
 }
 
 bool LazySchedulerMessageLoopDelegateForTests::IsNested() const {
-  return EnsureMessageLoop()->IsNested();
+  DCHECK(RunsTasksOnCurrentThread());
+  EnsureMessageLoop();
+  return base::RunLoop::IsNestedOnCurrentThread();
 }
 
 void LazySchedulerMessageLoopDelegateForTests::AddNestingObserver(
-    base::MessageLoop::NestingObserver* observer) {
+    base::RunLoop::NestingObserver* observer) {
+  // While |observer| _could_ be associated with the current thread regardless
+  // of the presence of a MessageLoop, the association is delayed until
+  // EnsureMessageLoop() is invoked. This works around a state issue where
+  // otherwise many tests fail because of the following sequence:
+  //   1) blink::scheduler::CreateRendererSchedulerForTests()
+  //       -> TaskQueueManager::TaskQueueManager()
+  //       -> LazySchedulerMessageLoopDelegateForTests::AddNestingObserver()
+  //   2) Any test framework with a base::MessageLoop member (and not caring
+  //      about the blink scheduler) does:
+  //        ThreadTaskRunnerHandle::Get()->PostTask(
+  //            FROM_HERE, an_init_task_with_a_nested_loop);
+  //        RunLoop.RunUntilIdle();
+  //   3) |a_task_with_a_nested_loop| triggers
+  //          TaskQueueManager::OnBeginNestedLoop() which:
+  //            a) flags any_thread().is_nested = true;
+  //            b) posts a task to self, which triggers:
+  //                 LazySchedulerMessageLoopDelegateForTests::PostDelayedTask()
+  //   4) This self-task in turn triggers TaskQueueManager::DoWork()
+  //      which expects to be the only one to trigger nested loops (doesn't
+  //      support TaskQueueManager::OnBeginNestedLoop() being invoked before
+  //      it kicks in), resulting in it hitting:
+  //      DCHECK_EQ(any_thread().is_nested, delegate_->IsNested()); (1 vs 0).
+  // TODO(skyostil): fix this convulotion as part of http://crbug.com/495659.
   if (!HasMessageLoop()) {
     pending_observer_ = observer;
     return;
   }
-  message_loop_->AddNestingObserver(observer);
+  base::RunLoop::AddNestingObserverOnCurrentThread(observer);
 }
 
 void LazySchedulerMessageLoopDelegateForTests::RemoveNestingObserver(
-    base::MessageLoop::NestingObserver* observer) {
+    base::RunLoop::NestingObserver* observer) {
   if (!message_loop_ || message_loop_ != base::MessageLoop::current()) {
     DCHECK_EQ(pending_observer_, observer);
     pending_observer_ = nullptr;
     return;
   }
-  message_loop_->RemoveNestingObserver(observer);
+  base::RunLoop::RemoveNestingObserverOnCurrentThread(observer);
 }
 
 base::TimeTicks LazySchedulerMessageLoopDelegateForTests::NowTicks() {
diff --git a/third_party/WebKit/Source/platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h b/third_party/WebKit/Source/platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h
index bdbd746..18ab82c 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h
+++ b/third_party/WebKit/Source/platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h
@@ -9,10 +9,14 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "base/time/tick_clock.h"
 #include "platform/scheduler/child/scheduler_tqm_delegate.h"
 
+namespace base {
+class MessageLoop;
+}
+
 namespace blink {
 namespace scheduler {
 
@@ -39,10 +43,8 @@
                                   base::TimeDelta delay) override;
   bool RunsTasksOnCurrentThread() const override;
   bool IsNested() const override;
-  void AddNestingObserver(
-      base::MessageLoop::NestingObserver* observer) override;
-  void RemoveNestingObserver(
-      base::MessageLoop::NestingObserver* observer) override;
+  void AddNestingObserver(base::RunLoop::NestingObserver* observer) override;
+  void RemoveNestingObserver(base::RunLoop::NestingObserver* observer) override;
   base::TimeTicks NowTicks() override;
 
  private:
@@ -60,7 +62,7 @@
   mutable scoped_refptr<base::SingleThreadTaskRunner> original_task_runner_;
   std::unique_ptr<base::TickClock> time_source_;
 
-  base::MessageLoop::NestingObserver* pending_observer_;
+  base::RunLoop::NestingObserver* pending_observer_;
 
   DISALLOW_COPY_AND_ASSIGN(LazySchedulerMessageLoopDelegateForTests);
 };
diff --git a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
index 22e296b..c9c5d51 100644
--- a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
@@ -426,13 +426,8 @@
           parent_frame->GetSecurityContext()->GetFeaturePolicy();
     }
     WebParsedFeaturePolicy container_policy;
-    if (GetFrame() && GetFrame()->Owner()) {
-      container_policy = GetContainerPolicyFromAllowedFeatures(
-          GetFrame()->Owner()->AllowedFeatures(),
-          GetFrame()->Owner()->AllowFullscreen(),
-          GetFrame()->Owner()->AllowPaymentRequest(),
-          GetFrame()->GetSecurityContext()->GetSecurityOrigin());
-    }
+    if (GetFrame()->Owner())
+      container_policy = GetFrame()->Owner()->ContainerPolicy();
     GetFrame()->GetSecurityContext()->InitializeFeaturePolicy(
         parsed_header, container_policy, parent_feature_policy);
   }
diff --git a/third_party/WebKit/Source/web/tests/ActiveConnectionThrottlingTest.cpp b/third_party/WebKit/Source/web/tests/ActiveConnectionThrottlingTest.cpp
index 7997723f..63280d99 100644
--- a/third_party/WebKit/Source/web/tests/ActiveConnectionThrottlingTest.cpp
+++ b/third_party/WebKit/Source/web/tests/ActiveConnectionThrottlingTest.cpp
@@ -9,6 +9,7 @@
 #include "public/platform/WebRTCError.h"
 #include "public/platform/WebRTCPeerConnectionHandler.h"
 #include "public/platform/WebRTCRtpReceiver.h"
+#include "public/platform/WebRTCRtpSender.h"
 #include "public/platform/WebRTCSessionDescription.h"
 #include "public/web/WebScriptSource.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -80,6 +81,10 @@
   void RemoveStream(const WebMediaStream&) override {}
   void GetStats(const WebRTCStatsRequest&) override {}
   void GetStats(std::unique_ptr<WebRTCStatsReportCallback>) override {}
+  blink::WebVector<std::unique_ptr<blink::WebRTCRtpSender>> GetSenders()
+      override {
+    return blink::WebVector<std::unique_ptr<blink::WebRTCRtpSender>>();
+  }
   blink::WebVector<std::unique_ptr<blink::WebRTCRtpReceiver>> GetReceivers()
       override {
     return blink::WebVector<std::unique_ptr<blink::WebRTCRtpReceiver>>();
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index c7a5b21..a5098ade 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -292,6 +292,7 @@
     "platform/WebRTCPeerConnectionHandlerClient.h",
     "platform/WebRTCRtpContributingSource.h",
     "platform/WebRTCRtpReceiver.h",
+    "platform/WebRTCRtpSender.h",
     "platform/WebRTCSessionDescription.h",
     "platform/WebRTCSessionDescriptionRequest.h",
     "platform/WebRTCStats.h",
diff --git a/third_party/WebKit/public/platform/WebRTCPeerConnectionHandler.h b/third_party/WebKit/public/platform/WebRTCPeerConnectionHandler.h
index 75268f13..eefeb61 100644
--- a/third_party/WebKit/public/platform/WebRTCPeerConnectionHandler.h
+++ b/third_party/WebKit/public/platform/WebRTCPeerConnectionHandler.h
@@ -46,6 +46,7 @@
 class WebRTCICECandidate;
 class WebRTCOfferOptions;
 class WebRTCRtpReceiver;
+class WebRTCRtpSender;
 class WebRTCSessionDescription;
 class WebRTCSessionDescriptionRequest;
 class WebRTCStatsRequest;
@@ -94,6 +95,10 @@
   virtual WebRTCDataChannelHandler* CreateDataChannel(
       const WebString& label,
       const WebRTCDataChannelInit&) = 0;
+  // Gets senders used by the peer connection. These are wrappers referencing
+  // webrtc-layer senders, multiple |WebRTCRtpSender| objects referencing the
+  // same webrtc-layer sender have the same |id|.
+  virtual WebVector<std::unique_ptr<WebRTCRtpSender>> GetSenders() = 0;
   // Gets receivers used by the peer connection. These are wrappers referencing
   // webrtc-layer receivers, multiple |WebRTCRtpReceiver| objects referencing
   // the same webrtc-layer receiver have the same |id|.
diff --git a/third_party/WebKit/public/platform/WebRTCRtpSender.h b/third_party/WebKit/public/platform/WebRTCRtpSender.h
new file mode 100644
index 0000000..ebf9523
--- /dev/null
+++ b/third_party/WebKit/public/platform/WebRTCRtpSender.h
@@ -0,0 +1,32 @@
+// 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.
+
+#ifndef WebRTCRtpSender_h
+#define WebRTCRtpSender_h
+
+#include "WebCommon.h"
+#include "WebString.h"
+
+namespace blink {
+
+class WebMediaStreamTrack;
+
+// Implementations of this interface keep the corresponding WebRTC-layer sender
+// alive through reference counting. Multiple |WebRTCRtpSender|s could reference
+// the same sender; check for equality with |id|.
+// https://w3c.github.io/webrtc-pc/#rtcrtpsender-interface
+class BLINK_PLATFORM_EXPORT WebRTCRtpSender {
+ public:
+  virtual ~WebRTCRtpSender();
+
+  // Two |WebRTCRtpSender|s referencing the same WebRTC-layer sender have the
+  // same |id|. IDs are guaranteed to be unique amongst senders but they are
+  // allowed to be reused after a sender is destroyed.
+  virtual uintptr_t Id() const = 0;
+  virtual const WebMediaStreamTrack* Track() const = 0;
+};
+
+}  // namespace blink
+
+#endif  // WebRTCRtpSender_h
diff --git a/tools/binary_size/diagnose_bloat.py b/tools/binary_size/diagnose_bloat.py
index 0f0e2e6..fe1a3f5 100755
--- a/tools/binary_size/diagnose_bloat.py
+++ b/tools/binary_size/diagnose_bloat.py
@@ -296,20 +296,10 @@
     """Save build artifacts necessary for diffing."""
     logging.info('Saving build results to: %s', self.dir)
     _EnsureDirsExist(self.dir)
-    build = self.build
-    self._ArchiveFile(build.abs_main_lib_path)
-    tool_prefix = _FindToolPrefix(build.output_directory)
-    size_path = os.path.join(self.dir, build.size_name)
-    supersize_cmd = [supersize_path, 'archive', size_path, '--elf-file',
-                     build.abs_main_lib_path, '--tool-prefix', tool_prefix,
-                     '--output-directory', build.output_directory,
-                     '--no-source-paths']
-    if build.IsAndroid():
-      supersize_cmd += ['--apk-file', build.abs_apk_path]
-      self._ArchiveFile(build.abs_apk_path)
-
-    logging.info('Creating .size file')
-    _RunCmd(supersize_cmd)
+    self._ArchiveFile(self.build.abs_main_lib_path)
+    if self.build.IsAndroid():
+      self._ArchiveFile(self.build.abs_apk_path)
+    self._ArchiveSizeFile(supersize_path)
     self.metadata.Write()
 
   def Exists(self):
@@ -320,6 +310,24 @@
       _Die('missing expected file: %s', filename)
     shutil.copy(filename, self.dir)
 
+  def _ArchiveSizeFile(self, supersize_path):
+    existing_size_file = self.build.abs_apk_path + '.size'
+    if os.path.exists(existing_size_file):
+      logging.info('Found existing .size file')
+      os.rename(
+          existing_size_file, os.path.join(self.dir, self.build.size_name))
+    else:
+      tool_prefix = _FindToolPrefix(self.build.output_directory)
+      size_path = os.path.join(self.dir, self.build.size_name)
+      supersize_cmd = [supersize_path, 'archive', size_path, '--elf-file',
+                       self.build.abs_main_lib_path, '--tool-prefix',
+                       tool_prefix, '--output-directory',
+                       self.build.output_directory, '--no-source-paths']
+      if self.build.IsAndroid():
+        supersize_cmd += ['--apk-file', self.build.abs_apk_path]
+      logging.info('Creating .size file')
+      _RunCmd(supersize_cmd)
+
 
 class _DiffArchiveManager(object):
   """Class for maintaining BuildArchives and their related diff artifacts."""
@@ -609,7 +617,7 @@
   # Files needed for supersize and resource_sizes. Paths relative to out dir.
   to_extract = [build.main_lib_path, build.map_file_path, 'args.gn']
   if build.IsAndroid():
-    to_extract += ['build_vars.txt', build.apk_path]
+    to_extract += ['build_vars.txt', build.apk_path, build.apk_path + '.size']
   extract_dir = dl_dst + '_' + 'unzipped'
   # Storage bucket stores entire output directory including out/Release prefix.
   logging.info('Extracting build artifacts')
@@ -622,12 +630,14 @@
 
 
 def _ExtractFiles(to_extract, prefix, dst, z):
-  zip_infos = z.infolist()
-  assert all(info.filename.startswith(prefix) for info in zip_infos), (
+  """Extract prefixed files in |to_extract| from |z| if they exist."""
+  zipped_names = z.namelist()
+  assert all(name.startswith(prefix) for name in zipped_names), (
       'Storage bucket folder structure doesn\'t start with %s' % prefix)
   to_extract = [os.path.join(prefix, f) for f in to_extract]
   for f in to_extract:
-    z.extract(f, path=dst)
+    if f in zipped_names:
+      z.extract(f, path=dst)
 
 
 def _PrintAndWriteToFile(logfile, s, *args, **kwargs):
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 239a2a6..43dc94dd 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -245,7 +245,7 @@
   base::win::ScopedComPtr<IAccessible> parent_accessible;
   if (S_OK != get_accParent(parent_dispatch.Receive()))
     return -1;
-  if (S_OK != parent_dispatch.QueryInterface(parent_accessible.Receive()))
+  if (S_OK != parent_dispatch.CopyTo(parent_accessible.Receive()))
     return -1;
 
   LONG child_count = 0;
@@ -257,7 +257,7 @@
     base::win::ScopedComPtr<IAccessible> child_accessible;
     if (S_OK == parent_accessible->get_accChild(childid_index,
                                                 child_dispatch.Receive()) &&
-        S_OK == child_dispatch.QueryInterface(child_accessible.Receive())) {
+        S_OK == child_dispatch.CopyTo(child_accessible.Receive())) {
       if (child_accessible.Get() == this)
         return index - 1;
     }
diff --git a/ui/aura/mus/mus_mouse_location_updater.cc b/ui/aura/mus/mus_mouse_location_updater.cc
index cbf89bd..fbb43f27 100644
--- a/ui/aura/mus/mus_mouse_location_updater.cc
+++ b/ui/aura/mus/mus_mouse_location_updater.cc
@@ -29,11 +29,11 @@
 }  // namespace
 
 MusMouseLocationUpdater::MusMouseLocationUpdater() {
-  base::MessageLoop::current()->AddNestingObserver(this);
+  base::RunLoop::AddNestingObserverOnCurrentThread(this);
 }
 
 MusMouseLocationUpdater::~MusMouseLocationUpdater() {
-  base::MessageLoop::current()->RemoveNestingObserver(this);
+  base::RunLoop::RemoveNestingObserverOnCurrentThread(this);
 }
 
 void MusMouseLocationUpdater::OnEventProcessingStarted(const ui::Event& event) {
@@ -60,7 +60,7 @@
   Env::GetInstance()->get_last_mouse_location_from_mus_ = true;
 }
 
-void MusMouseLocationUpdater::OnBeginNestedMessageLoop() {
+void MusMouseLocationUpdater::OnBeginNestedRunLoop() {
   UseCursorScreenPoint();
 }
 
diff --git a/ui/aura/mus/mus_mouse_location_updater.h b/ui/aura/mus/mus_mouse_location_updater.h
index d820049..982fdac2 100644
--- a/ui/aura/mus/mus_mouse_location_updater.h
+++ b/ui/aura/mus/mus_mouse_location_updater.h
@@ -6,7 +6,7 @@
 #define UI_AURA_MUS_MUS_MOUSE_LOCATION_UPDATER_H_
 
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 
 namespace ui {
 class Event;
@@ -21,7 +21,7 @@
 // Env uses the value from the current event, otherwise Env uses
 // WindowTreeClient::GetCursorScreenPoint(). If a nested message loop is
 // started while processing an event Env uses GetCursorScreenPoint().
-class MusMouseLocationUpdater : public base::MessageLoop::NestingObserver {
+class MusMouseLocationUpdater : public base::RunLoop::NestingObserver {
  public:
   MusMouseLocationUpdater();
   ~MusMouseLocationUpdater() override;
@@ -36,8 +36,8 @@
   // location.
   void UseCursorScreenPoint();
 
-  // base::MessageLoop::NestingObserver:
-  void OnBeginNestedMessageLoop() override;
+  // base::RunLoop::NestingObserver:
+  void OnBeginNestedRunLoop() override;
 
   // Set to true while processing a valid mouse event.
   bool is_processing_trigger_event_ = false;
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc
index f264e4d..950bf1f 100644
--- a/ui/aura/mus/window_tree_client.cc
+++ b/ui/aura/mus/window_tree_client.cc
@@ -14,6 +14,8 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "base/threading/thread.h"
 #include "cc/base/switches.h"
 #include "components/discardable_memory/client/client_discardable_shared_memory_manager.h"
@@ -86,16 +88,16 @@
 
 // Handles acknowledgment of an input event, either immediately when a nested
 // message loop starts, or upon destruction.
-class EventAckHandler : public base::MessageLoop::NestingObserver {
+class EventAckHandler : public base::RunLoop::NestingObserver {
  public:
   explicit EventAckHandler(std::unique_ptr<EventResultCallback> ack_callback)
       : ack_callback_(std::move(ack_callback)) {
     DCHECK(ack_callback_);
-    base::MessageLoop::current()->AddNestingObserver(this);
+    base::RunLoop::AddNestingObserverOnCurrentThread(this);
   }
 
   ~EventAckHandler() override {
-    base::MessageLoop::current()->RemoveNestingObserver(this);
+    base::RunLoop::RemoveNestingObserverOnCurrentThread(this);
     if (ack_callback_) {
       ack_callback_->Run(handled_ ? ui::mojom::EventResult::HANDLED
                                   : ui::mojom::EventResult::UNHANDLED);
@@ -104,8 +106,8 @@
 
   void set_handled(bool handled) { handled_ = handled; }
 
-  // base::MessageLoop::NestingObserver:
-  void OnBeginNestedMessageLoop() override {
+  // base::RunLoop::NestingObserver:
+  void OnBeginNestedRunLoop() override {
     // Acknowledge the event immediately if a nested message loop starts.
     // Otherwise we appear unresponsive for the life of the nested message loop.
     if (ack_callback_) {
diff --git a/ui/aura/window_event_dispatcher_unittest.cc b/ui/aura/window_event_dispatcher_unittest.cc
index 3d4e153ca..135849f 100644
--- a/ui/aura/window_event_dispatcher_unittest.cc
+++ b/ui/aura/window_event_dispatcher_unittest.cc
@@ -2116,7 +2116,7 @@
 };
 
 TEST_P(WindowEventDispatcherTestWithMessageLoop, EventRepostedInNonNestedLoop) {
-  CHECK(!message_loop()->is_running());
+  ASSERT_FALSE(base::RunLoop::IsRunningOnCurrentThread());
   // Perform the test in a callback, so that it runs after the message-loop
   // starts.
   message_loop()->task_runner()->PostTask(
diff --git a/ui/gfx/font_fallback_win.cc b/ui/gfx/font_fallback_win.cc
index 6352cfe..d01547d 100644
--- a/ui/gfx/font_fallback_win.cc
+++ b/ui/gfx/font_fallback_win.cc
@@ -359,7 +359,7 @@
   base::win::ScopedComPtr<IDWriteFactory> factory;
   gfx::win::CreateDWriteFactory(factory.Receive());
   base::win::ScopedComPtr<IDWriteFactory2> factory2;
-  factory.QueryInterface(factory2.Receive());
+  factory.CopyTo(factory2.Receive());
   if (!factory2) {
     // IDWriteFactory2 is not available before Win8.1
     return GetUniscribeFallbackFont(font, text, text_length, result);
diff --git a/ui/gfx/win/direct_write.cc b/ui/gfx/win/direct_write.cc
index 8645ae85..341ffe9 100644
--- a/ui/gfx/win/direct_write.cc
+++ b/ui/gfx/win/direct_write.cc
@@ -29,7 +29,7 @@
     CHECK(false);
     return;
   }
-  factory_unknown.QueryInterface<IDWriteFactory>(factory);
+  factory_unknown.CopyTo(factory);
 }
 
 void MaybeInitializeDirectWrite() {
diff --git a/ui/gl/gl_angle_util_win.cc b/ui/gl/gl_angle_util_win.cc
index 179b971..29d8dcf 100644
--- a/ui/gl/gl_angle_util_win.cc
+++ b/ui/gl/gl_angle_util_win.cc
@@ -119,14 +119,14 @@
     return dcomp_device;
 
   base::win::ScopedComPtr<IDXGIDevice> dxgi_device;
-  d3d11_device.QueryInterface(dxgi_device.Receive());
+  d3d11_device.CopyTo(dxgi_device.Receive());
   base::win::ScopedComPtr<IDCompositionDesktopDevice> desktop_device;
   hr = create_device_function(dxgi_device.Get(),
                               IID_PPV_ARGS(desktop_device.Receive()));
   if (FAILED(hr))
     return dcomp_device;
 
-  hr = desktop_device.QueryInterface(dcomp_device.Receive());
+  hr = desktop_device.CopyTo(dcomp_device.Receive());
   CHECK(SUCCEEDED(hr));
   d3d11_device->SetPrivateDataInterface(kDirectCompositionGUID,
                                         dcomp_device.Get());
diff --git a/ui/views/accessibility/native_view_accessibility_win_unittest.cc b/ui/views/accessibility/native_view_accessibility_win_unittest.cc
index 3265ee7..631e03c 100644
--- a/ui/views/accessibility/native_view_accessibility_win_unittest.cc
+++ b/ui/views/accessibility/native_view_accessibility_win_unittest.cc
@@ -29,7 +29,7 @@
     ScopedComPtr<IAccessible> view_accessible(
         view->GetNativeViewAccessible());
     ScopedComPtr<IServiceProvider> service_provider;
-    ASSERT_EQ(S_OK, view_accessible.QueryInterface(service_provider.Receive()));
+    ASSERT_EQ(S_OK, view_accessible.CopyTo(service_provider.Receive()));
     ASSERT_EQ(S_OK,
         service_provider->QueryService(IID_IAccessible2_2, result));
   }
@@ -61,7 +61,7 @@
   ScopedVariant child_index(1);
   ASSERT_EQ(S_OK, content_accessible->get_accChild(
       child_index, textfield_dispatch.Receive()));
-  ASSERT_EQ(S_OK, textfield_dispatch.QueryInterface(
+  ASSERT_EQ(S_OK, textfield_dispatch.CopyTo(
       textfield_accessible.Receive()));
 
   ScopedBstr name;
@@ -100,7 +100,7 @@
   ScopedVariant child_index_1(1);
   ASSERT_EQ(S_OK, root_view_accessible->get_accChild(
       child_index_1, child_view_dispatch.Receive()));
-  ASSERT_EQ(S_OK, child_view_dispatch.QueryInterface(
+  ASSERT_EQ(S_OK, child_view_dispatch.CopyTo(
       child_view_accessible.Receive()));
 
   Widget owned_widget;
@@ -119,7 +119,7 @@
   ScopedVariant child_index_2(2);
   ASSERT_EQ(S_OK, root_view_accessible->get_accChild(
       child_index_2, child_widget_dispatch.Receive()));
-  ASSERT_EQ(S_OK, child_widget_dispatch.QueryInterface(
+  ASSERT_EQ(S_OK, child_widget_dispatch.CopyTo(
       child_widget_accessible.Receive()));
 
   ScopedComPtr<IDispatch> child_widget_sibling_dispatch;
@@ -130,7 +130,7 @@
       NAVDIR_PREVIOUS, childid_self, result.Receive()));
   ASSERT_EQ(VT_DISPATCH, V_VT(result.ptr()));
   child_widget_sibling_dispatch = V_DISPATCH(result.ptr());
-  ASSERT_EQ(S_OK, child_widget_sibling_dispatch.QueryInterface(
+  ASSERT_EQ(S_OK, child_widget_sibling_dispatch.CopyTo(
       child_widget_sibling_accessible.Receive()));
   ASSERT_EQ(child_view_accessible.Get(), child_widget_sibling_accessible.Get());
 
@@ -138,7 +138,7 @@
   ScopedComPtr<IAccessible> child_widget_parent_accessible;
   ASSERT_EQ(S_OK, child_widget_accessible->get_accParent(
       child_widget_parent_dispatch.Receive()));
-  ASSERT_EQ(S_OK, child_widget_parent_dispatch.QueryInterface(
+  ASSERT_EQ(S_OK, child_widget_parent_dispatch.CopyTo(
       child_widget_parent_accessible.Receive()));
   ASSERT_EQ(root_view_accessible.Get(), child_widget_parent_accessible.Get());
 }