diff --git a/components/viz/host/host_frame_sink_manager.cc b/components/viz/host/host_frame_sink_manager.cc
index d6af712..25d4003 100644
--- a/components/viz/host/host_frame_sink_manager.cc
+++ b/components/viz/host/host_frame_sink_manager.cc
@@ -30,7 +30,7 @@
 
 void HostFrameSinkManager::BindAndSetManager(
     cc::mojom::FrameSinkManagerClientRequest request,
-    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     cc::mojom::FrameSinkManagerPtr ptr) {
   DCHECK(!frame_sink_manager_impl_);
   DCHECK(!binding_.is_bound());
diff --git a/components/viz/host/host_frame_sink_manager.h b/components/viz/host/host_frame_sink_manager.h
index db76c340..bcfd9fa 100644
--- a/components/viz/host/host_frame_sink_manager.h
+++ b/components/viz/host/host_frame_sink_manager.h
@@ -20,7 +20,7 @@
 #include "mojo/public/cpp/bindings/binding.h"
 
 namespace base {
-class SequencedTaskRunner;
+class SingleThreadTaskRunner;
 }
 
 namespace cc {
@@ -52,9 +52,10 @@
   // Binds |this| as a FrameSinkManagerClient for |request| on |task_runner|. On
   // Mac |task_runner| will be the resize helper task runner. May only be called
   // once.
-  void BindAndSetManager(cc::mojom::FrameSinkManagerClientRequest request,
-                         scoped_refptr<base::SequencedTaskRunner> task_runner,
-                         cc::mojom::FrameSinkManagerPtr ptr);
+  void BindAndSetManager(
+      cc::mojom::FrameSinkManagerClientRequest request,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      cc::mojom::FrameSinkManagerPtr ptr);
 
   void AddObserver(FrameSinkObserver* observer);
   void RemoveObserver(FrameSinkObserver* observer);
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index 61a6ceb..795212fd 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -35,7 +35,7 @@
 
 void FrameSinkManagerImpl::BindAndSetClient(
     cc::mojom::FrameSinkManagerRequest request,
-    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     cc::mojom::FrameSinkManagerClientPtr client) {
   DCHECK(!client_);
   DCHECK(!binding_.is_bound());
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
index 5dd3b25..a24afed 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.h
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -23,7 +23,7 @@
 #include "mojo/public/cpp/bindings/binding.h"
 
 namespace base {
-class SequencedTaskRunner;
+class SingleThreadTaskRunner;
 }
 
 namespace viz {
@@ -53,7 +53,7 @@
   // |task_runner| will be the resize helper task runner. May only be called
   // once.
   void BindAndSetClient(cc::mojom::FrameSinkManagerRequest request,
-                        scoped_refptr<base::SequencedTaskRunner> task_runner,
+                        scoped_refptr<base::SingleThreadTaskRunner> task_runner,
                         cc::mojom::FrameSinkManagerClientPtr client);
 
   // Sets up a direction connection to |client| without using Mojo.
diff --git a/content/browser/compositor/surface_utils.cc b/content/browser/compositor/surface_utils.cc
index e70b74fe..b429ef45 100644
--- a/content/browser/compositor/surface_utils.cc
+++ b/content/browser/compositor/surface_utils.cc
@@ -220,7 +220,7 @@
 void ConnectWithInProcessFrameSinkManager(
     viz::HostFrameSinkManager* host,
     viz::FrameSinkManagerImpl* manager,
-    scoped_refptr<base::SequencedTaskRunner> task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   // A mojo pointer to |host| which is the FrameSinkManager's client.
   cc::mojom::FrameSinkManagerClientPtr host_mojo;
   // A mojo pointer to |manager|.
diff --git a/content/browser/compositor/surface_utils.h b/content/browser/compositor/surface_utils.h
index 997edaf6..1632909 100644
--- a/content/browser/compositor/surface_utils.h
+++ b/content/browser/compositor/surface_utils.h
@@ -15,7 +15,7 @@
 #include "ui/gfx/geometry/size.h"
 
 namespace base {
-class SequencedTaskRunner;
+class SingleThreadTaskRunner;
 }
 
 namespace cc {
@@ -53,7 +53,7 @@
 CONTENT_EXPORT void ConnectWithInProcessFrameSinkManager(
     viz::HostFrameSinkManager* host_frame_sink_manager,
     viz::FrameSinkManagerImpl* frame_sink_manager_impl,
-    scoped_refptr<base::SequencedTaskRunner> task_runner);
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
 }  // namespace surface_utils
 
diff --git a/content/common/quarantine/quarantine_mac.mm b/content/common/quarantine/quarantine_mac.mm
index c407233d593..8dff600 100644
--- a/content/common/quarantine/quarantine_mac.mm
+++ b/content/common/quarantine/quarantine_mac.mm
@@ -10,6 +10,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
+#include "base/mac/availability.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/mac_logging.h"
 #include "base/mac/mac_util.h"
@@ -76,6 +77,7 @@
 #pragma clang diagnostic pop
 #endif
 
+API_AVAILABLE(macos(10.10))
 bool GetQuarantineProperties(
     const base::FilePath& file,
     base::scoped_nsobject<NSMutableDictionary>* properties) {
@@ -84,15 +86,11 @@
   if (!file_url)
     return false;
 
-// NSURLQuarantinePropertiesKey is only available on macOS 10.10+.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability"
   NSError* error = nil;
   id quarantine_properties = nil;
   BOOL success = [file_url getResourceValue:&quarantine_properties
                                      forKey:NSURLQuarantinePropertiesKey
                                       error:&error];
-#pragma clang diagnostic pop
   if (!success) {
     std::string error_message(error ? error.description.UTF8String : "");
     LOG(WARNING) << "Unable to get quarantine attributes for file "
@@ -116,6 +114,7 @@
   return true;
 }
 
+API_AVAILABLE(macos(10.10))
 bool SetQuarantineProperties(const base::FilePath& file,
                              NSDictionary* properties) {
   base::scoped_nsobject<NSURL> file_url([[NSURL alloc]
@@ -123,14 +122,10 @@
   if (!file_url)
     return false;
 
-// NSURLQuarantinePropertiesKey is only available on macOS 10.10+.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability"
   NSError* error = nil;
   bool success = [file_url setResourceValue:properties
                                      forKey:NSURLQuarantinePropertiesKey
                                       error:&error];
-#pragma clang diagnostic pop
   if (!success) {
     std::string error_message(error ? error.description.UTF8String : "");
     LOG(WARNING) << "Unable to set quarantine attributes on file "
@@ -241,7 +236,7 @@
   base::ThreadRestrictions::AssertIOAllowed();
   base::scoped_nsobject<NSMutableDictionary> properties;
   bool success = false;
-  if (base::mac::IsAtLeastOS10_10()) {
+  if (@available(macos 10.10, *)) {
     success = GetQuarantineProperties(file, &properties);
   } else {
     success = GetQuarantinePropertiesDeprecated(file, &properties);
@@ -285,7 +280,7 @@
     [properties setValue:origin_url forKey:(NSString*)kLSQuarantineDataURLKey];
   }
 
-  if (base::mac::IsAtLeastOS10_10()) {
+  if (@available(macos 10.10, *)) {
     return SetQuarantineProperties(file, properties);
   } else {
     return SetQuarantinePropertiesDeprecated(file, properties);
@@ -319,7 +314,7 @@
 
   base::scoped_nsobject<NSMutableDictionary> properties;
   bool success = false;
-  if (base::mac::IsAtLeastOS10_10()) {
+  if (@available(macos 10.10, *)) {
     success = GetQuarantineProperties(file, &properties);
   } else {
     success = GetQuarantinePropertiesDeprecated(file, &properties);
diff --git a/content/common/quarantine/quarantine_mac_unittest.mm b/content/common/quarantine/quarantine_mac_unittest.mm
index 4e3cf6d..2723d4db 100644
--- a/content/common/quarantine/quarantine_mac_unittest.mm
+++ b/content/common/quarantine/quarantine_mac_unittest.mm
@@ -10,6 +10,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
+#include "base/mac/availability.h"
 #include "base/mac/mac_util.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
@@ -29,32 +30,28 @@
 
  protected:
   void SetUp() override {
-    if (base::mac::IsAtMostOS10_9()) {
-      LOG(WARNING) << "Test suite requires Mac OS X 10.10 or later";
-      return;
-    }
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    ASSERT_TRUE(
-        base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &test_file_));
-    file_url_.reset([[NSURL alloc]
-        initFileURLWithPath:base::SysUTF8ToNSString(test_file_.value())]);
+    if (@available(macos 10.10, *)) {
+      ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+      ASSERT_TRUE(
+          base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &test_file_));
+      file_url_.reset([[NSURL alloc]
+          initFileURLWithPath:base::SysUTF8ToNSString(test_file_.value())]);
 
-    base::scoped_nsobject<NSMutableDictionary> properties(
-        [[NSMutableDictionary alloc] init]);
-    [properties
-        setValue:@"com.google.Chrome"
-          forKey:static_cast<NSString*>(kLSQuarantineAgentBundleIdentifierKey)];
-    [properties setValue:@"Google Chrome.app"
-                  forKey:static_cast<NSString*>(kLSQuarantineAgentNameKey)];
-    [properties setValue:@(1) forKey:@"kLSQuarantineIsOwnedByCurrentUserKey"];
-// NSURLQuarantinePropertiesKey is only available on macOS 10.10+.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability"
-    bool success = [file_url_ setResourceValue:properties
-                                        forKey:NSURLQuarantinePropertiesKey
-                                         error:nullptr];
-#pragma clang diagnostic pop
-    ASSERT_TRUE(success);
+      base::scoped_nsobject<NSMutableDictionary> properties(
+          [[NSMutableDictionary alloc] init]);
+      [properties setValue:@"com.google.Chrome"
+                    forKey:static_cast<NSString*>(
+                               kLSQuarantineAgentBundleIdentifierKey)];
+      [properties setValue:@"Google Chrome.app"
+                    forKey:static_cast<NSString*>(kLSQuarantineAgentNameKey)];
+      [properties setValue:@(1) forKey:@"kLSQuarantineIsOwnedByCurrentUserKey"];
+      bool success = [file_url_ setResourceValue:properties
+                                          forKey:NSURLQuarantinePropertiesKey
+                                           error:nullptr];
+      ASSERT_TRUE(success);
+    } else {
+      LOG(WARNING) << "Test suite requires Mac OS X 10.10 or later";
+    }
   }
 
   base::ScopedTempDir temp_dir_;
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
index fa00667..8af8fc2 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
@@ -34,13 +34,12 @@
   MOCK_METHOD1(DoCreateChannel,
                void(arc::mojom::CameraModuleRequest& camera_module_request));
 
-  arc::mojom::CameraHalServerPtr GetInterfacePtr(
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-    arc::mojom::CameraHalServerPtr camera_hal_server_ptr;
+  arc::mojom::CameraHalServerPtrInfo GetInterfacePtrInfo() {
+    arc::mojom::CameraHalServerPtrInfo camera_hal_server_ptr_info;
     arc::mojom::CameraHalServerRequest camera_hal_server_request =
-        mojo::MakeRequest(&camera_hal_server_ptr, std::move(task_runner));
+        mojo::MakeRequest(&camera_hal_server_ptr_info);
     binding_.Bind(std::move(camera_hal_server_request));
-    return camera_hal_server_ptr;
+    return camera_hal_server_ptr_info;
   }
 
  private:
@@ -60,13 +59,12 @@
   MOCK_METHOD1(DoSetUpChannel,
                void(arc::mojom::CameraModulePtr& camera_module_ptr));
 
-  arc::mojom::CameraHalClientPtr GetInterfacePtr(
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-    arc::mojom::CameraHalClientPtr camera_hal_client_ptr;
+  arc::mojom::CameraHalClientPtrInfo GetInterfacePtrInfo() {
+    arc::mojom::CameraHalClientPtrInfo camera_hal_client_ptr_info;
     arc::mojom::CameraHalClientRequest camera_hal_client_request =
-        mojo::MakeRequest(&camera_hal_client_ptr, std::move(task_runner));
+        mojo::MakeRequest(&camera_hal_client_ptr_info);
     binding_.Bind(std::move(camera_hal_client_request));
-    return camera_hal_client_ptr;
+    return camera_hal_client_ptr_info;
   }
 
  private:
@@ -104,6 +102,16 @@
     }
   }
 
+  static void RegisterServer(CameraHalDispatcherImpl* dispatcher,
+                             arc::mojom::CameraHalServerPtrInfo server) {
+    dispatcher->RegisterServer(mojo::MakeProxy(std::move(server)));
+  }
+
+  static void RegisterClient(CameraHalDispatcherImpl* dispatcher,
+                             arc::mojom::CameraHalClientPtrInfo client) {
+    dispatcher->RegisterClient(mojo::MakeProxy(std::move(client)));
+  }
+
  protected:
   // We can't use std::unique_ptr here because the constructor and destructor of
   // CameraHalDispatcherImpl are private.
@@ -129,15 +137,15 @@
       .WillOnce(
           InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop));
 
-  auto server_ptr = mock_server->GetInterfacePtr(GetProxyTaskRunner());
+  auto server_ptr = mock_server->GetInterfacePtrInfo();
   GetProxyTaskRunner()->PostTask(
       FROM_HERE,
-      base::BindOnce(&CameraHalDispatcherImpl::RegisterServer,
+      base::BindOnce(&CameraHalDispatcherImplTest::RegisterServer,
                      base::Unretained(dispatcher_), base::Passed(&server_ptr)));
-  auto client_ptr = mock_client->GetInterfacePtr(GetProxyTaskRunner());
+  auto client_ptr = mock_client->GetInterfacePtrInfo();
   GetProxyTaskRunner()->PostTask(
       FROM_HERE,
-      base::BindOnce(&CameraHalDispatcherImpl::RegisterClient,
+      base::BindOnce(&CameraHalDispatcherImplTest::RegisterClient,
                      base::Unretained(dispatcher_), base::Passed(&client_ptr)));
 
   // Wait until the client gets the established Mojo channel.
@@ -154,10 +162,10 @@
       .WillOnce(
           InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop));
 
-  server_ptr = mock_server->GetInterfacePtr(GetProxyTaskRunner());
+  server_ptr = mock_server->GetInterfacePtrInfo();
   GetProxyTaskRunner()->PostTask(
       FROM_HERE,
-      base::BindOnce(&CameraHalDispatcherImpl::RegisterServer,
+      base::BindOnce(&CameraHalDispatcherImplTest::RegisterServer,
                      base::Unretained(dispatcher_), base::Passed(&server_ptr)));
 
   // Wait until the clients gets the newly established Mojo channel.
@@ -178,15 +186,15 @@
       .WillOnce(
           InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop));
 
-  auto server_ptr = mock_server->GetInterfacePtr(GetProxyTaskRunner());
+  auto server_ptr = mock_server->GetInterfacePtrInfo();
   GetProxyTaskRunner()->PostTask(
       FROM_HERE,
-      base::BindOnce(&CameraHalDispatcherImpl::RegisterServer,
+      base::BindOnce(&CameraHalDispatcherImplTest::RegisterServer,
                      base::Unretained(dispatcher_), base::Passed(&server_ptr)));
-  auto client_ptr = mock_client->GetInterfacePtr(GetProxyTaskRunner());
+  auto client_ptr = mock_client->GetInterfacePtrInfo();
   GetProxyTaskRunner()->PostTask(
       FROM_HERE,
-      base::BindOnce(&CameraHalDispatcherImpl::RegisterClient,
+      base::BindOnce(&CameraHalDispatcherImplTest::RegisterClient,
                      base::Unretained(dispatcher_), base::Passed(&client_ptr)));
 
   // Wait until the client gets the established Mojo channel.
@@ -203,10 +211,10 @@
       .WillOnce(
           InvokeWithoutArgs(this, &CameraHalDispatcherImplTest::QuitRunLoop));
 
-  client_ptr = mock_client->GetInterfacePtr(GetProxyTaskRunner());
+  client_ptr = mock_client->GetInterfacePtrInfo();
   GetProxyTaskRunner()->PostTask(
       FROM_HERE,
-      base::BindOnce(&CameraHalDispatcherImpl::RegisterClient,
+      base::BindOnce(&CameraHalDispatcherImplTest::RegisterClient,
                      base::Unretained(dispatcher_), base::Passed(&client_ptr)));
 
   // Wait until the clients gets the newly established Mojo channel.
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index 19d6fc30..00802b7 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -116,6 +116,7 @@
     "//content/gpu:*",
     "//content/renderer:*",
     "//media/gpu/ipc/*",
+    "//media/mojo/*",
     ":*",
   ]
 
diff --git a/media/mojo/BUILD.gn b/media/mojo/BUILD.gn
index e46b3dc..024ec5a 100644
--- a/media/mojo/BUILD.gn
+++ b/media/mojo/BUILD.gn
@@ -86,6 +86,7 @@
     "interfaces/video_frame_struct_traits_unittest.cc",
     "services/mojo_audio_output_stream_unittest.cc",
     "services/mojo_cdm_allocator_unittest.cc",
+    "services/mojo_video_encode_accelerator_service_unittest.cc",
   ]
 
   if (is_android) {
diff --git a/media/mojo/services/BUILD.gn b/media/mojo/services/BUILD.gn
index 2b6914b..0bd8534 100644
--- a/media/mojo/services/BUILD.gn
+++ b/media/mojo/services/BUILD.gn
@@ -53,6 +53,8 @@
     "mojo_renderer_service.h",
     "mojo_video_decoder_service.cc",
     "mojo_video_decoder_service.h",
+    "mojo_video_encode_accelerator_service.cc",
+    "mojo_video_encode_accelerator_service.h",
     "test_mojo_media_client.cc",
     "test_mojo_media_client.h",
   ]
@@ -65,6 +67,7 @@
   public_deps = [
     "//base",
     "//media",
+    "//media/gpu",
     "//media/mojo:features",
     "//media/mojo/interfaces",
     "//mojo/public/cpp/bindings",
diff --git a/media/mojo/services/mojo_video_encode_accelerator_service.cc b/media/mojo/services/mojo_video_encode_accelerator_service.cc
new file mode 100644
index 0000000..e783da5
--- /dev/null
+++ b/media/mojo/services/mojo_video_encode_accelerator_service.cc
@@ -0,0 +1,224 @@
+// 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 "media/mojo/services/mojo_video_encode_accelerator_service.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/logging.h"
+#include "media/base/bind_to_current_loop.h"
+#include "media/base/limits.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+
+namespace media {
+
+// static
+void MojoVideoEncodeAcceleratorService::Create(
+    media::mojom::VideoEncodeAcceleratorRequest request,
+    const CreateAndInitializeVideoEncodeAcceleratorCallback&
+        create_vea_callback,
+    const gpu::GpuPreferences& gpu_preferences) {
+  mojo::MakeStrongBinding(base::MakeUnique<MojoVideoEncodeAcceleratorService>(
+                              create_vea_callback, gpu_preferences),
+                          std::move(request));
+}
+
+MojoVideoEncodeAcceleratorService::MojoVideoEncodeAcceleratorService(
+    const CreateAndInitializeVideoEncodeAcceleratorCallback&
+        create_vea_callback,
+    const gpu::GpuPreferences& gpu_preferences)
+    : create_vea_callback_(create_vea_callback),
+      gpu_preferences_(gpu_preferences),
+      output_buffer_size_(0),
+      weak_factory_(this) {
+  DVLOG(1) << __func__;
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+MojoVideoEncodeAcceleratorService::~MojoVideoEncodeAcceleratorService() {
+  DVLOG(1) << __func__;
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void MojoVideoEncodeAcceleratorService::Initialize(
+    media::VideoPixelFormat input_format,
+    const gfx::Size& input_visible_size,
+    media::VideoCodecProfile output_profile,
+    uint32_t initial_bitrate,
+    mojom::VideoEncodeAcceleratorClientPtr client) {
+  DVLOG(1) << __func__
+           << " input_format=" << VideoPixelFormatToString(input_format)
+           << ", input_visible_size=" << input_visible_size.ToString()
+           << ", output_profile=" << GetProfileName(output_profile)
+           << ", initial_bitrate=" << initial_bitrate;
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!encoder_);
+  DCHECK_EQ(PIXEL_FORMAT_I420, input_format) << "Only I420 format supported";
+
+  if (!client) {
+    DLOG(ERROR) << __func__ << "null |client|";
+    return;
+  }
+  vea_client_ = std::move(client);
+
+  if (input_visible_size.width() > limits::kMaxDimension ||
+      input_visible_size.height() > limits::kMaxDimension ||
+      input_visible_size.GetArea() > limits::kMaxCanvas) {
+    DLOG(ERROR) << __func__ << "too large input_visible_size "
+                << input_visible_size.ToString();
+    NotifyError(::media::VideoEncodeAccelerator::kInvalidArgumentError);
+    return;
+  }
+
+  encoder_ =
+      create_vea_callback_.Run(input_format, input_visible_size, output_profile,
+                               initial_bitrate, this, gpu_preferences_);
+  if (!encoder_) {
+    DLOG(ERROR) << __func__ << " Error creating or initializing VEA";
+    NotifyError(::media::VideoEncodeAccelerator::kPlatformFailureError);
+    return;
+  }
+
+  // TODO(mcasas): We could still TryToSetupEncodeOnSeparateThread() with an
+  // ad-hoc background worker thread, but for the time being this doesn't seem
+  // necessary since we're already on a background thread.
+
+  return;
+}
+
+void MojoVideoEncodeAcceleratorService::Encode(
+    const scoped_refptr<VideoFrame>& frame,
+    bool force_keyframe,
+    EncodeCallback callback) {
+  DVLOG(2) << __func__ << " tstamp=" << frame->timestamp();
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!encoder_)
+    return;
+
+  if (frame->coded_size() != input_coded_size_) {
+    DLOG(ERROR) << __func__ << " wrong input coded size, expected "
+                << input_coded_size_.ToString() << ", got "
+                << frame->coded_size().ToString();
+    NotifyError(::media::VideoEncodeAccelerator::kInvalidArgumentError);
+    return;
+  }
+
+  frame->AddDestructionObserver(media::BindToCurrentLoop(std::move(callback)));
+  encoder_->Encode(frame, force_keyframe);
+}
+
+void MojoVideoEncodeAcceleratorService::UseOutputBitstreamBuffer(
+    int32_t bitstream_buffer_id,
+    mojo::ScopedSharedBufferHandle buffer) {
+  DVLOG(2) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id;
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!encoder_)
+    return;
+  if (!buffer.is_valid()) {
+    DLOG(ERROR) << __func__ << " invalid |buffer|.";
+    NotifyError(::media::VideoEncodeAccelerator::kInvalidArgumentError);
+    return;
+  }
+  if (bitstream_buffer_id < 0) {
+    DLOG(ERROR) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id
+                << " must be >= 0";
+    NotifyError(::media::VideoEncodeAccelerator::kInvalidArgumentError);
+    return;
+  }
+
+  base::SharedMemoryHandle handle;
+  size_t memory_size = 0;
+  bool read_only = false;
+  auto result = mojo::UnwrapSharedMemoryHandle(std::move(buffer), &handle,
+                                               &memory_size, &read_only);
+  if (result != MOJO_RESULT_OK || memory_size == 0u) {
+    DLOG(ERROR) << __func__ << " mojo::UnwrapSharedMemoryHandle() failed";
+    NotifyError(::media::VideoEncodeAccelerator::kPlatformFailureError);
+    return;
+  }
+
+  if (memory_size < output_buffer_size_) {
+    DLOG(ERROR) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id
+                << " has a size of " << memory_size
+                << "B, different from expected " << output_buffer_size_ << "B";
+    NotifyError(::media::VideoEncodeAccelerator::kInvalidArgumentError);
+    return;
+  }
+
+  encoder_->UseOutputBitstreamBuffer(
+      BitstreamBuffer(bitstream_buffer_id, handle, memory_size));
+}
+
+void MojoVideoEncodeAcceleratorService::RequestEncodingParametersChange(
+    uint32_t bitrate,
+    uint32_t framerate) {
+  DVLOG(2) << __func__ << " bitrate=" << bitrate << " framerate=" << framerate;
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!encoder_)
+    return;
+  encoder_->RequestEncodingParametersChange(bitrate, framerate);
+}
+
+void MojoVideoEncodeAcceleratorService::RequireBitstreamBuffers(
+    unsigned int input_count,
+    const gfx::Size& input_coded_size,
+    size_t output_buffer_size) {
+  DVLOG(2) << __func__ << " input_count=" << input_count
+           << " input_coded_size=" << input_coded_size.ToString()
+           << " output_buffer_size=" << output_buffer_size;
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!vea_client_)
+    return;
+
+  output_buffer_size_ = output_buffer_size;
+  input_coded_size_ = input_coded_size;
+
+  vea_client_->RequireBitstreamBuffers(input_count, input_coded_size,
+                                       output_buffer_size);
+}
+
+void MojoVideoEncodeAcceleratorService::BitstreamBufferReady(
+    int32_t bitstream_buffer_id,
+    size_t payload_size,
+    bool key_frame,
+    base::TimeDelta timestamp) {
+  DVLOG(2) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id
+           << ", payload_size=" << payload_size
+           << "B,  key_frame=" << key_frame;
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!vea_client_)
+    return;
+
+  vea_client_->BitstreamBufferReady(bitstream_buffer_id, payload_size,
+                                    key_frame, timestamp);
+}
+
+void MojoVideoEncodeAcceleratorService::NotifyError(
+    ::media::VideoEncodeAccelerator::Error error) {
+  DVLOG(1) << __func__;
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!vea_client_)
+    return;
+
+  // TODO(mcasas): Use EnumTraits, https://crbug.com/736517
+  Error mojo_error = Error::PLATFORM_FAILURE_ERROR;
+  switch (error) {
+    case ::media::VideoEncodeAccelerator::kIllegalStateError:
+      mojo_error = Error::ILLEGAL_STATE_ERROR;
+      break;
+    case ::media::VideoEncodeAccelerator::kInvalidArgumentError:
+      mojo_error = Error::INVALID_ARGUMENT_ERROR;
+      break;
+    case ::media::VideoEncodeAccelerator::kPlatformFailureError:
+      mojo_error = Error::PLATFORM_FAILURE_ERROR;
+      break;
+  }
+  vea_client_->NotifyError(mojo_error);
+}
+
+}  // namespace media
diff --git a/media/mojo/services/mojo_video_encode_accelerator_service.h b/media/mojo/services/mojo_video_encode_accelerator_service.h
new file mode 100644
index 0000000..7fefbfe
--- /dev/null
+++ b/media/mojo/services/mojo_video_encode_accelerator_service.h
@@ -0,0 +1,102 @@
+// 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 MEDIA_MOJO_SERVICES_MOJO_VIDEO_ENCODE_ACCELERATOR_SERVICE_H_
+#define MEDIA_MOJO_SERVICES_MOJO_VIDEO_ENCODE_ACCELERATOR_SERVICE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "media/mojo/interfaces/video_encode_accelerator.mojom.h"
+#include "media/mojo/services/media_mojo_export.h"
+#include "media/video/video_encode_accelerator.h"
+
+namespace gpu {
+struct GpuPreferences;
+}  // namespace gpu
+
+namespace media {
+
+// This class implements the interface mojom::VideoEncodeAccelerator.
+class MEDIA_MOJO_EXPORT MojoVideoEncodeAcceleratorService
+    : public NON_EXPORTED_BASE(mojom::VideoEncodeAccelerator),
+      public VideoEncodeAccelerator::Client {
+ public:
+  // Create and initialize a VEA. Returns nullptr if either part fails.
+  using CreateAndInitializeVideoEncodeAcceleratorCallback =
+      base::Callback<std::unique_ptr<::media::VideoEncodeAccelerator>(
+          VideoPixelFormat input_format,
+          const gfx::Size& input_visible_size,
+          VideoCodecProfile output_profile,
+          uint32_t initial_bitrate,
+          Client* client,
+          const gpu::GpuPreferences& gpu_preferences)>;
+
+  static void Create(media::mojom::VideoEncodeAcceleratorRequest request,
+                     const CreateAndInitializeVideoEncodeAcceleratorCallback&
+                         create_vea_callback,
+                     const gpu::GpuPreferences& gpu_preferences);
+
+  MojoVideoEncodeAcceleratorService(
+      const CreateAndInitializeVideoEncodeAcceleratorCallback&
+          create_vea_callback,
+      const gpu::GpuPreferences& gpu_preferences);
+  ~MojoVideoEncodeAcceleratorService() override;
+
+  // mojom::VideoEncodeAccelerator impl.
+  void Initialize(media::VideoPixelFormat input_format,
+                  const gfx::Size& input_visible_size,
+                  media::VideoCodecProfile output_profile,
+                  uint32_t initial_bitrate,
+                  mojom::VideoEncodeAcceleratorClientPtr client) override;
+  void Encode(const scoped_refptr<VideoFrame>& frame,
+              bool force_keyframe,
+              EncodeCallback callback) override;
+  void UseOutputBitstreamBuffer(int32_t bitstream_buffer_id,
+                                mojo::ScopedSharedBufferHandle buffer) override;
+  void RequestEncodingParametersChange(uint32_t bitrate,
+                                       uint32_t framerate) override;
+
+ private:
+  friend class MojoVideoEncodeAcceleratorServiceTest;
+
+  // VideoEncodeAccelerator::Client implementation.
+  void RequireBitstreamBuffers(unsigned int input_count,
+                               const gfx::Size& input_coded_size,
+                               size_t output_buffer_size) override;
+  void BitstreamBufferReady(int32_t bitstream_buffer_id,
+                            size_t payload_size,
+                            bool key_frame,
+                            base::TimeDelta timestamp) override;
+  void NotifyError(::media::VideoEncodeAccelerator::Error error) override;
+
+  const CreateAndInitializeVideoEncodeAcceleratorCallback create_vea_callback_;
+  const gpu::GpuPreferences& gpu_preferences_;
+
+  // Owned pointer to the underlying VideoEncodeAccelerator.
+  std::unique_ptr<::media::VideoEncodeAccelerator> encoder_;
+  mojom::VideoEncodeAcceleratorClientPtr vea_client_;
+
+  // Cache of parameters for sanity verification.
+  size_t output_buffer_size_;
+  gfx::Size input_coded_size_;
+
+  // Note that this class is already thread hostile when bound.
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  base::WeakPtrFactory<MojoVideoEncodeAcceleratorService> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(MojoVideoEncodeAcceleratorService);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_MOJO_SERVICES_MOJO_VIDEO_ENCODE_ACCELERATOR_SERVICE_H_
diff --git a/media/mojo/services/mojo_video_encode_accelerator_service_unittest.cc b/media/mojo/services/mojo_video_encode_accelerator_service_unittest.cc
new file mode 100644
index 0000000..0be0663
--- /dev/null
+++ b/media/mojo/services/mojo_video_encode_accelerator_service_unittest.cc
@@ -0,0 +1,279 @@
+// 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 <stddef.h>
+
+#include "base/message_loop/message_loop.h"
+#include "gpu/command_buffer/service/gpu_preferences.h"
+#include "media/mojo/interfaces/video_encode_accelerator.mojom.h"
+#include "media/mojo/services/mojo_video_encode_accelerator_service.h"
+#include "media/video/fake_video_encode_accelerator.h"
+#include "media/video/video_encode_accelerator.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+struct GpuPreferences;
+}  // namespace gpu
+
+using ::testing::_;
+
+namespace media {
+
+static const gfx::Size kInputVisibleSize(64, 48);
+
+std::unique_ptr<VideoEncodeAccelerator> CreateAndInitializeFakeVEA(
+    bool will_initialization_succeed,
+    VideoPixelFormat input_format,
+    const gfx::Size& input_visible_size,
+    VideoCodecProfile output_profile,
+    uint32_t initial_bitrate,
+    VideoEncodeAccelerator::Client* client,
+    const gpu::GpuPreferences& gpu_preferences) {
+  // Use FakeVEA as scoped_ptr to guarantee proper destruction via Destroy().
+  auto vea = base::MakeUnique<FakeVideoEncodeAccelerator>(
+      base::ThreadTaskRunnerHandle::Get());
+  vea->SetWillInitializationSucceed(will_initialization_succeed);
+  const bool result = vea->Initialize(input_format, input_visible_size,
+                                      output_profile, initial_bitrate, client);
+
+  // Mimic the behaviour of GpuVideoEncodeAcceleratorFactory::CreateVEA().
+  return result ? base::WrapUnique<VideoEncodeAccelerator>(vea.release())
+                : nullptr;
+}
+
+class MockMojoVideoEncodeAcceleratorClient
+    : public mojom::VideoEncodeAcceleratorClient {
+ public:
+  MockMojoVideoEncodeAcceleratorClient() = default;
+
+  MOCK_METHOD3(RequireBitstreamBuffers,
+               void(uint32_t, const gfx::Size&, uint32_t));
+  MOCK_METHOD4(BitstreamBufferReady,
+               void(int32_t, uint32_t, bool, base::TimeDelta));
+  MOCK_METHOD1(NotifyError, void(mojom::VideoEncodeAccelerator::Error));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockMojoVideoEncodeAcceleratorClient);
+};
+
+// Test harness for a MojoVideoEncodeAcceleratorService; the tests manipulate it
+// via its MojoVideoEncodeAcceleratorService interface while observing a
+// "remote" mojo::VideoEncodeAcceleratorClient (that we keep inside a Mojo
+// binding). The class under test uses a FakeVideoEncodeAccelerator as
+// implementation.
+class MojoVideoEncodeAcceleratorServiceTest : public ::testing::Test {
+ public:
+  MojoVideoEncodeAcceleratorServiceTest() = default;
+
+  void TearDown() override {
+    // The destruction of a mojo::StrongBinding closes the bound message pipe
+    // but does not destroy the implementation object: needs to happen manually,
+    // otherwise we leak it. This only applies if BindAndInitialize() has been
+    // called.
+    if (mojo_vea_binding_)
+      mojo_vea_binding_->Close();
+  }
+
+  // Creates the class under test, configuring the underlying FakeVEA to succeed
+  // upon initialization (by default) or not.
+  void CreateMojoVideoEncodeAccelerator(
+      bool will_fake_vea_initialization_succeed = true) {
+    mojo_vea_service_ = base::MakeUnique<MojoVideoEncodeAcceleratorService>(
+        base::Bind(&CreateAndInitializeFakeVEA,
+                   will_fake_vea_initialization_succeed),
+        gpu::GpuPreferences());
+  }
+
+  void BindAndInitialize() {
+    // Create an Mojo VEA Client InterfacePtr and point it to bind to our Mock.
+    mojom::VideoEncodeAcceleratorClientPtr mojo_vea_client;
+    mojo_vea_binding_ = mojo::MakeStrongBinding(
+        base::MakeUnique<MockMojoVideoEncodeAcceleratorClient>(),
+        mojo::MakeRequest(&mojo_vea_client));
+
+    EXPECT_CALL(*mock_mojo_vea_client(),
+                RequireBitstreamBuffers(_, kInputVisibleSize, _));
+
+    const uint32_t kInitialBitrate = 100000u;
+    mojo_vea_service()->Initialize(PIXEL_FORMAT_I420, kInputVisibleSize,
+                                   H264PROFILE_MIN, kInitialBitrate,
+                                   std::move(mojo_vea_client));
+    base::RunLoop().RunUntilIdle();
+  }
+
+  MojoVideoEncodeAcceleratorService* mojo_vea_service() {
+    return mojo_vea_service_.get();
+  }
+
+  MockMojoVideoEncodeAcceleratorClient* mock_mojo_vea_client() const {
+    return static_cast<media::MockMojoVideoEncodeAcceleratorClient*>(
+        mojo_vea_binding_->impl());
+  }
+
+  FakeVideoEncodeAccelerator* fake_vea() const {
+    return static_cast<FakeVideoEncodeAccelerator*>(
+        mojo_vea_service_->encoder_.get());
+  }
+
+ private:
+  const base::MessageLoop message_loop_;
+
+  mojo::StrongBindingPtr<mojom::VideoEncodeAcceleratorClient> mojo_vea_binding_;
+
+  // The class under test.
+  std::unique_ptr<MojoVideoEncodeAcceleratorService> mojo_vea_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(MojoVideoEncodeAcceleratorServiceTest);
+};
+
+// This test verifies the BindAndInitialize() communication prologue in
+// isolation.
+TEST_F(MojoVideoEncodeAcceleratorServiceTest,
+       InitializeAndRequireBistreamBuffers) {
+  CreateMojoVideoEncodeAccelerator();
+  BindAndInitialize();
+}
+
+// This test verifies the BindAndInitialize() communication prologue followed by
+// a sharing of a single bitstream buffer and the Encode() of one frame.
+TEST_F(MojoVideoEncodeAcceleratorServiceTest, EncodeOneFrame) {
+  CreateMojoVideoEncodeAccelerator();
+  BindAndInitialize();
+
+  const int32_t kBitstreamBufferId = 17;
+  {
+    const uint64_t kShMemSize = fake_vea()->minimum_output_buffer_size();
+    auto handle = mojo::SharedBufferHandle::Create(kShMemSize);
+
+    mojo_vea_service()->UseOutputBitstreamBuffer(kBitstreamBufferId,
+                                                 std::move(handle));
+    base::RunLoop().RunUntilIdle();
+  }
+
+  {
+    const auto video_frame = VideoFrame::CreateBlackFrame(kInputVisibleSize);
+    EXPECT_CALL(*mock_mojo_vea_client(),
+                BitstreamBufferReady(kBitstreamBufferId, _, _, _));
+
+    mojo_vea_service()->Encode(video_frame, true /* is_keyframe */,
+                               base::Bind(&base::DoNothing));
+    base::RunLoop().RunUntilIdle();
+  }
+}
+
+// Tests that a RequestEncodingParametersChange() ripples through correctly.
+TEST_F(MojoVideoEncodeAcceleratorServiceTest, EncodingParametersChange) {
+  CreateMojoVideoEncodeAccelerator();
+  BindAndInitialize();
+
+  const uint32_t kNewBitrate = 123123u;
+  const uint32_t kNewFramerate = 321321u;
+  mojo_vea_service()->RequestEncodingParametersChange(kNewBitrate,
+                                                      kNewFramerate);
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_TRUE(fake_vea());
+  EXPECT_EQ(kNewBitrate, fake_vea()->stored_bitrates().front());
+}
+
+// This test verifies that when FakeVEA is configured to fail upon start,
+// MojoVEA::Initialize() causes a NotifyError().
+TEST_F(MojoVideoEncodeAcceleratorServiceTest, InitializeFailure) {
+  CreateMojoVideoEncodeAccelerator(
+      false /* will_fake_vea_initialization_succeed */);
+
+  mojom::VideoEncodeAcceleratorClientPtr mojo_vea_client;
+  auto mojo_vea_binding = mojo::MakeStrongBinding(
+      base::MakeUnique<MockMojoVideoEncodeAcceleratorClient>(),
+      mojo::MakeRequest(&mojo_vea_client));
+
+  EXPECT_CALL(
+      *static_cast<media::MockMojoVideoEncodeAcceleratorClient*>(
+          mojo_vea_binding->impl()),
+      NotifyError(
+          mojom::VideoEncodeAccelerator::Error::PLATFORM_FAILURE_ERROR));
+
+  const uint32_t kInitialBitrate = 100000u;
+  mojo_vea_service()->Initialize(PIXEL_FORMAT_I420, kInputVisibleSize,
+                                 H264PROFILE_MIN, kInitialBitrate,
+                                 std::move(mojo_vea_client));
+  base::RunLoop().RunUntilIdle();
+
+  mojo_vea_binding->Close();
+}
+
+// This test verifies that UseOutputBitstreamBuffer() with a wrong ShMem size
+// causes NotifyError().
+TEST_F(MojoVideoEncodeAcceleratorServiceTest,
+       UseOutputBitstreamBufferWithWrongSizeFails) {
+  CreateMojoVideoEncodeAccelerator();
+  BindAndInitialize();
+
+  const int32_t kBitstreamBufferId = 17;
+  const uint64_t wrong_size = fake_vea()->minimum_output_buffer_size() / 2;
+  auto handle = mojo::SharedBufferHandle::Create(wrong_size);
+
+  EXPECT_CALL(
+      *mock_mojo_vea_client(),
+      NotifyError(
+          mojom::VideoEncodeAccelerator::Error::INVALID_ARGUMENT_ERROR));
+
+  mojo_vea_service()->UseOutputBitstreamBuffer(kBitstreamBufferId,
+                                               std::move(handle));
+  base::RunLoop().RunUntilIdle();
+}
+
+// This test verifies that Encode() with wrong coded size causes NotifyError().
+TEST_F(MojoVideoEncodeAcceleratorServiceTest, EncodeWithWrongSizeFails) {
+  CreateMojoVideoEncodeAccelerator();
+  BindAndInitialize();
+
+  // We should send a UseOutputBitstreamBuffer() first but in unit tests we can
+  // skip that prologue.
+
+  const gfx::Size wrong_size(kInputVisibleSize.width() / 2,
+                             kInputVisibleSize.height() / 2);
+  const auto video_frame = VideoFrame::CreateBlackFrame(wrong_size);
+
+  EXPECT_CALL(
+      *mock_mojo_vea_client(),
+      NotifyError(
+          mojom::VideoEncodeAccelerator::Error::INVALID_ARGUMENT_ERROR));
+
+  mojo_vea_service()->Encode(video_frame, true /* is_keyframe */,
+                             base::Bind(&base::DoNothing));
+  base::RunLoop().RunUntilIdle();
+}
+
+// This test verifies that an any mojom::VEA method call (e.g. Encode(),
+// UseOutputBitstreamBuffer() etc) before MojoVEA::Initialize() is ignored (we
+// can't expect NotifyError()s since there's no mojo client registered).
+TEST_F(MojoVideoEncodeAcceleratorServiceTest, CallsBeforeInitializeAreIgnored) {
+  CreateMojoVideoEncodeAccelerator();
+  {
+    const auto video_frame = VideoFrame::CreateBlackFrame(kInputVisibleSize);
+    mojo_vea_service()->Encode(video_frame, true /* is_keyframe */,
+                               base::Bind(&base::DoNothing));
+    base::RunLoop().RunUntilIdle();
+  }
+  {
+    const int32_t kBitstreamBufferId = 17;
+    const uint64_t kShMemSize = 10;
+    auto handle = mojo::SharedBufferHandle::Create(kShMemSize);
+    mojo_vea_service()->UseOutputBitstreamBuffer(kBitstreamBufferId,
+                                                 std::move(handle));
+    base::RunLoop().RunUntilIdle();
+  }
+  {
+    const uint32_t kNewBitrate = 123123u;
+    const uint32_t kNewFramerate = 321321u;
+    mojo_vea_service()->RequestEncodingParametersChange(kNewBitrate,
+                                                        kNewFramerate);
+    base::RunLoop().RunUntilIdle();
+  }
+}
+
+}  // namespace media
diff --git a/media/video/fake_video_encode_accelerator.cc b/media/video/fake_video_encode_accelerator.cc
index 45f38e69..dc51da61 100644
--- a/media/video/fake_video_encode_accelerator.cc
+++ b/media/video/fake_video_encode_accelerator.cc
@@ -12,7 +12,6 @@
 namespace media {
 
 static const unsigned int kMinimumInputCount = 1;
-static const size_t kMinimumOutputBufferSize = 123456;
 
 FakeVideoEncodeAccelerator::FakeVideoEncodeAccelerator(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
diff --git a/media/video/fake_video_encode_accelerator.h b/media/video/fake_video_encode_accelerator.h
index 5e7813d..7b731de 100644
--- a/media/video/fake_video_encode_accelerator.h
+++ b/media/video/fake_video_encode_accelerator.h
@@ -26,6 +26,8 @@
 
 namespace media {
 
+static const size_t kMinimumOutputBufferSize = 123456;
+
 class MEDIA_EXPORT FakeVideoEncodeAccelerator : public VideoEncodeAccelerator {
  public:
   explicit FakeVideoEncodeAccelerator(
@@ -51,6 +53,8 @@
   void SendDummyFrameForTesting(bool key_frame);
   void SetWillInitializationSucceed(bool will_initialization_succeed);
 
+  size_t minimum_output_buffer_size() const { return kMinimumOutputBufferSize; }
+
  private:
   void DoRequireBitstreamBuffers(unsigned int input_count,
                                  const gfx::Size& input_coded_size,
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
index 9037c87b..f68242a 100644
--- a/mojo/public/cpp/bindings/BUILD.gn
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -108,6 +108,8 @@
     "lib/sync_event_watcher.cc",
     "lib/sync_handle_registry.cc",
     "lib/sync_handle_watcher.cc",
+    "lib/task_runner_helper.cc",
+    "lib/task_runner_helper.h",
     "lib/template_util.h",
     "lib/unserialized_message_context.cc",
     "lib/unserialized_message_context.h",
diff --git a/mojo/public/cpp/bindings/README.md b/mojo/public/cpp/bindings/README.md
index 92e79fe6..b5e2c16 100644
--- a/mojo/public/cpp/bindings/README.md
+++ b/mojo/public/cpp/bindings/README.md
@@ -177,15 +177,15 @@
 type, which is a generated alias for `mojo::InterfacePtrInfo<Logger>`. This is
 similar to an `InterfaceRequest<T>` in that it merely holds onto a pipe handle
 and cannot actually read or write messages on the pipe. Both this type and
-`InterfaceRequest<T>` are safe to move freely from thread to thread, whereas a
-bound `InterfacePtr<T>` is bound to a single thread.
+`InterfaceRequest<T>` are safe to move freely from sequence to sequence, whereas
+a bound `InterfacePtr<T>` is bound to a single sequence.
 
 An `InterfacePtr<T>` may be unbound by calling its `PassInterface()` method,
 which returns a new `InterfacePtrInfo<T>`. Conversely, an `InterfacePtr<T>` may
 bind (and thus take ownership of) an `InterfacePtrInfo<T>` so that interface
 calls can be made on the pipe.
 
-The thread-bound nature of `InterfacePtr<T>` is necessary to support safe
+The sequence-bound nature of `InterfacePtr<T>` is necessary to support safe
 dispatch of its [message responses](#Receiving-Responses) and
 [connection error notifications](#Connection-Errors).
 ***
@@ -251,7 +251,7 @@
 
 Now we can construct a `LoggerImpl` over our pending `LoggerRequest`, and the
 previously queued `Log` message will be dispatched ASAP on the `LoggerImpl`'s
-thread:
+sequence:
 
 ``` cpp
 LoggerImpl impl(std::move(request));
diff --git a/mojo/public/cpp/bindings/associated_binding.h b/mojo/public/cpp/bindings/associated_binding.h
index de0d85a..c34e971 100644
--- a/mojo/public/cpp/bindings/associated_binding.h
+++ b/mojo/public/cpp/bindings/associated_binding.h
@@ -15,8 +15,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
-#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/single_thread_task_runner.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
 #include "mojo/public/cpp/bindings/associated_interface_request.h"
 #include "mojo/public/cpp/bindings/bindings_export.h"
@@ -72,7 +71,7 @@
                 MessageReceiverWithResponderStatus* receiver,
                 std::unique_ptr<MessageReceiver> payload_validator,
                 bool expect_sync_requests,
-                scoped_refptr<base::SequencedTaskRunner> runner,
+                scoped_refptr<base::SingleThreadTaskRunner> runner,
                 uint32_t interface_version);
 
   std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
@@ -82,12 +81,12 @@
 // to Binding, except that it doesn't own a message pipe handle.
 //
 // When you bind this class to a request, optionally you can specify a
-// base::SequencedTaskRunner. This task runner must belong to the same
+// base::SingleThreadTaskRunner. This task runner must belong to the same
 // thread. It will be used to dispatch incoming method calls and connection
 // error notification. It is useful when you attach multiple task runners to a
-// single thread for the purposes of task scheduling. Please note that incoming
-// synchrounous method calls may not be run from this task runner, when they
-// reenter outgoing synchrounous calls on the same thread.
+// single thread for the purposes of task scheduling. Please note that
+// incoming synchronous method calls may not be run from this task runner, when
+// they reenter outgoing synchronous calls on the same thread.
 template <typename Interface,
           typename ImplRefTraits = RawPtrImplRefTraits<Interface>>
 class AssociatedBinding : public AssociatedBindingBase {
@@ -103,10 +102,10 @@
 
   // Constructs a completed associated binding of |impl|. |impl| must outlive
   // the binding.
-  AssociatedBinding(ImplPointerType impl,
-                    AssociatedInterfaceRequest<Interface> request,
-                    scoped_refptr<base::SequencedTaskRunner> runner =
-                        base::SequencedTaskRunnerHandle::Get())
+  AssociatedBinding(
+      ImplPointerType impl,
+      AssociatedInterfaceRequest<Interface> request,
+      scoped_refptr<base::SingleThreadTaskRunner> runner = nullptr)
       : AssociatedBinding(std::move(impl)) {
     Bind(std::move(request), std::move(runner));
   }
@@ -115,8 +114,7 @@
 
   // Sets up this object as the implementation side of an associated interface.
   void Bind(AssociatedInterfaceRequest<Interface> request,
-            scoped_refptr<base::SequencedTaskRunner> runner =
-                base::SequencedTaskRunnerHandle::Get()) {
+            scoped_refptr<base::SingleThreadTaskRunner> runner = nullptr) {
     BindImpl(request.PassHandle(), &stub_,
              base::WrapUnique(new typename Interface::RequestValidator_()),
              Interface::HasSyncMethods_, std::move(runner),
@@ -124,7 +122,7 @@
   }
 
   // Unbinds and returns the associated interface request so it can be
-  // used in another context, such as on another thread or with a different
+  // used in another context, such as on another sequence or with a different
   // implementation. Puts this object into a state where it can be rebound.
   AssociatedInterfaceRequest<Interface> Unbind() {
     DCHECK(endpoint_client_);
diff --git a/mojo/public/cpp/bindings/associated_group_controller.h b/mojo/public/cpp/bindings/associated_group_controller.h
index 5c9d9e3..d2139cec 100644
--- a/mojo/public/cpp/bindings/associated_group_controller.h
+++ b/mojo/public/cpp/bindings/associated_group_controller.h
@@ -53,7 +53,7 @@
 
   // Attaches a client to the specified endpoint to send and receive messages.
   // The returned object is still owned by the controller. It must only be used
-  // on the same thread as this call, and only before the client is detached
+  // on the same sequence as this call, and only before the client is detached
   // using DetachEndpointClient().
   virtual InterfaceEndpointController* AttachEndpointClient(
       const ScopedInterfaceEndpointHandle& handle,
@@ -61,7 +61,7 @@
       scoped_refptr<base::SequencedTaskRunner> runner) = 0;
 
   // Detaches the client attached to the specified endpoint. It must be called
-  // on the same thread as the corresponding AttachEndpointClient() call.
+  // on the same sequence as the corresponding AttachEndpointClient() call.
   virtual void DetachEndpointClient(
       const ScopedInterfaceEndpointHandle& handle) = 0;
 
diff --git a/mojo/public/cpp/bindings/associated_interface_ptr.h b/mojo/public/cpp/bindings/associated_interface_ptr.h
index 35c264e6..835c349a 100644
--- a/mojo/public/cpp/bindings/associated_interface_ptr.h
+++ b/mojo/public/cpp/bindings/associated_interface_ptr.h
@@ -14,8 +14,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
-#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/single_thread_task_runner.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
 #include "mojo/public/cpp/bindings/associated_interface_request.h"
 #include "mojo/public/cpp/bindings/bindings_export.h"
@@ -71,8 +70,7 @@
   // comments of MakeRequest(AssociatedInterfacePtr<Interface>*) for more
   // details.
   void Bind(AssociatedInterfacePtrInfo<Interface> info,
-            scoped_refptr<base::SequencedTaskRunner> runner =
-                base::SequencedTaskRunnerHandle::Get()) {
+            scoped_refptr<base::SingleThreadTaskRunner> runner = nullptr) {
     reset();
 
     if (info.is_valid())
@@ -148,7 +146,7 @@
 
   // Unbinds and returns the associated interface pointer information which
   // could be used to setup an AssociatedInterfacePtr again. This method may be
-  // used to move the proxy to a different thread.
+  // used to move the proxy to a different sequence.
   //
   // It is an error to call PassInterface() while there are pending responses.
   // TODO: fix this restriction, it's not always obvious when there is a
@@ -186,8 +184,7 @@
 template <typename Interface>
 AssociatedInterfaceRequest<Interface> MakeRequest(
     AssociatedInterfacePtr<Interface>* ptr,
-    scoped_refptr<base::SequencedTaskRunner> runner =
-        base::SequencedTaskRunnerHandle::Get()) {
+    scoped_refptr<base::SingleThreadTaskRunner> runner = nullptr) {
   AssociatedInterfacePtrInfo<Interface> ptr_info;
   auto request = MakeRequest(&ptr_info);
   ptr->Bind(std::move(ptr_info), std::move(runner));
diff --git a/mojo/public/cpp/bindings/binding.h b/mojo/public/cpp/bindings/binding.h
index 1e07a840..388a3e6b 100644
--- a/mojo/public/cpp/bindings/binding.h
+++ b/mojo/public/cpp/bindings/binding.h
@@ -11,8 +11,7 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
-#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/single_thread_task_runner.h"
 #include "mojo/public/cpp/bindings/connection_error_callback.h"
 #include "mojo/public/cpp/bindings/interface_ptr.h"
 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
@@ -55,17 +54,17 @@
 //   };
 //
 // This class is thread hostile while bound to a message pipe. All calls to this
-// class must be from the thread that bound it. The interface implementation's
-// methods will be called from the thread that bound this. If a Binding is not
-// bound to a message pipe, it may be bound or destroyed on any thread.
+// class must be from the sequence that bound it. The interface implementation's
+// methods will be called from the sequence that bound this. If a Binding is not
+// bound to a message pipe, it may be bound or destroyed on any sequence.
 //
 // When you bind this class to a message pipe, optionally you can specify a
-// base::SequencedTaskRunner. This task runner must belong to the same
+// base::SingleThreadTaskRunner. This task runner must belong to the same
 // thread. It will be used to dispatch incoming method calls and connection
 // error notification. It is useful when you attach multiple task runners to a
-// single thread for the purposes of task scheduling. Please note that incoming
-// synchrounous method calls may not be run from this task runner, when they
-// reenter outgoing synchrounous calls on the same thread.
+// single thread for the purposes of task scheduling. Please note that
+// incoming synchrounous method calls may not be run from this task runner, when
+// they reenter outgoing synchrounous calls on the same thread.
 template <typename Interface,
           typename ImplRefTraits = RawPtrImplRefTraits<Interface>>
 class Binding {
@@ -82,8 +81,7 @@
   // |impl|, which must outlive the binding.
   Binding(ImplPointerType impl,
           InterfaceRequest<Interface> request,
-          scoped_refptr<base::SequencedTaskRunner> runner =
-              base::SequencedTaskRunnerHandle::Get())
+          scoped_refptr<base::SingleThreadTaskRunner> runner = nullptr)
       : Binding(std::move(impl)) {
     Bind(std::move(request), std::move(runner));
   }
@@ -96,8 +94,7 @@
   // implementation by removing the message pipe endpoint from |request| and
   // binding it to the previously specified implementation.
   void Bind(InterfaceRequest<Interface> request,
-            scoped_refptr<base::SequencedTaskRunner> runner =
-                base::SequencedTaskRunnerHandle::Get()) {
+            scoped_refptr<base::SingleThreadTaskRunner> runner = nullptr) {
     internal_state_.Bind(request.PassMessagePipe(), std::move(runner));
   }
 
@@ -130,7 +127,7 @@
     internal_state_.ResumeIncomingMethodCallProcessing();
   }
 
-  // Blocks the calling thread until either a call arrives on the previously
+  // Blocks the calling sequence until either a call arrives on the previously
   // bound message pipe, the deadline is exceeded, or an error occurs. Returns
   // true if a method was successfully read and dispatched.
   //
@@ -152,7 +149,7 @@
   }
 
   // Unbinds the underlying pipe from this binding and returns it so it can be
-  // used in another context, such as on another thread or with a different
+  // used in another context, such as on another sequence or with a different
   // implementation. Put this object into a state where it can be rebound to a
   // new pipe.
   //
@@ -214,7 +211,7 @@
   // from directly within the stack frame of a message dispatch, but the
   // returned callback may be called exactly once any time thereafter to report
   // the message as bad. This may only be called once per message. The returned
-  // callback must be called on the Binding's own thread.
+  // callback must be called on the Binding's own sequence.
   ReportBadMessageCallback GetBadMessageCallback() {
     return internal_state_.GetBadMessageCallback();
   }
diff --git a/mojo/public/cpp/bindings/binding_set.h b/mojo/public/cpp/bindings/binding_set.h
index 6b447ea..29d5f89 100644
--- a/mojo/public/cpp/bindings/binding_set.h
+++ b/mojo/public/cpp/bindings/binding_set.h
@@ -164,7 +164,7 @@
   // message dispatch, but the returned callback may be called exactly once any
   // time thereafter as long as the binding set itself hasn't been destroyed yet
   // to report the message as bad. This may only be called once per message.
-  // The returned callback must be called on the BindingSet's own thread.
+  // The returned callback must be called on the BindingSet's own sequence.
   ReportBadMessageCallback GetBadMessageCallback() {
     DCHECK(dispatch_context_);
     return base::Bind(
diff --git a/mojo/public/cpp/bindings/connector.h b/mojo/public/cpp/bindings/connector.h
index e3ee8ffa..4531843 100644
--- a/mojo/public/cpp/bindings/connector.h
+++ b/mojo/public/cpp/bindings/connector.h
@@ -37,14 +37,14 @@
 //   - MessagePipe I/O is non-blocking.
 //   - Sending messages can be configured to be thread safe (please see comments
 //     of the constructor). Other than that, the object should only be accessed
-//     on the creating thread.
+//     on the creating sequence.
 class MOJO_CPP_BINDINGS_EXPORT Connector
     : NON_EXPORTED_BASE(public MessageReceiver) {
  public:
   enum ConnectorConfig {
-    // Connector::Accept() is only called from a single thread.
+    // Connector::Accept() is only called from a single sequence.
     SINGLE_THREADED_SEND,
-    // Connector::Accept() is allowed to be called from multiple threads.
+    // Connector::Accept() is allowed to be called from multiple sequences.
     MULTI_THREADED_SEND
   };
 
@@ -164,7 +164,7 @@
   }
 
   // Allows |message_pipe_| to be watched while others perform sync handle
-  // watching on the same thread. Please see comments of
+  // watching on the same sequence. Please see comments of
   // SyncHandleWatcher::AllowWokenUpBySyncWatchOnSameThread().
   void AllowWokenUpBySyncWatchOnSameThread();
 
@@ -244,7 +244,7 @@
   OutgoingSerializationMode outgoing_serialization_mode_;
   IncomingSerializationMode incoming_serialization_mode_;
 
-  // If sending messages is allowed from multiple threads, |lock_| is used to
+  // If sending messages is allowed from multiple sequences, |lock_| is used to
   // protect modifications to |message_pipe_| and |drop_writes_|.
   base::Optional<base::Lock> lock_;
 
diff --git a/mojo/public/cpp/bindings/interface_endpoint_client.h b/mojo/public/cpp/bindings/interface_endpoint_client.h
index c3887f7..25b815c 100644
--- a/mojo/public/cpp/bindings/interface_endpoint_client.h
+++ b/mojo/public/cpp/bindings/interface_endpoint_client.h
@@ -37,7 +37,7 @@
 
 // InterfaceEndpointClient handles message sending and receiving of an interface
 // endpoint, either the implementation side or the client side.
-// It should only be accessed and destructed on the creating thread.
+// It should only be accessed and destructed on the creating sequence.
 class MOJO_CPP_BINDINGS_EXPORT InterfaceEndpointClient
     : NON_EXPORTED_BASE(public MessageReceiverWithResponder),
       NON_EXPORTED_BASE(private internal::LifeTimeTrackerForDebugging) {
diff --git a/mojo/public/cpp/bindings/interface_endpoint_controller.h b/mojo/public/cpp/bindings/interface_endpoint_controller.h
index 8d99d4a4..dabc3d88 100644
--- a/mojo/public/cpp/bindings/interface_endpoint_controller.h
+++ b/mojo/public/cpp/bindings/interface_endpoint_controller.h
@@ -18,8 +18,8 @@
   virtual bool SendMessage(Message* message) = 0;
 
   // Allows the interface endpoint to watch for incoming sync messages while
-  // others perform sync handle watching on the same thread. Please see comments
-  // of SyncHandleWatcher::AllowWokenUpBySyncWatchOnSameThread().
+  // others perform sync handle watching on the same sequence. Please see
+  // comments of SyncHandleWatcher::AllowWokenUpBySyncWatchOnSameThread().
   virtual void AllowWokenUpBySyncWatchOnSameThread() = 0;
 
   // Watches the interface endpoint for incoming sync messages. (It also watches
diff --git a/mojo/public/cpp/bindings/interface_ptr.h b/mojo/public/cpp/bindings/interface_ptr.h
index 431f575..4a69644 100644
--- a/mojo/public/cpp/bindings/interface_ptr.h
+++ b/mojo/public/cpp/bindings/interface_ptr.h
@@ -14,8 +14,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
-#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/single_thread_task_runner.h"
 #include "mojo/public/cpp/bindings/connection_error_callback.h"
 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
 #include "mojo/public/cpp/bindings/lib/interface_ptr_state.h"
@@ -29,12 +28,12 @@
 //
 // This class is thread hostile, as is the local proxy it manages, while bound
 // to a message pipe. All calls to this class or the proxy should be from the
-// same thread that bound it. If you need to move the proxy to a different
-// thread, extract the InterfacePtrInfo (containing just the message pipe and
-// any version information) using PassInterface() on the original thread, pass
-// it to a different thread, and create and bind a new InterfacePtr from that
-// thread. If an InterfacePtr is not bound to a message pipe, it may be bound or
-// destroyed on any thread.
+// same sequence that bound it. If you need to move the proxy to a different
+// sequence, extract the InterfacePtrInfo (containing just the message pipe and
+// any version information) using PassInterface() on the original sequence, pass
+// it to a different sequence, and create and bind a new InterfacePtr from that
+// sequence. If an InterfacePtr is not bound to a message pipe, it may be bound
+// or destroyed on any sequence.
 template <typename Interface>
 class InterfacePtr {
  public:
@@ -79,8 +78,7 @@
   // multiple task runners to a single thread for the purposes of task
   // scheduling.
   void Bind(InterfacePtrInfo<Interface> info,
-            scoped_refptr<base::SequencedTaskRunner> runner =
-                base::SequencedTaskRunnerHandle::Get()) {
+            scoped_refptr<base::SingleThreadTaskRunner> runner = nullptr) {
     reset();
     if (info.is_valid())
       internal_state_.Bind(std::move(info), std::move(runner));
@@ -149,7 +147,7 @@
   bool encountered_error() const { return internal_state_.encountered_error(); }
 
   // Registers a handler to receive error notifications. The handler will be
-  // called from the thread that owns this InterfacePtr.
+  // called from the sequence that owns this InterfacePtr.
   //
   // This method may only be called after the InterfacePtr has been bound to a
   // message pipe.
@@ -165,7 +163,7 @@
 
   // Unbinds the InterfacePtr and returns the information which could be used
   // to setup an InterfacePtr again. This method may be used to move the proxy
-  // to a different thread (see class comments for details).
+  // to a different sequence (see class comments for details).
   //
   // It is an error to call PassInterface() while:
   //   - there are pending responses; or
@@ -214,8 +212,7 @@
 template <typename Interface>
 InterfacePtr<Interface> MakeProxy(
     InterfacePtrInfo<Interface> info,
-    scoped_refptr<base::SequencedTaskRunner> runner =
-        base::SequencedTaskRunnerHandle::Get()) {
+    scoped_refptr<base::SingleThreadTaskRunner> runner = nullptr) {
   InterfacePtr<Interface> ptr;
   if (info.is_valid())
     ptr.Bind(std::move(info), std::move(runner));
diff --git a/mojo/public/cpp/bindings/interface_request.h b/mojo/public/cpp/bindings/interface_request.h
index 54b18d7..6502868c 100644
--- a/mojo/public/cpp/bindings/interface_request.h
+++ b/mojo/public/cpp/bindings/interface_request.h
@@ -10,8 +10,7 @@
 
 #include "base/macros.h"
 #include "base/optional.h"
-#include "base/sequenced_task_runner.h"
-#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/single_thread_task_runner.h"
 #include "mojo/public/cpp/bindings/disconnect_reason.h"
 #include "mojo/public/cpp/bindings/interface_ptr.h"
 #include "mojo/public/cpp/bindings/pipe_control_message_proxy.h"
@@ -133,8 +132,7 @@
 template <typename Interface>
 InterfaceRequest<Interface> MakeRequest(
     InterfacePtr<Interface>* ptr,
-    scoped_refptr<base::SequencedTaskRunner> runner =
-        base::SequencedTaskRunnerHandle::Get()) {
+    scoped_refptr<base::SingleThreadTaskRunner> runner = nullptr) {
   MessagePipe pipe;
   ptr->Bind(InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u),
             std::move(runner));
diff --git a/mojo/public/cpp/bindings/lib/associated_binding.cc b/mojo/public/cpp/bindings/lib/associated_binding.cc
index eec391c..da8f0ab0 100644
--- a/mojo/public/cpp/bindings/lib/associated_binding.cc
+++ b/mojo/public/cpp/bindings/lib/associated_binding.cc
@@ -3,7 +3,8 @@
 // found in the LICENSE file.
 
 #include "mojo/public/cpp/bindings/associated_binding.h"
-#include "base/single_thread_task_runner.h"
+
+#include "mojo/public/cpp/bindings/lib/task_runner_helper.h"
 
 namespace mojo {
 
@@ -49,7 +50,7 @@
     MessageReceiverWithResponderStatus* receiver,
     std::unique_ptr<MessageReceiver> payload_validator,
     bool expect_sync_requests,
-    scoped_refptr<base::SequencedTaskRunner> runner,
+    scoped_refptr<base::SingleThreadTaskRunner> runner,
     uint32_t interface_version) {
   if (!handle.is_valid()) {
     endpoint_client_.reset();
@@ -58,7 +59,9 @@
 
   endpoint_client_.reset(new InterfaceEndpointClient(
       std::move(handle), receiver, std::move(payload_validator),
-      expect_sync_requests, std::move(runner), interface_version));
+      expect_sync_requests,
+      internal::GetTaskRunnerToUseFromUserProvidedTaskRunner(std::move(runner)),
+      interface_version));
 }
 
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc
index a239f19..57b275e 100644
--- a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc
+++ b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc
@@ -4,6 +4,8 @@
 
 #include "mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h"
 
+#include "mojo/public/cpp/bindings/lib/task_runner_helper.h"
+
 namespace mojo {
 namespace internal {
 
@@ -56,7 +58,7 @@
     ScopedInterfaceEndpointHandle handle,
     uint32_t version,
     std::unique_ptr<MessageReceiver> validator,
-    scoped_refptr<base::SequencedTaskRunner> runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> runner) {
   DCHECK(!endpoint_client_);
   DCHECK_EQ(0u, version_);
   DCHECK(handle.is_valid());
@@ -66,7 +68,7 @@
   // will not be used.
   endpoint_client_ = base::MakeUnique<InterfaceEndpointClient>(
       std::move(handle), nullptr, std::move(validator), false,
-      std::move(runner), 0u);
+      GetTaskRunnerToUseFromUserProvidedTaskRunner(std::move(runner)), 0u);
 }
 
 ScopedInterfaceEndpointHandle AssociatedInterfacePtrStateBase::PassHandle() {
diff --git a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
index 3c2086b9..3db0118 100644
--- a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
+++ b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
@@ -81,7 +81,7 @@
   void Bind(ScopedInterfaceEndpointHandle handle,
             uint32_t version,
             std::unique_ptr<MessageReceiver> validator,
-            scoped_refptr<base::SequencedTaskRunner> runner);
+            scoped_refptr<base::SingleThreadTaskRunner> runner);
   ScopedInterfaceEndpointHandle PassHandle();
 
   InterfaceEndpointClient* endpoint_client() { return endpoint_client_.get(); }
@@ -111,7 +111,7 @@
   }
 
   void Bind(AssociatedInterfacePtrInfo<Interface> info,
-            scoped_refptr<base::SequencedTaskRunner> runner) {
+            scoped_refptr<base::SingleThreadTaskRunner> runner) {
     DCHECK(!proxy_);
     AssociatedInterfacePtrStateBase::Bind(
         info.PassHandle(), info.version(),
diff --git a/mojo/public/cpp/bindings/lib/binding_state.cc b/mojo/public/cpp/bindings/lib/binding_state.cc
index 41195801..af6ff5f 100644
--- a/mojo/public/cpp/bindings/lib/binding_state.cc
+++ b/mojo/public/cpp/bindings/lib/binding_state.cc
@@ -4,6 +4,8 @@
 
 #include "mojo/public/cpp/bindings/lib/binding_state.h"
 
+#include "mojo/public/cpp/bindings/lib/task_runner_helper.h"
+
 namespace mojo {
 namespace internal {
 
@@ -74,7 +76,7 @@
 
 void BindingStateBase::BindInternal(
     ScopedMessagePipeHandle handle,
-    scoped_refptr<base::SequencedTaskRunner> runner,
+    scoped_refptr<base::SingleThreadTaskRunner> runner,
     const char* interface_name,
     std::unique_ptr<MessageReceiver> request_validator,
     bool passes_associated_kinds,
@@ -83,19 +85,22 @@
     uint32_t interface_version) {
   DCHECK(!router_);
 
+  auto sequenced_runner =
+      GetTaskRunnerToUseFromUserProvidedTaskRunner(std::move(runner));
   MultiplexRouter::Config config =
       passes_associated_kinds
           ? MultiplexRouter::MULTI_INTERFACE
           : (has_sync_methods
                  ? MultiplexRouter::SINGLE_INTERFACE_WITH_SYNC_METHODS
                  : MultiplexRouter::SINGLE_INTERFACE);
-  router_ = new MultiplexRouter(std::move(handle), config, false, runner);
+  router_ =
+      new MultiplexRouter(std::move(handle), config, false, sequenced_runner);
   router_->SetMasterInterfaceName(interface_name);
 
   endpoint_client_.reset(new InterfaceEndpointClient(
       router_->CreateLocalEndpointHandle(kMasterInterfaceId), stub,
-      std::move(request_validator), has_sync_methods, std::move(runner),
-      interface_version));
+      std::move(request_validator), has_sync_methods,
+      std::move(sequenced_runner), interface_version));
 }
 
 }  // namesapce internal
diff --git a/mojo/public/cpp/bindings/lib/binding_state.h b/mojo/public/cpp/bindings/lib/binding_state.h
index ba3163f5..8d3708b 100644
--- a/mojo/public/cpp/bindings/lib/binding_state.h
+++ b/mojo/public/cpp/bindings/lib/binding_state.h
@@ -77,7 +77,7 @@
 
  protected:
   void BindInternal(ScopedMessagePipeHandle handle,
-                    scoped_refptr<base::SequencedTaskRunner> runner,
+                    scoped_refptr<base::SingleThreadTaskRunner> runner,
                     const char* interface_name,
                     std::unique_ptr<MessageReceiver> request_validator,
                     bool passes_associated_kinds,
@@ -103,7 +103,7 @@
   ~BindingState() { Close(); }
 
   void Bind(ScopedMessagePipeHandle handle,
-            scoped_refptr<base::SequencedTaskRunner> runner) {
+            scoped_refptr<base::SingleThreadTaskRunner> runner) {
     BindingStateBase::BindInternal(
         std::move(handle), runner, Interface::Name_,
         base::MakeUnique<typename Interface::RequestValidator_>(),
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc
index 55c9e03d..ee5e6b2 100644
--- a/mojo/public/cpp/bindings/lib/connector.cc
+++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -156,7 +156,8 @@
 
 Connector::~Connector() {
   {
-    // Allow for quick destruction on any thread if the pipe is already closed.
+    // Allow for quick destruction on any sequence if the pipe is already
+    // closed.
     base::AutoLock lock(connected_lock_);
     if (!connected_)
       return;
@@ -263,9 +264,9 @@
   if (!lock_)
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  // It shouldn't hurt even if |error_| may be changed by a different thread at
-  // the same time. The outcome is that we may write into |message_pipe_| after
-  // encountering an error, which should be fine.
+  // It shouldn't hurt even if |error_| may be changed by a different sequence
+  // at the same time. The outcome is that we may write into |message_pipe_|
+  // after encountering an error, which should be fine.
   if (error_)
     return false;
 
@@ -291,10 +292,10 @@
     case MOJO_RESULT_BUSY:
       // We'd get a "busy" result if one of the message's handles is:
       //   - |message_pipe_|'s own handle;
-      //   - simultaneously being used on another thread; or
+      //   - simultaneously being used on another sequence; or
       //   - in a "busy" state that prohibits it from being transferred (e.g.,
       //     a data pipe handle in the middle of a two-phase read/write,
-      //     regardless of which thread that two-phase read/write is happening
+      //     regardless of which sequence that two-phase read/write is happening
       //     on).
       // TODO(vtl): I wonder if this should be a |DCHECK()|. (But, until
       // crbug.com/389666, etc. are resolved, this will make tests fail quickly
diff --git a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
index 0fa68d3b6..0fe98c7e 100644
--- a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
+++ b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
@@ -16,6 +16,7 @@
 #include "mojo/public/cpp/bindings/associated_group.h"
 #include "mojo/public/cpp/bindings/associated_group_controller.h"
 #include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
+#include "mojo/public/cpp/bindings/lib/task_runner_helper.h"
 #include "mojo/public/cpp/bindings/lib/validation_util.h"
 #include "mojo/public/cpp/bindings/sync_call_restrictions.h"
 
diff --git a/mojo/public/cpp/bindings/lib/interface_ptr_state.cc b/mojo/public/cpp/bindings/lib/interface_ptr_state.cc
index 8f19567..6633471 100644
--- a/mojo/public/cpp/bindings/lib/interface_ptr_state.cc
+++ b/mojo/public/cpp/bindings/lib/interface_ptr_state.cc
@@ -4,6 +4,8 @@
 
 #include "mojo/public/cpp/bindings/lib/interface_ptr_state.h"
 
+#include "mojo/public/cpp/bindings/lib/task_runner_helper.h"
+
 namespace mojo {
 namespace internal {
 
@@ -44,7 +46,7 @@
 void InterfacePtrStateBase::Bind(
     ScopedMessagePipeHandle handle,
     uint32_t version,
-    scoped_refptr<base::SequencedTaskRunner> task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   DCHECK(!router_);
   DCHECK(!endpoint_client_);
   DCHECK(!handle_.is_valid());
@@ -53,7 +55,8 @@
 
   handle_ = std::move(handle);
   version_ = version;
-  runner_ = std::move(task_runner);
+  runner_ =
+      GetTaskRunnerToUseFromUserProvidedTaskRunner(std::move(task_runner));
 }
 
 void InterfacePtrStateBase::OnQueryVersion(
@@ -88,4 +91,4 @@
 }
 
 }  // namespace internal
-}  // namespace mojo
\ No newline at end of file
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/interface_ptr_state.h b/mojo/public/cpp/bindings/lib/interface_ptr_state.h
index 6e61f85..4aa73132 100644
--- a/mojo/public/cpp/bindings/lib/interface_ptr_state.h
+++ b/mojo/public/cpp/bindings/lib/interface_ptr_state.h
@@ -70,7 +70,7 @@
   void Swap(InterfacePtrStateBase* other);
   void Bind(ScopedMessagePipeHandle handle,
             uint32_t version,
-            scoped_refptr<base::SequencedTaskRunner> task_runner);
+            scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   ScopedMessagePipeHandle PassMessagePipe() {
     endpoint_client_.reset();
@@ -141,7 +141,7 @@
   }
 
   void Bind(InterfacePtrInfo<Interface> info,
-            scoped_refptr<base::SequencedTaskRunner> runner) {
+            scoped_refptr<base::SingleThreadTaskRunner> runner) {
     DCHECK(!proxy_);
     InterfacePtrStateBase::Bind(info.PassHandle(), info.version(),
                                 std::move(runner));
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.cc b/mojo/public/cpp/bindings/lib/multiplex_router.cc
index c46ef7117..f40c040 100644
--- a/mojo/public/cpp/bindings/lib/multiplex_router.cc
+++ b/mojo/public/cpp/bindings/lib/multiplex_router.cc
@@ -15,8 +15,6 @@
 #include "base/sequenced_task_runner.h"
 #include "base/stl_util.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "mojo/public/cpp/bindings/interface_endpoint_client.h"
 #include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
 #include "mojo/public/cpp/bindings/lib/may_auto_lock.h"
@@ -42,7 +40,7 @@
         client_(nullptr) {}
 
   // ---------------------------------------------------------------------------
-  // The following public methods are safe to call from any threads without
+  // The following public methods are safe to call from any sequence without
   // locking.
 
   InterfaceId id() const { return id_; }
@@ -92,7 +90,7 @@
     client_ = client;
   }
 
-  // This method must be called on the same thread as the corresponding
+  // This method must be called on the same sequence as the corresponding
   // AttachClient() call.
   void DetachClient() {
     router_->AssertLockAcquired();
@@ -125,7 +123,7 @@
 
   // ---------------------------------------------------------------------------
   // The following public methods (i.e., InterfaceEndpointController
-  // implementation) are called by the client on the same thread as the
+  // implementation) are called by the client on the same sequence as the
   // AttachClient() call. They are called outside of the router's lock.
 
   bool SendMessage(Message* message) override {
@@ -204,7 +202,7 @@
   }
 
   // ---------------------------------------------------------------------------
-  // The following members are safe to access from any threads.
+  // The following members are safe to access from any sequence.
 
   MultiplexRouter* const router_;
   const InterfaceId id_;
@@ -236,7 +234,7 @@
 
   // ---------------------------------------------------------------------------
   // The following members are only valid while a client is attached. They are
-  // used exclusively on the client's thread. They may be accessed outside of
+  // used exclusively on the client's sequence. They may be accessed outside of
   // the router's lock.
 
   std::unique_ptr<SyncEventWatcher> sync_watcher_;
@@ -347,7 +345,7 @@
     // Always participate in sync handle watching in multi-interface mode,
     // because even if it doesn't expect sync requests during sync handle
     // watching, it may still need to dispatch messages to associated endpoints
-    // on a different thread.
+    // on a different sequence.
     connector_.AllowWokenUpBySyncWatchOnSameThread();
   }
   connector_.set_incoming_receiver(&filters_);
@@ -809,7 +807,7 @@
     // object within NotifyError(). Holding the lock will lead to deadlock.
     //
     // It is safe to call into |client| without the lock. Because |client| is
-    // always accessed on the same thread, including DetachEndpointClient().
+    // always accessed on the same sequence, including DetachEndpointClient().
     MayAutoUnlock unlocker(&lock_);
     client->NotifyError(disconnect_reason);
   }
@@ -883,7 +881,7 @@
     // deadlock.
     //
     // It is safe to call into |client| without the lock. Because |client| is
-    // always accessed on the same thread, including DetachEndpointClient().
+    // always accessed on the same sequence, including DetachEndpointClient().
     MayAutoUnlock unlocker(&lock_);
     result = client->HandleIncomingMessage(message);
   }
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.h b/mojo/public/cpp/bindings/lib/multiplex_router.h
index 3b2e954d..3061ce6 100644
--- a/mojo/public/cpp/bindings/lib/multiplex_router.h
+++ b/mojo/public/cpp/bindings/lib/multiplex_router.h
@@ -44,15 +44,15 @@
 // MultiplexRouter supports routing messages for multiple interfaces over a
 // single message pipe.
 //
-// It is created on the thread where the master interface of the message pipe
+// It is created on the sequence where the master interface of the message pipe
 // lives. Although it is ref-counted, it is guarateed to be destructed on the
-// same thread.
-// Some public methods are only allowed to be called on the creating thread;
-// while the others are safe to call from any threads. Please see the method
+// same sequence.
+// Some public methods are only allowed to be called on the creating sequence;
+// while the others are safe to call from any sequence. Please see the method
 // comments for more details.
 //
 // NOTE: CloseMessagePipe() or PassMessagePipe() MUST be called on |runner|'s
-// thread before this object is destroyed.
+// sequence before this object is destroyed.
 class MOJO_CPP_BINDINGS_EXPORT MultiplexRouter
     : NON_EXPORTED_BASE(public MessageReceiver),
       public AssociatedGroupController,
@@ -86,7 +86,7 @@
   void SetMasterInterfaceName(const char* name);
 
   // ---------------------------------------------------------------------------
-  // The following public methods are safe to call from any threads.
+  // The following public methods are safe to call from any sequence.
 
   // AssociatedGroupController implementation:
   InterfaceId AssociateInterface(
@@ -106,7 +106,7 @@
   bool PrefersSerializedMessages() override;
 
   // ---------------------------------------------------------------------------
-  // The following public methods are called on the creating thread.
+  // The following public methods are called on the creating sequence.
 
   // Please note that this method shouldn't be called unless it results from an
   // explicit request of the user of bindings (e.g., the user sets an
@@ -120,7 +120,8 @@
     return connector_.PassMessagePipe();
   }
 
-  // Blocks the current thread until the first incoming message, or |deadline|.
+  // Blocks the current sequence until the first incoming message, or
+  // |deadline|.
   bool WaitForIncomingMessage(MojoDeadline deadline) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return connector_.WaitForIncomingMessage(deadline);
@@ -172,7 +173,7 @@
   void OnPipeConnectionError();
 
   // Specifies whether we are allowed to directly call into
-  // InterfaceEndpointClient (given that we are already on the same thread as
+  // InterfaceEndpointClient (given that we are already on the same sequence as
   // the client).
   enum ClientCallBehavior {
     // Don't call any InterfaceEndpointClient methods directly.
diff --git a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
index d987cf0..2e5559c 100644
--- a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
+++ b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
@@ -15,7 +15,7 @@
 
 // ScopedInterfaceEndpointHandle::State ----------------------------------------
 
-// State could be called from multiple threads.
+// State could be called from multiple sequences.
 class ScopedInterfaceEndpointHandle::State
     : public base::RefCountedThreadSafe<State> {
  public:
@@ -52,7 +52,7 @@
           // Intentionally keep |group_controller_| unchanged.
           // That is because the callback created by
           // CreateGroupControllerGetter() could still be used after this point,
-          // potentially from another thread. We would like it to continue
+          // potentially from another sequence. We would like it to continue
           // returning the same group controller.
           //
           // Imagine there is a ThreadSafeForwarder A:
@@ -172,7 +172,7 @@
     DCHECK(!IsValidInterfaceId(id_));
   }
 
-  // Called by the peer, maybe from a different thread.
+  // Called by the peer, maybe from a different sequence.
   void OnAssociated(InterfaceId id,
                     scoped_refptr<AssociatedGroupController> group_controller) {
     AssociationEventCallback handler;
@@ -180,7 +180,7 @@
       internal::MayAutoLock locker(&lock_);
 
       // There may be race between Close() of endpoint A and
-      // NotifyPeerAssociation() of endpoint A_peer on different threads.
+      // NotifyPeerAssociation() of endpoint A_peer on different sequences.
       // Therefore, it is possible that endpoint A has been closed but it
       // still gets OnAssociated() call from its peer.
       if (!pending_association_)
@@ -208,7 +208,7 @@
       std::move(handler).Run(ASSOCIATED);
   }
 
-  // Called by the peer, maybe from a different thread.
+  // Called by the peer, maybe from a different sequence.
   void OnPeerClosedBeforeAssociation(
       const base::Optional<DisconnectReason>& reason) {
     AssociationEventCallback handler;
@@ -216,7 +216,7 @@
       internal::MayAutoLock locker(&lock_);
 
       // There may be race between Close()/NotifyPeerAssociation() of endpoint
-      // A and Close() of endpoint A_peer on different threads.
+      // A and Close() of endpoint A_peer on different sequences.
       // Therefore, it is possible that endpoint A is not in pending association
       // state but still gets OnPeerClosedBeforeAssociation() call from its
       // peer.
@@ -374,7 +374,7 @@
 
 base::Callback<AssociatedGroupController*()>
 ScopedInterfaceEndpointHandle::CreateGroupControllerGetter() const {
-  // We allow this callback to be run on any thread. If this handle is created
+  // We allow this callback to be run on any sequence. If this handle is created
   // in non-pending state, we don't have a lock but it should still be safe
   // because the group controller never changes.
   return base::Bind(&State::group_controller, state_);
diff --git a/mojo/public/cpp/bindings/lib/task_runner_helper.cc b/mojo/public/cpp/bindings/lib/task_runner_helper.cc
new file mode 100644
index 0000000..e1020499
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/task_runner_helper.cc
@@ -0,0 +1,27 @@
+// 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 "mojo/public/cpp/bindings/lib/task_runner_helper.h"
+
+#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace mojo {
+namespace internal {
+
+scoped_refptr<base::SequencedTaskRunner>
+GetTaskRunnerToUseFromUserProvidedTaskRunner(
+    scoped_refptr<base::SingleThreadTaskRunner> runner) {
+  if (runner) {
+    DCHECK(base::ThreadTaskRunnerHandle::IsSet() &&
+           runner->RunsTasksInCurrentSequence());
+    return runner;
+  }
+  return base::SequencedTaskRunnerHandle::Get();
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/task_runner_helper.h b/mojo/public/cpp/bindings/lib/task_runner_helper.h
new file mode 100644
index 0000000..44d1ebf
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/task_runner_helper.h
@@ -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.
+
+#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_TASK_RUNNER_HELPER_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_TASK_RUNNER_HELPER_H_
+
+#include "base/memory/ref_counted.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+class SequencedTaskRunner;
+}  // namespace base
+
+namespace mojo {
+namespace internal {
+
+// Returns the SequencedTaskRunner to use from the optional user-provided
+// SingleThreadTaskRunner. If |runner| is provided non-null, it is returned.
+// Otherwise, the current SequencedTaskRunner is returned. If |runner| is
+// non-null, it must run on the current thread.
+scoped_refptr<base::SequencedTaskRunner>
+GetTaskRunnerToUseFromUserProvidedTaskRunner(
+    scoped_refptr<base::SingleThreadTaskRunner> runner);
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_TASK_RUNNER_HELPER_H_
diff --git a/mojo/public/cpp/bindings/pipe_control_message_proxy.h b/mojo/public/cpp/bindings/pipe_control_message_proxy.h
index 52c408f..f57f039a4 100644
--- a/mojo/public/cpp/bindings/pipe_control_message_proxy.h
+++ b/mojo/public/cpp/bindings/pipe_control_message_proxy.h
@@ -19,11 +19,11 @@
 
 // Proxy for request messages defined in pipe_control_messages.mojom.
 //
-// NOTE: This object may be used from multiple threads.
+// NOTE: This object may be used from multiple sequences.
 class MOJO_CPP_BINDINGS_EXPORT PipeControlMessageProxy {
  public:
   // Doesn't take ownership of |receiver|. If This PipeControlMessageProxy will
-  // be used from multiple threads, |receiver| must be thread-safe.
+  // be used from multiple sequences, |receiver| must be thread-safe.
   explicit PipeControlMessageProxy(MessageReceiver* receiver);
 
   void NotifyPeerEndpointClosed(InterfaceId id,
diff --git a/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h b/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h
index 16527cf7..5d00e501 100644
--- a/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h
+++ b/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h
@@ -24,7 +24,7 @@
 // ScopedInterfaceEndpointHandle refers to one end of an interface, either the
 // implementation side or the client side.
 // Threading: At any given time, a ScopedInterfaceEndpointHandle should only
-// be accessed from a single thread.
+// be accessed from a single sequence.
 class MOJO_CPP_BINDINGS_EXPORT ScopedInterfaceEndpointHandle {
  public:
   // Creates a pair of handles representing the two endpoints of an interface,
@@ -69,7 +69,7 @@
   using AssociationEventCallback = base::OnceCallback<void(AssociationEvent)>;
   // Note:
   // - |handler| won't run if the handle is invalid. Otherwise, |handler| is run
-  //   on the calling thread asynchronously, even if the interface has already
+  //   on the calling sequence asynchronously, even if the interface has already
   //   been associated or the peer has been closed before association.
   // - |handler| won't be called after this object is destroyed or reset.
   // - A null |handler| can be used to cancel the previous callback.
@@ -98,8 +98,8 @@
   void ResetInternal(const base::Optional<DisconnectReason>& reason);
 
   // Used by AssociatedGroup.
-  // It is safe to run the returned callback on any thread, or after this handle
-  // is destroyed.
+  // It is safe to run the returned callback on any sequence, or after this
+  // handle is destroyed.
   // The return value of the getter:
   //   - If the getter is retrieved when the handle is invalid, the return value
   //     of the getter will always be null.
diff --git a/mojo/public/cpp/bindings/sync_call_restrictions.h b/mojo/public/cpp/bindings/sync_call_restrictions.h
index 99e13a4..a2a7d60e 100644
--- a/mojo/public/cpp/bindings/sync_call_restrictions.h
+++ b/mojo/public/cpp/bindings/sync_call_restrictions.h
@@ -58,12 +58,12 @@
 // MOJO_PROPERTY_TYPE_SYNC_CALL_ALLOWED. If the default setting says no but you
 // have a very compelling reason to disregard that (which should be very very
 // rare), you can override it by constructing a ScopedAllowSyncCall object,
-// which allows making sync calls on the current thread during its lifetime.
+// which allows making sync calls on the current sequence during its lifetime.
 class MOJO_CPP_BINDINGS_EXPORT SyncCallRestrictions {
  public:
 #if ENABLE_SYNC_CALL_RESTRICTIONS
-  // Checks whether the current thread is allowed to make sync calls, and causes
-  // a DCHECK if not.
+  // Checks whether the current sequence is allowed to make sync calls, and
+  // causes a DCHECK if not.
   static void AssertSyncCallAllowed();
 #else
   // Inline the empty definitions of functions so that they can be compiled out.
@@ -106,7 +106,7 @@
 
   // If a process is configured to disallow sync calls in general, constructing
   // a ScopedAllowSyncCall object temporarily allows making sync calls on the
-  // current thread. Doing this is almost always incorrect, which is why we
+  // current sequence. Doing this is almost always incorrect, which is why we
   // limit who can use this through friend. If you find yourself needing to use
   // this, talk to mojo/OWNERS.
   class ScopedAllowSyncCall {
diff --git a/mojo/public/cpp/bindings/sync_event_watcher.h b/mojo/public/cpp/bindings/sync_event_watcher.h
index 1f1d265a..76dc4fe 100644
--- a/mojo/public/cpp/bindings/sync_event_watcher.h
+++ b/mojo/public/cpp/bindings/sync_event_watcher.h
@@ -19,7 +19,7 @@
 
 // SyncEventWatcher supports waiting on a base::WaitableEvent to signal while
 // also allowing other SyncEventWatchers and SyncHandleWatchers on the same
-// thread to wake up as needed.
+// sequence to wake up as needed.
 //
 // This class is not thread safe.
 class MOJO_CPP_BINDINGS_EXPORT SyncEventWatcher {
@@ -29,12 +29,13 @@
   ~SyncEventWatcher();
 
   // Registers |event_| with SyncHandleRegistry, so that when others perform
-  // sync watching on the same thread, |event_| will be watched along with them.
+  // sync watching on the same sequence, |event_| will be watched along with
+  // them.
   void AllowWokenUpBySyncWatchOnSameThread();
 
   // Waits on |event_| plus all other events and handles registered with this
-  // thread's SyncHandleRegistry, running callbacks synchronously for any ready
-  // events and handles.
+  // sequence's SyncHandleRegistry, running callbacks synchronously for any
+  // ready events and handles.
   // This method:
   //   - returns true when |should_stop| is set to true;
   //   - return false when any error occurs, including this object being
diff --git a/mojo/public/cpp/bindings/sync_handle_watcher.h b/mojo/public/cpp/bindings/sync_handle_watcher.h
index 18df10c..e680d74a 100644
--- a/mojo/public/cpp/bindings/sync_handle_watcher.h
+++ b/mojo/public/cpp/bindings/sync_handle_watcher.h
@@ -15,15 +15,15 @@
 namespace mojo {
 
 // SyncHandleWatcher supports watching a handle synchronously. It also supports
-// registering the handle with a thread-local storage (SyncHandleRegistry), so
-// that when other SyncHandleWatcher instances on the same thread perform sync
+// registering the handle with a sequence-local storage (SyncHandleRegistry), so
+// that when other SyncHandleWatcher instances on the same sequence perform sync
 // handle watching, this handle will be watched together.
 //
 // SyncHandleWatcher is used for sync methods. While a sync call is waiting for
-// response, we would like to block the thread. On the other hand, we need
-// incoming sync method requests on the same thread to be able to reenter. We
+// response, we would like to block the sequence. On the other hand, we need
+// incoming sync method requests on the same sequence to be able to reenter. We
 // also need master interface endpoints to continue dispatching messages for
-// associated endpoints on different threads.
+// associated endpoints on different sequence.
 //
 // This class is not thread safe.
 class MOJO_CPP_BINDINGS_EXPORT SyncHandleWatcher {
@@ -36,7 +36,7 @@
   ~SyncHandleWatcher();
 
   // Registers |handle_| with SyncHandleRegistry, so that when others perform
-  // sync handle watching on the same thread, |handle_| will be watched
+  // sync handle watching on the same sequence, |handle_| will be watched
   // together.
   void AllowWokenUpBySyncWatchOnSameThread();
 
diff --git a/mojo/public/cpp/bindings/thread_safe_interface_ptr.h b/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
index c15c6e3..4a0b040 100644
--- a/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
+++ b/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
@@ -22,22 +22,22 @@
 #include "mojo/public/cpp/bindings/sync_event_watcher.h"
 
 // ThreadSafeInterfacePtr wraps a non-thread-safe InterfacePtr and proxies
-// messages to it. Async calls are posted to the thread that the InteracePtr is
-// bound to, and the responses are posted back. Sync calls are dispatched
-// directly if the call is made on the thread that the wrapped InterfacePtr is
+// messages to it. Async calls are posted to the sequence that the InteracePtr
+// is bound to, and the responses are posted back. Sync calls are dispatched
+// directly if the call is made on the sequence that the wrapped InterfacePtr is
 // bound to, or posted otherwise. It's important to be aware that sync calls
-// block both the calling thread and the InterfacePtr thread. That means that
-// you cannot make sync calls through a ThreadSafeInterfacePtr if the
-// underlying InterfacePtr is bound to a thread that cannot block, like the IO
+// block both the calling sequence and the InterfacePtr sequence. That means
+// that you cannot make sync calls through a ThreadSafeInterfacePtr if the
+// underlying InterfacePtr is bound to a sequence that cannot block, like the IO
 // thread.
 
 namespace mojo {
 
-// Instances of this class may be used from any thread to serialize |Interface|
-// messages and forward them elsewhere. In general you should use one of the
-// ThreadSafeInterfacePtrBase helper aliases defined below, but this type may be
-// useful if you need/want to manually manage the lifetime of the underlying
-// proxy object which will be used to ultimately send messages.
+// Instances of this class may be used from any sequence to serialize
+// |Interface| messages and forward them elsewhere. In general you should use
+// one of the ThreadSafeInterfacePtrBase helper aliases defined below, but this
+// type may be useful if you need/want to manually manage the lifetime of the
+// underlying proxy object which will be used to ultimately send messages.
 template <typename Interface>
 class ThreadSafeForwarder : public MessageReceiverWithResponder {
  public:
@@ -50,7 +50,8 @@
   // |forward| or |forward_with_responder| by posting to |task_runner|.
   //
   // Any message sent through this forwarding interface will dispatch its reply,
-  // if any, back to the thread which called the corresponding interface method.
+  // if any, back to the sequence which called the corresponding interface
+  // method.
   ThreadSafeForwarder(
       const scoped_refptr<base::SequencedTaskRunner>& task_runner,
       const ForwardMessageCallback& forward,
@@ -111,7 +112,7 @@
     }
 
     // Async messages are always posted (even if |task_runner_| runs tasks on
-    // this thread) to guarantee that two async calls can't be reordered.
+    // this sequence) to guarantee that two async calls can't be reordered.
     if (!message->has_flag(Message::kFlagIsSync)) {
       auto reply_forwarder =
           base::MakeUnique<ForwardToCallingThread>(std::move(responder));
@@ -123,15 +124,15 @@
 
     SyncCallRestrictions::AssertSyncCallAllowed();
 
-    // If the InterfacePtr is bound to this thread, dispatch it directly.
+    // If the InterfacePtr is bound to this sequence, dispatch it directly.
     if (task_runner_->RunsTasksInCurrentSequence()) {
       forward_with_responder_.Run(std::move(*message), std::move(responder));
       return true;
     }
 
-    // If the InterfacePtr is bound on another thread, post the call.
-    // TODO(yzshen, watk): We block both this thread and the InterfacePtr
-    // thread. Ideally only this thread would block.
+    // If the InterfacePtr is bound on another sequence, post the call.
+    // TODO(yzshen, watk): We block both this sequence and the InterfacePtr
+    // sequence. Ideally only this sequence would block.
     auto response = make_scoped_refptr(new SyncResponseInfo());
     auto response_signaler = base::MakeUnique<SyncResponseSignaler>(response);
     task_runner_->PostTask(
@@ -164,7 +165,7 @@
     return true;
   }
 
-  // Data that we need to share between the threads involved in a sync call.
+  // Data that we need to share between the sequences involved in a sync call.
   struct SyncResponseInfo
       : public base::RefCountedThreadSafe<SyncResponseInfo> {
     Message message;
@@ -263,9 +264,9 @@
       : forwarder_(std::move(forwarder)) {}
 
   // Creates a ThreadSafeInterfacePtrBase wrapping an underlying non-thread-safe
-  // InterfacePtrType which is bound to the calling thread. All messages sent
+  // InterfacePtrType which is bound to the calling sequence. All messages sent
   // via this thread-safe proxy will internally be sent by first posting to this
-  // (the calling) thread's TaskRunner.
+  // (the calling) sequence's TaskRunner.
   static scoped_refptr<ThreadSafeInterfacePtrBase> Create(
       InterfacePtrType interface_ptr) {
     scoped_refptr<PtrWrapper> wrapper =
@@ -296,7 +297,7 @@
   struct PtrWrapperDeleter;
 
   // Helper class which owns an |InterfacePtrType| instance on an appropriate
-  // thread. This is kept alive as long its bound within some
+  // sequence. This is kept alive as long its bound within some
   // ThreadSafeForwarder's callbacks.
   class PtrWrapper
       : public base::RefCountedThreadSafe<PtrWrapper, PtrWrapperDeleter> {
@@ -323,8 +324,8 @@
       // endpoints on this interface (at least not immediately). In order to fix
       // this, we need to create a MultiplexRouter immediately and bind it to
       // the interface pointer on the |task_runner_|. Therefore, MultiplexRouter
-      // should be able to be created on a thread different than the one that it
-      // is supposed to listen on. crbug.com/682334
+      // should be able to be created on a sequence different than the one that
+      // it is supposed to listen on. crbug.com/682334
       task_runner_->PostTask(FROM_HERE, base::Bind(&PtrWrapper::Bind, this,
                                                    base::Passed(&ptr_info)));
     }
diff --git a/mojo/public/cpp/system/README.md b/mojo/public/cpp/system/README.md
index bb669623..7b842571 100644
--- a/mojo/public/cpp/system/README.md
+++ b/mojo/public/cpp/system/README.md
@@ -217,8 +217,8 @@
 The [`mojo::SimpleWatcher`](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/simple_watcher.h)
 class serves as a convenient helper for using the [low-level watcher API](/mojo/public/c/system#Signals-Watchers)
 to watch a handle for signaling state changes. A `SimpleWatcher` is bound to a
-single thread and always dispatches its notifications on a
-`base::SingleThreadTaskRunner`.
+single sequence and always dispatches its notifications on a
+`base::SequencedTaskRunner`.
 
 `SimpleWatcher` has two possible modes of operation, selected at construction
 time by the `mojo::SimpleWatcher::ArmingPolicy` enum:
@@ -280,7 +280,7 @@
 
 ## Synchronous Waiting
 
-The C++ System API defines some utilities to block a calling thread while
+The C++ System API defines some utilities to block a calling sequence while
 waiting for one or more handles to change signaling state in an interesting way.
 These threads combine usage of the [low-level Watcher API](/mojo/public/c/system#Signals-Watchers)
 with common synchronization primitives (namely `base::WaitableEvent`.)
@@ -294,8 +294,9 @@
 
 ### Waiting On a Single Handle
 
-The `mojo::Wait` function simply blocks the calling thread until a given signal
-mask is either partially satisfied or fully unsatisfiable on a given handle.
+The `mojo::Wait` function simply blocks the calling sequence until a given
+signal mask is either partially satisfied or fully unsatisfiable on a given
+handle.
 
 ``` cpp
 mojo::MessagePipe pipe;
@@ -353,9 +354,9 @@
 explicitly added to or removed from the set at any time.
 
 The `WaitSet` may be waited upon repeatedly, each time blocking the calling
-thread until either one of the handles attains an interesting signaling state or
-one of the events is signaled. For example let's suppose we want to wait up to 5
-seconds for either one of two handles to become readable:
+sequence until either one of the handles attains an interesting signaling state
+or one of the events is signaled. For example let's suppose we want to wait up
+to 5 seconds for either one of two handles to become readable:
 
 ``` cpp
 base::WaitableEvent timeout_event(
diff --git a/mojo/public/cpp/system/simple_watcher.h b/mojo/public/cpp/system/simple_watcher.h
index a697e46..d5caf92 100644
--- a/mojo/public/cpp/system/simple_watcher.h
+++ b/mojo/public/cpp/system/simple_watcher.h
@@ -24,9 +24,9 @@
 
 namespace mojo {
 
-// This provides a convenient thread-bound watcher implementation to safely
+// This provides a convenient sequence-bound watcher implementation to safely
 // watch a single handle, dispatching state change notifications to an arbitrary
-// SequencedTaskRunner running on the same thread as the SimpleWatcher.
+// SequencedTaskRunner running on the same sequence as the SimpleWatcher.
 //
 // SimpleWatcher exposes the concept of "arming" from the low-level Watcher API.
 // In general, a SimpleWatcher must be "armed" in order to dispatch a single
@@ -107,7 +107,7 @@
   // explicitly called.
   //
   // Once the watch is started, |callback| may be called at any time on the
-  // current thread until |Cancel()| is called or the handle is closed. Note
+  // current sequence until |Cancel()| is called or the handle is closed. Note
   // that |callback| can be called for results other than
   // |MOJO_RESULT_CANCELLED| only if the SimpleWatcher is currently armed. Use
   // ArmingPolicy to configure how a SimpleWatcher is armed.
@@ -202,8 +202,8 @@
   // The policy used to determine how this SimpleWatcher is armed.
   const ArmingPolicy arming_policy_;
 
-  // The TaskRunner of this SimpleWatcher's owning thread. This field is safe to
-  // access from any thread.
+  // The TaskRunner of this SimpleWatcher's owning sequence. This field is safe
+  // to access from any sequence.
   const scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
   // Whether |task_runner_| is the same as
@@ -216,7 +216,7 @@
   // if any.
   scoped_refptr<Context> context_;
 
-  // Fields below must only be accessed on the SimpleWatcher's owning thread.
+  // Fields below must only be accessed on the SimpleWatcher's owning sequence.
 
   // The handle currently under watch. Not owned.
   Handle handle_;
diff --git a/mojo/public/cpp/system/wait.cc b/mojo/public/cpp/system/wait.cc
index bb383fe2..4f00587a 100644
--- a/mojo/public/cpp/system/wait.cc
+++ b/mojo/public/cpp/system/wait.cc
@@ -55,7 +55,7 @@
   base::WaitableEvent event_;
 
   // NOTE: Although these are modified in Notify() which may be called from any
-  // thread, Notify() is guaranteed to never run concurrently with itself.
+  // sequence, Notify() is guaranteed to never run concurrently with itself.
   // Furthermore, they are only modified once, before |event_| signals; so there
   // is no need for a WatchContext user to synchronize access to these fields
   // apart from waiting on |event()|.
diff --git a/mojo/public/cpp/system/wait.h b/mojo/public/cpp/system/wait.h
index c597edb..ccd6ebe 100644
--- a/mojo/public/cpp/system/wait.h
+++ b/mojo/public/cpp/system/wait.h
@@ -13,9 +13,9 @@
 
 namespace mojo {
 
-// Blocks the calling thread, waiting for one or more signals in |signals| to be
-// become satisfied, not-satisfied, or permanently unsatisfiable on the handle,
-// depending on the |condition| selected.
+// Blocks the calling sequence, waiting for one or more signals in |signals| to
+// be become satisfied, not-satisfied, or permanently unsatisfiable on the
+// handle, depending on the |condition| selected.
 //
 // If |signals_state| is non-null, |handle| is valid, the wait is not cancelled
 // (see return values below), the last known signaling state of |handle| is
@@ -31,7 +31,7 @@
 //       is |MOJO_WATCH_CONDITION_SATISFIED|.
 //   |MOJO_RESULT_INVALID_ARGUMENT| if |handle| is not a valid handle.
 //   |MOJO_RESULT_CANCELLED| if the wait was cancelled because |handle| was
-//       closed by some other thread while waiting.
+//       closed by some other sequence while waiting.
 MOJO_CPP_SYSTEM_EXPORT MojoResult
 Wait(Handle handle,
      MojoHandleSignals signals,
@@ -72,7 +72,7 @@
 //   |MOJO_RESULT_INVALID_ARGUMENT| if any Handle in |handles| is invalid,
 //       or if either |handles| or |signals| is null.
 //   |MOJO_RESULT_CANCELLED| if the wait was cancelled because a handle in
-//       |handles| was closed by some other thread while waiting.
+//       |handles| was closed by some other sequence while waiting.
 //       |*result_index| contains the index of the closed Handle if
 //       |result_index| is non-null.
 MOJO_CPP_SYSTEM_EXPORT MojoResult
diff --git a/mojo/public/cpp/system/wait_set.cc b/mojo/public/cpp/system/wait_set.cc
index 6dcf26f..e73a9a4 100644
--- a/mojo/public/cpp/system/wait_set.cc
+++ b/mojo/public/cpp/system/wait_set.cc
@@ -272,8 +272,8 @@
               Context* context) {
     base::AutoLock lock(lock_);
 
-    // This notification may have raced with RemoveHandle() from another thread.
-    // We only signal the WaitSet if that's not the case.
+    // This notification may have raced with RemoveHandle() from another
+    // sequence. We only signal the WaitSet if that's not the case.
     if (handle_to_context_.count(handle)) {
       ready_handles_[handle] = {result, signals_state};
       handle_event_.Signal();
@@ -288,13 +288,13 @@
       // NOTE: We retain a context ref in |cancelled_contexts_| to ensure that
       // this Context's heap address is not reused too soon. For example, it
       // would otherwise be possible for the user to call AddHandle() from the
-      // WaitSet's thread immediately after this notification has fired on
-      // another thread, potentially reusing the same heap address for the newly
-      // added Context; and then they may call RemoveHandle() for this handle
-      // (not knowing its context has just been implicitly cancelled) and
+      // WaitSet's sequence immediately after this notification has fired on
+      // another sequence, potentially reusing the same heap address for the
+      // newly added Context; and then they may call RemoveHandle() for this
+      // handle (not knowing its context has just been implicitly cancelled) and
       // cause the new Context to be incorrectly removed from |contexts_|.
       //
-      // This vector is cleared on the WaitSet's own thread every time
+      // This vector is cleared on the WaitSet's own sequence every time
       // RemoveHandle is called.
       cancelled_contexts_.emplace_back(make_scoped_refptr(context));
 
@@ -314,7 +314,7 @@
   };
 
   // Not guarded by lock. Must only be accessed from the WaitSet's owning
-  // thread.
+  // sequence.
   ScopedWatcherHandle watcher_handle_;
 
   base::Lock lock_;
diff --git a/mojo/public/cpp/system/wait_set.h b/mojo/public/cpp/system/wait_set.h
index 5047a86..46d6b7d 100644
--- a/mojo/public/cpp/system/wait_set.h
+++ b/mojo/public/cpp/system/wait_set.h
@@ -20,7 +20,7 @@
 
 namespace mojo {
 
-// WaitSet provides an efficient means of blocking a thread on any number of
+// WaitSet provides an efficient means of blocking a sequence on any number of
 // events and Mojo handle state changes.
 //
 // Unlike WaitMany(), which incurs some extra setup cost for every call, a
@@ -98,7 +98,7 @@
   //   |MOJO_RESULT_FAILED_PRECONDITION| all of the signals for the handle have
   //       become permanently unsatisfiable.
   //   |MOJO_RESULT_CANCELLED| if the handle has been closed from another
-  //       thread. NOTE: It is important to recognize that this means the
+  //       sequence. NOTE: It is important to recognize that this means the
   //       corresponding value in |ready_handles| is either invalid, or valid
   //       but referring to a different handle (i.e. has already been reused) by
   //       the time Wait() returns. The handle in question is automatically
diff --git a/services/ui/gpu/gpu_main.cc b/services/ui/gpu/gpu_main.cc
index 88a8f96b..4c96305 100644
--- a/services/ui/gpu/gpu_main.cc
+++ b/services/ui/gpu/gpu_main.cc
@@ -191,8 +191,7 @@
 
   frame_sink_manager_ = base::MakeUnique<viz::FrameSinkManagerImpl>(
       true, display_provider_.get());
-  frame_sink_manager_->BindAndSetClient(std::move(request),
-                                        base::SequencedTaskRunnerHandle::Get(),
+  frame_sink_manager_->BindAndSetClient(std::move(request), nullptr,
                                         std::move(client));
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
index c47f482c..e193675 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
@@ -58,7 +58,7 @@
     Platform::Current()->GetInterfaceProvider()->GetInterface(
         mojo::MakeRequest(&provider));
 
-    scoped_refptr<base::SequencedTaskRunner> task_runner;
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner;
     auto scheduler = blink::Platform::Current()->CurrentThread()->Scheduler();
     if (scheduler) {
       WebTaskRunner* web_task_runner = scheduler->CompositorTaskRunner();
@@ -66,10 +66,6 @@
         task_runner = web_task_runner->ToSingleThreadTaskRunner();
       }
     }
-    if (!task_runner) {
-      task_runner = base::SequencedTaskRunnerHandle::Get();
-    }
-
     cc::mojom::blink::CompositorFrameSinkClientPtr client;
     binding_.Bind(mojo::MakeRequest(&client), task_runner);
     provider->CreateCompositorFrameSink(frame_sink_id_, std::move(client),