diff --git a/chrome/browser/chromeos/drive/OWNERS b/chrome/browser/chromeos/drive/OWNERS
index 9df9e4f..2563657 100644
--- a/chrome/browser/chromeos/drive/OWNERS
+++ b/chrome/browser/chromeos/drive/OWNERS
@@ -2,5 +2,4 @@
 hidehiko@chromium.org
 hirono@chromium.org
 kinaba@chromium.org
-mtomasz@chromium.org
 yoshiki@chromium.org
diff --git a/chrome/browser/chromeos/extensions/file_manager/OWNERS b/chrome/browser/chromeos/extensions/file_manager/OWNERS
index 5f9e355..b1654a9 100644
--- a/chrome/browser/chromeos/extensions/file_manager/OWNERS
+++ b/chrome/browser/chromeos/extensions/file_manager/OWNERS
@@ -2,5 +2,4 @@
 fukino@chromium.org
 hirono@chromium.org
 kinaba@chromium.org
-mtomasz@chromium.org
 yoshiki@chromium.org
diff --git a/chrome/browser/chromeos/extensions/file_system_provider/OWNERS b/chrome/browser/chromeos/extensions/file_system_provider/OWNERS
index 4eab6e4..4de4587c 100644
--- a/chrome/browser/chromeos/extensions/file_system_provider/OWNERS
+++ b/chrome/browser/chromeos/extensions/file_system_provider/OWNERS
@@ -1 +1,2 @@
-mtomasz@chromium.org
+fukino@chromium.org
+yamaguchi@chromium.org
diff --git a/chrome/browser/chromeos/file_manager/OWNERS b/chrome/browser/chromeos/file_manager/OWNERS
index 82f9484..3dd2532 100644
--- a/chrome/browser/chromeos/file_manager/OWNERS
+++ b/chrome/browser/chromeos/file_manager/OWNERS
@@ -1,5 +1,4 @@
 fukino@chromium.org
 hirono@chromium.org
 kinaba@chromium.org
-mtomasz@chromium.org
 yoshiki@chromium.org
diff --git a/chrome/browser/chromeos/file_system_provider/OWNERS b/chrome/browser/chromeos/file_system_provider/OWNERS
index 4eab6e4..4de4587c 100644
--- a/chrome/browser/chromeos/file_system_provider/OWNERS
+++ b/chrome/browser/chromeos/file_system_provider/OWNERS
@@ -1 +1,2 @@
-mtomasz@chromium.org
+fukino@chromium.org
+yamaguchi@chromium.org
diff --git a/chrome/browser/chromeos/fileapi/OWNERS b/chrome/browser/chromeos/fileapi/OWNERS
index 4eab6e4..af611691 100644
--- a/chrome/browser/chromeos/fileapi/OWNERS
+++ b/chrome/browser/chromeos/fileapi/OWNERS
@@ -1 +1,3 @@
-mtomasz@chromium.org
+fukino@chromium.org
+yamaguchi@chromium.org
+
diff --git a/chrome/browser/chromeos/smb_client/OWNERS b/chrome/browser/chromeos/smb_client/OWNERS
index 2d8049a..9a71e3b2 100644
--- a/chrome/browser/chromeos/smb_client/OWNERS
+++ b/chrome/browser/chromeos/smb_client/OWNERS
@@ -1,5 +1,4 @@
 set noparent
 allenvic@chromium.org
 baileyberro@chromium.org
-mtomasz@chromium.org
 zentaro@chromium.org
diff --git a/chrome/browser/drive/OWNERS b/chrome/browser/drive/OWNERS
index aec41e60..7ca29178 100644
--- a/chrome/browser/drive/OWNERS
+++ b/chrome/browser/drive/OWNERS
@@ -3,5 +3,4 @@
 hidehiko@chromium.org
 hirono@chromium.org
 kinaba@chromium.org
-mtomasz@chromium.org
 yoshiki@chromium.org
diff --git a/chrome/browser/extensions/api/file_system/OWNERS b/chrome/browser/extensions/api/file_system/OWNERS
index ac81da7..64f6677 100644
--- a/chrome/browser/extensions/api/file_system/OWNERS
+++ b/chrome/browser/extensions/api/file_system/OWNERS
@@ -1,3 +1,2 @@
 benwells@chromium.org
-mtomasz@chromium.org
 sammc@chromium.org
diff --git a/chrome/browser/extensions/api/webstore_widget_private/OWNERS b/chrome/browser/extensions/api/webstore_widget_private/OWNERS
index f8d2da3d..655a976 100644
--- a/chrome/browser/extensions/api/webstore_widget_private/OWNERS
+++ b/chrome/browser/extensions/api/webstore_widget_private/OWNERS
@@ -3,5 +3,4 @@
 # chrome/browser/chromeos/file_manager/OWNERS
 hirono@chromium.org
 kinaba@chromium.org
-mtomasz@chromium.org
 yoshiki@chromium.org
diff --git a/chrome/browser/resources/chromeos/zip_archiver/OWNERS b/chrome/browser/resources/chromeos/zip_archiver/OWNERS
index 77f7614..191333e 100644
--- a/chrome/browser/resources/chromeos/zip_archiver/OWNERS
+++ b/chrome/browser/resources/chromeos/zip_archiver/OWNERS
@@ -1,2 +1 @@
 yawano@chromium.org
-mtomasz@chromium.org
diff --git a/chrome/common/extensions/api/OWNERS b/chrome/common/extensions/api/OWNERS
index dbad8fa0..1a183d1 100644
--- a/chrome/common/extensions/api/OWNERS
+++ b/chrome/common/extensions/api/OWNERS
@@ -15,6 +15,7 @@
 per-file automation*.idl=dmazzoni@chromium.org
 per-file automation*.idl=dtseng@chromium.org
 per-file automation*.idl=nektar@chromium.org
-per-file file_manager_private*.idl=mtomasz@chromium.org
+per-file file_manager_private*.idl=fukino@chromium.org
+per-file file_manager_private*.idl=yamaguchi@chromium.org
 
 # COMPONENT: Platform>Extensions>API
diff --git a/chrome/renderer/resources/extensions/OWNERS b/chrome/renderer/resources/extensions/OWNERS
index 6e983f13..1e03873f 100644
--- a/chrome/renderer/resources/extensions/OWNERS
+++ b/chrome/renderer/resources/extensions/OWNERS
@@ -6,7 +6,8 @@
 per-file automation_custom_bindings.js=dtseng@chromium.org
 per-file automation_custom_bindings.js=nektar@chromium.org
 per-file enterprise_platform_keys*=emaxx@chromium.org
-per-file file_manager_private_custom_bindings.js=mtomasz@chromium.org
+per-file file_manager_private_custom_bindings.js=fukino@chromium.org
+per-file file_manager_private_custom_bindings.js=yamaguchi@chromium.org
 per-file image_util.js=dewittj@chromium.org
 per-file media_galleries*.js=file://chrome/browser/media_galleries/OWNERS
 per-file media_router_bindings.js=file://chrome/browser/media/router/OWNERS
diff --git a/chrome/test/data/extensions/api_test/file_browser/OWNERS b/chrome/test/data/extensions/api_test/file_browser/OWNERS
index f17c9865..2eb77e1 100644
--- a/chrome/test/data/extensions/api_test/file_browser/OWNERS
+++ b/chrome/test/data/extensions/api_test/file_browser/OWNERS
@@ -1,4 +1,3 @@
 # This should match ui/file_manager/file_manager/OWNERS
 hirono@chromium.org
-mtomasz@chromium.org
 yoshiki@chromium.org
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index b7c03c1..9fa8e46c 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-10210.0.0
\ No newline at end of file
+10213.0.0
\ No newline at end of file
diff --git a/components/chrome_apps/webstore_widget/OWNERS b/components/chrome_apps/webstore_widget/OWNERS
index c0edc54..2537d91 100644
--- a/components/chrome_apps/webstore_widget/OWNERS
+++ b/components/chrome_apps/webstore_widget/OWNERS
@@ -1,5 +1,4 @@
 fukino@chromium.org
 hirono@chromium.org
-mtomasz@chromium.org
 tbarzic@chromium.org
 yoshiki@chromium.org
diff --git a/components/drive/OWNERS b/components/drive/OWNERS
index aec41e60..7ca29178 100644
--- a/components/drive/OWNERS
+++ b/components/drive/OWNERS
@@ -3,5 +3,4 @@
 hidehiko@chromium.org
 hirono@chromium.org
 kinaba@chromium.org
-mtomasz@chromium.org
 yoshiki@chromium.org
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 87988955..5b77db4 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1317,6 +1317,8 @@
     "renderer_host/media/audio_input_device_manager.h",
     "renderer_host/media/audio_input_renderer_host.cc",
     "renderer_host/media/audio_input_renderer_host.h",
+    "renderer_host/media/audio_input_stream_handle.cc",
+    "renderer_host/media/audio_input_stream_handle.h",
     "renderer_host/media/audio_input_sync_writer.cc",
     "renderer_host/media/audio_input_sync_writer.h",
     "renderer_host/media/audio_output_authorization_handler.cc",
@@ -1350,6 +1352,8 @@
     "renderer_host/media/media_stream_track_metrics_host.h",
     "renderer_host/media/media_stream_ui_proxy.cc",
     "renderer_host/media/media_stream_ui_proxy.h",
+    "renderer_host/media/render_frame_audio_input_stream_factory.cc",
+    "renderer_host/media/render_frame_audio_input_stream_factory.h",
     "renderer_host/media/render_frame_audio_output_stream_factory.cc",
     "renderer_host/media/render_frame_audio_output_stream_factory.h",
     "renderer_host/media/renderer_audio_output_stream_factory_context.h",
diff --git a/content/browser/renderer_host/media/audio_input_stream_handle.cc b/content/browser/renderer_host/media/audio_input_stream_handle.cc
new file mode 100644
index 0000000..202e20c
--- /dev/null
+++ b/content/browser/renderer_host/media/audio_input_stream_handle.cc
@@ -0,0 +1,71 @@
+// 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 "content/browser/renderer_host/media/audio_input_stream_handle.h"
+
+#include <utility>
+
+#include "base/bind_helpers.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+
+namespace content {
+
+namespace {
+
+media::mojom::AudioInputStreamClientPtr CreatePtrAndStoreRequest(
+    media::mojom::AudioInputStreamClientRequest* request_out) {
+  media::mojom::AudioInputStreamClientPtr ptr;
+  *request_out = mojo::MakeRequest(&ptr);
+  return ptr;
+}
+
+}  // namespace
+
+AudioInputStreamHandle::AudioInputStreamHandle(
+    mojom::RendererAudioInputStreamFactoryClientPtr client,
+    media::MojoAudioInputStream::CreateDelegateCallback
+        create_delegate_callback,
+    DeleterCallback deleter_callback)
+    : deleter_callback_(std::move(deleter_callback)),
+      client_(std::move(client)),
+      stream_ptr_(),
+      stream_client_request_(),
+      stream_(mojo::MakeRequest(&stream_ptr_),
+              CreatePtrAndStoreRequest(&stream_client_request_),
+              std::move(create_delegate_callback),
+              base::BindOnce(&AudioInputStreamHandle::OnCreated,
+                             base::Unretained(this)),
+              base::BindOnce(&AudioInputStreamHandle::CallDeleter,
+                             base::Unretained(this))) {
+  // Unretained is safe since |this| owns |stream_| and |client_|.
+  DCHECK(client_);
+  DCHECK(deleter_callback_);
+  client_.set_connection_error_handler(base::BindOnce(
+      &AudioInputStreamHandle::CallDeleter, base::Unretained(this)));
+}
+
+AudioInputStreamHandle::~AudioInputStreamHandle() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void AudioInputStreamHandle::OnCreated(
+    mojo::ScopedSharedBufferHandle shared_buffer,
+    mojo::ScopedHandle socket_descriptor,
+    bool initially_muted) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(client_);
+  DCHECK(deleter_callback_)
+      << "|deleter_callback_| was called, but |this| hasn't been destructed!";
+  client_->StreamCreated(
+      std::move(stream_ptr_), std::move(stream_client_request_),
+      std::move(shared_buffer), std::move(socket_descriptor), initially_muted);
+}
+
+void AudioInputStreamHandle::CallDeleter() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(deleter_callback_);
+  std::move(deleter_callback_).Run(this);
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/media/audio_input_stream_handle.h b/content/browser/renderer_host/media/audio_input_stream_handle.h
new file mode 100644
index 0000000..4f57adf
--- /dev/null
+++ b/content/browser/renderer_host/media/audio_input_stream_handle.h
@@ -0,0 +1,54 @@
+// 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 CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_INPUT_STREAM_HANDLE_H_
+#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_INPUT_STREAM_HANDLE_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/sequence_checker.h"
+#include "content/common/content_export.h"
+#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
+#include "media/mojo/interfaces/audio_input_stream.mojom.h"
+#include "media/mojo/services/mojo_audio_input_stream.h"
+#include "mojo/public/cpp/system/buffer.h"
+#include "mojo/public/cpp/system/handle.h"
+
+namespace content {
+
+// This class creates a MojoAudioInputStream and forwards the OnCreated event
+// to a RendererAudioInputStreamFactoryClient.
+class CONTENT_EXPORT AudioInputStreamHandle {
+ public:
+  using DeleterCallback = base::OnceCallback<void(AudioInputStreamHandle*)>;
+
+  // |deleter_callback| will be called when encountering an error, in which
+  // case |this| should be synchronously destructed by its owner.
+  AudioInputStreamHandle(mojom::RendererAudioInputStreamFactoryClientPtr client,
+                         media::MojoAudioInputStream::CreateDelegateCallback
+                             create_delegate_callback,
+                         DeleterCallback deleter_callback);
+
+  ~AudioInputStreamHandle();
+
+ private:
+  void OnCreated(mojo::ScopedSharedBufferHandle shared_buffer,
+                 mojo::ScopedHandle socket_descriptor,
+                 bool initially_muted);
+
+  void CallDeleter();
+
+  SEQUENCE_CHECKER(sequence_checker_);
+  DeleterCallback deleter_callback_;
+  mojom::RendererAudioInputStreamFactoryClientPtr client_;
+  media::mojom::AudioInputStreamPtr stream_ptr_;
+  media::mojom::AudioInputStreamClientRequest stream_client_request_;
+  media::MojoAudioInputStream stream_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioInputStreamHandle);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_INPUT_STREAM_HANDLE_H_
diff --git a/content/browser/renderer_host/media/audio_input_stream_handle_unittest.cc b/content/browser/renderer_host/media/audio_input_stream_handle_unittest.cc
new file mode 100644
index 0000000..1a95520
--- /dev/null
+++ b/content/browser/renderer_host/media/audio_input_stream_handle_unittest.cc
@@ -0,0 +1,173 @@
+// 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 "content/browser/renderer_host/media/audio_input_stream_handle.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/memory/shared_memory.h"
+#include "base/memory/shared_memory_handle.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/sync_socket.h"
+#include "base/test/mock_callback.h"
+#include "media/audio/audio_input_delegate.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+using testing::StrictMock;
+using testing::Mock;
+using testing::Test;
+
+class FakeAudioInputDelegate : public media::AudioInputDelegate {
+ public:
+  FakeAudioInputDelegate() {}
+
+  ~FakeAudioInputDelegate() override {}
+
+  int GetStreamId() override { return 0; };
+  void OnRecordStream() override{};
+  void OnSetVolume(double volume) override{};
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeAudioInputDelegate);
+};
+
+class MockRendererAudioInputStreamFactoryClient
+    : public mojom::RendererAudioInputStreamFactoryClient {
+ public:
+  MOCK_METHOD0(Created, void());
+
+  void StreamCreated(media::mojom::AudioInputStreamPtr input_stream,
+                     media::mojom::AudioInputStreamClientRequest client_request,
+                     mojo::ScopedSharedBufferHandle shared_buffer,
+                     mojo::ScopedHandle socket_descriptor,
+                     bool initially_muted) override {
+    input_stream_ = std::move(input_stream);
+    client_request_ = std::move(client_request);
+    Created();
+  }
+
+ private:
+  media::mojom::AudioInputStreamPtr input_stream_;
+  media::mojom::AudioInputStreamClientRequest client_request_;
+};
+
+using MockDeleter =
+    base::MockCallback<base::OnceCallback<void(AudioInputStreamHandle*)>>;
+
+// Creates a fake delegate and saves the provided event handler in
+// |event_handler_out|.
+std::unique_ptr<media::AudioInputDelegate> CreateFakeDelegate(
+    media::AudioInputDelegate::EventHandler** event_handler_out,
+    media::AudioInputDelegate::EventHandler* event_handler) {
+  *event_handler_out = event_handler;
+  return std::make_unique<FakeAudioInputDelegate>();
+}
+
+}  // namespace
+
+class AudioInputStreamHandleTest : public Test {
+ public:
+  AudioInputStreamHandleTest()
+      : client_binding_(&client_, mojo::MakeRequest(&client_ptr_)),
+        handle_(std::make_unique<AudioInputStreamHandle>(
+            std::move(client_ptr_),
+            base::BindOnce(&CreateFakeDelegate, &event_handler_),
+            deleter_.Get())),
+        local_(std::make_unique<base::CancelableSyncSocket>()),
+        remote_(std::make_unique<base::CancelableSyncSocket>()) {
+    // Wait for |event_handler| to be set.
+    base::RunLoop().RunUntilIdle();
+    EXPECT_TRUE(event_handler_);
+
+    const size_t kSize = 1234;
+    base::SharedMemoryCreateOptions shmem_options;
+    shmem_options.size = kSize;
+    shmem_options.share_read_only = true;
+    shared_memory_.Create(shmem_options);
+    shared_memory_.Map(kSize);
+    EXPECT_TRUE(
+        base::CancelableSyncSocket::CreatePair(local_.get(), remote_.get()));
+  }
+
+  void SendCreatedNotification() {
+    const int kIrrelevantStreamId = 0;
+    const bool kInitiallyMuted = false;
+    event_handler_->OnStreamCreated(kIrrelevantStreamId, &shared_memory_,
+                                    std::move(remote_), kInitiallyMuted);
+  }
+
+  MockRendererAudioInputStreamFactoryClient* client() { return &client_; }
+
+  void UnbindClientBinding() { client_binding_.Unbind(); }
+
+  void ExpectHandleWillCallDeleter() {
+    EXPECT_CALL(deleter_, Run(handle_.release()))
+        .WillOnce(testing::DeleteArg<0>());
+  }
+
+  // Note: Must call ExpectHandleWillCallDeleter() first.
+  void VerifyDeleterWasCalled() {
+    EXPECT_TRUE(Mock::VerifyAndClear(&deleter_));
+  }
+
+ private:
+  base::MessageLoop message_loop_;
+  StrictMock<MockRendererAudioInputStreamFactoryClient> client_;
+  mojom::RendererAudioInputStreamFactoryClientPtr client_ptr_;
+  mojo::Binding<mojom::RendererAudioInputStreamFactoryClient> client_binding_;
+  StrictMock<MockDeleter> deleter_;
+  media::AudioInputDelegate::EventHandler* event_handler_ = nullptr;
+  std::unique_ptr<AudioInputStreamHandle> handle_;
+
+  base::SharedMemory shared_memory_;
+  std::unique_ptr<base::CancelableSyncSocket> local_;
+  std::unique_ptr<base::CancelableSyncSocket> remote_;
+};
+
+TEST_F(AudioInputStreamHandleTest, CreateStream) {
+  EXPECT_CALL(*client(), Created());
+
+  SendCreatedNotification();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(Mock::VerifyAndClear(client()));
+}
+
+TEST_F(AudioInputStreamHandleTest,
+       DestructClientBeforeCreationFinishes_CancelsStreamCreation) {
+  ExpectHandleWillCallDeleter();
+
+  UnbindClientBinding();
+  base::RunLoop().RunUntilIdle();
+
+  VerifyDeleterWasCalled();
+}
+
+TEST_F(AudioInputStreamHandleTest,
+       CreateStreamAndDisconnectClient_DestroysStream) {
+  EXPECT_CALL(*client(), Created());
+
+  SendCreatedNotification();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(Mock::VerifyAndClear(client()));
+
+  ExpectHandleWillCallDeleter();
+
+  UnbindClientBinding();
+  base::RunLoop().RunUntilIdle();
+
+  VerifyDeleterWasCalled();
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc
new file mode 100644
index 0000000..531d94f
--- /dev/null
+++ b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc
@@ -0,0 +1,128 @@
+// 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 "content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h"
+
+#include <utility>
+
+#include "base/task_runner_util.h"
+#include "content/browser/media/media_internals.h"
+#include "content/browser/renderer_host/media/media_stream_manager.h"
+#include "media/base/audio_parameters.h"
+
+namespace content {
+
+// static
+std::unique_ptr<RenderFrameAudioInputStreamFactoryHandle,
+                BrowserThread::DeleteOnIOThread>
+RenderFrameAudioInputStreamFactoryHandle::CreateFactory(
+    RenderFrameAudioInputStreamFactory::CreateDelegateCallback
+        create_delegate_callback,
+    content::MediaStreamManager* media_stream_manager,
+    mojom::RendererAudioInputStreamFactoryRequest request) {
+  std::unique_ptr<RenderFrameAudioInputStreamFactoryHandle,
+                  BrowserThread::DeleteOnIOThread>
+      handle(new RenderFrameAudioInputStreamFactoryHandle(
+          std::move(create_delegate_callback), media_stream_manager));
+  // Unretained is safe since |*handle| must be posted to the IO thread prior to
+  // deletion.
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&RenderFrameAudioInputStreamFactoryHandle::Init,
+                     base::Unretained(handle.get()), std::move(request)));
+  return handle;
+}
+
+RenderFrameAudioInputStreamFactoryHandle::
+    ~RenderFrameAudioInputStreamFactoryHandle() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+}
+
+RenderFrameAudioInputStreamFactoryHandle::
+    RenderFrameAudioInputStreamFactoryHandle(
+        RenderFrameAudioInputStreamFactory::CreateDelegateCallback
+            create_delegate_callback,
+        MediaStreamManager* media_stream_manager)
+    : impl_(std::move(create_delegate_callback), media_stream_manager),
+      binding_(&impl_) {}
+
+void RenderFrameAudioInputStreamFactoryHandle::Init(
+    mojom::RendererAudioInputStreamFactoryRequest request) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  binding_.Bind(std::move(request));
+}
+
+RenderFrameAudioInputStreamFactory::RenderFrameAudioInputStreamFactory(
+    CreateDelegateCallback create_delegate_callback,
+    MediaStreamManager* media_stream_manager)
+    : create_delegate_callback_(std::move(create_delegate_callback)),
+      media_stream_manager_(media_stream_manager),
+      audio_log_(MediaInternals::GetInstance()->CreateAudioLog(
+          media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)),
+      weak_ptr_factory_(this) {
+  DCHECK(create_delegate_callback_);
+  // No thread-hostile state has been initialized yet, so we don't have to bind
+  // to this specific thread.
+}
+
+RenderFrameAudioInputStreamFactory::~RenderFrameAudioInputStreamFactory() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+}
+
+void RenderFrameAudioInputStreamFactory::CreateStream(
+    mojom::RendererAudioInputStreamFactoryClientPtr client,
+    int32_t session_id,
+    const media::AudioParameters& audio_params,
+    bool automatic_gain_control,
+    uint32_t shared_memory_count) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+#if defined(OS_CHROMEOS)
+  if (audio_params.channel_layout() ==
+      media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
+    media_stream_manager_->audio_input_device_manager()
+        ->RegisterKeyboardMicStream(base::BindOnce(
+            &RenderFrameAudioInputStreamFactory::DoCreateStream,
+            weak_ptr_factory_.GetWeakPtr(), std::move(client), session_id,
+            audio_params, automatic_gain_control, shared_memory_count));
+    return;
+  }
+#endif
+  DoCreateStream(std::move(client), session_id, audio_params,
+                 automatic_gain_control, shared_memory_count,
+                 AudioInputDeviceManager::KeyboardMicRegistration());
+}
+
+void RenderFrameAudioInputStreamFactory::DoCreateStream(
+    mojom::RendererAudioInputStreamFactoryClientPtr client,
+    int session_id,
+    const media::AudioParameters& audio_params,
+    bool automatic_gain_control,
+    uint32_t shared_memory_count,
+    AudioInputDeviceManager::KeyboardMicRegistration
+        keyboard_mic_registration) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  int stream_id = ++next_stream_id_;
+
+  // Unretained is safe since |this| owns |streams_|.
+  streams_.insert(std::make_unique<AudioInputStreamHandle>(
+      std::move(client),
+      base::BindOnce(
+          create_delegate_callback_,
+          base::Unretained(media_stream_manager_->audio_input_device_manager()),
+          audio_log_.get(), std::move(keyboard_mic_registration),
+          shared_memory_count, stream_id, session_id, automatic_gain_control,
+          audio_params),
+      base::BindOnce(&RenderFrameAudioInputStreamFactory::RemoveStream,
+                     weak_ptr_factory_.GetWeakPtr())));
+}
+
+void RenderFrameAudioInputStreamFactory::RemoveStream(
+    AudioInputStreamHandle* stream) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  streams_.erase(stream);
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h
new file mode 100644
index 0000000..2985ba2b
--- /dev/null
+++ b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h
@@ -0,0 +1,128 @@
+// 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 CONTENT_BROWSER_RENDERER_HOST_MEDIA_RENDER_FRAME_AUDIO_INPUT_STREAM_FACTORY_H_
+#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_RENDER_FRAME_AUDIO_INPUT_STREAM_FACTORY_H_
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/containers/flat_set.h"
+#include "base/containers/unique_ptr_comparator.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "build/build_config.h"
+#include "content/browser/renderer_host/media/audio_input_device_manager.h"
+#include "content/browser/renderer_host/media/audio_input_stream_handle.h"
+#include "content/common/content_export.h"
+#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
+#include "content/public/browser/browser_thread.h"
+#include "media/audio/audio_input_delegate.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace media {
+class AudioParameters;
+class AudioLog;
+}  // namespace media
+
+namespace content {
+
+class MediaStreamManager;
+
+// Handles a RendererAudioInputStreamFactory request for a render frame host,
+// using the provided RendererAudioInputStreamFactoryContext. This class may
+// be constructed on any thread, but must be used on the IO thread after that,
+// and also destructed on the IO thread.
+class CONTENT_EXPORT RenderFrameAudioInputStreamFactory
+    : public mojom::RendererAudioInputStreamFactory {
+ public:
+  using CreateDelegateCallback =
+      base::RepeatingCallback<std::unique_ptr<media::AudioInputDelegate>(
+          AudioInputDeviceManager* audio_input_device_manager,
+          media::AudioLog* audio_log,
+          AudioInputDeviceManager::KeyboardMicRegistration
+              keyboard_mic_registration,
+          uint32_t shared_memory_count,
+          int stream_id,
+          int session_id,
+          bool automatic_gain_control,
+          const media::AudioParameters& parameters,
+          media::AudioInputDelegate::EventHandler* event_handler)>;
+
+  RenderFrameAudioInputStreamFactory(
+      CreateDelegateCallback create_delegate_callback,
+      MediaStreamManager* media_stream_manager);
+
+  ~RenderFrameAudioInputStreamFactory() override;
+
+ private:
+  using InputStreamSet = base::flat_set<std::unique_ptr<AudioInputStreamHandle>,
+                                        base::UniquePtrComparator>;
+
+  // mojom::RendererAudioInputStreamFactory implementation.
+  void CreateStream(mojom::RendererAudioInputStreamFactoryClientPtr client,
+                    int32_t session_id,
+                    const media::AudioParameters& audio_params,
+                    bool automatic_gain_control,
+                    uint32_t shared_memory_count) override;
+
+  void DoCreateStream(mojom::RendererAudioInputStreamFactoryClientPtr client,
+                      int session_id,
+                      const media::AudioParameters& audio_params,
+                      bool automatic_gain_control,
+                      uint32_t shared_memory_count,
+                      AudioInputDeviceManager::KeyboardMicRegistration
+                          keyboard_mic_registration);
+
+  void RemoveStream(AudioInputStreamHandle* input_stream);
+
+  const CreateDelegateCallback create_delegate_callback_;
+  MediaStreamManager* media_stream_manager_;
+  const std::unique_ptr<media::AudioLog> audio_log_;
+
+  InputStreamSet streams_;
+  int next_stream_id_ = 0;
+
+  base::WeakPtrFactory<RenderFrameAudioInputStreamFactory> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderFrameAudioInputStreamFactory);
+};
+
+// This class is a convenient bundle of factory and binding.
+// It can be created on any thread, but should be destroyed on the IO thread
+// (hence the DeleteOnIOThread pointer).
+class CONTENT_EXPORT RenderFrameAudioInputStreamFactoryHandle {
+ public:
+  static std::unique_ptr<RenderFrameAudioInputStreamFactoryHandle,
+                         BrowserThread::DeleteOnIOThread>
+  CreateFactory(RenderFrameAudioInputStreamFactory::CreateDelegateCallback
+                    create_delegate_callback,
+                MediaStreamManager* media_stream_manager,
+                mojom::RendererAudioInputStreamFactoryRequest request);
+
+  ~RenderFrameAudioInputStreamFactoryHandle();
+
+ private:
+  RenderFrameAudioInputStreamFactoryHandle(
+      RenderFrameAudioInputStreamFactory::CreateDelegateCallback
+          create_delegate_callback,
+      MediaStreamManager* media_stream_manager);
+
+  void Init(mojom::RendererAudioInputStreamFactoryRequest request);
+
+  RenderFrameAudioInputStreamFactory impl_;
+  mojo::Binding<mojom::RendererAudioInputStreamFactory> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderFrameAudioInputStreamFactoryHandle);
+};
+
+using UniqueAudioInputStreamFactoryPtr =
+    std::unique_ptr<RenderFrameAudioInputStreamFactoryHandle,
+                    BrowserThread::DeleteOnIOThread>;
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_RENDER_FRAME_AUDIO_INPUT_STREAM_FACTORY_H_
diff --git a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
new file mode 100644
index 0000000..68b691f
--- /dev/null
+++ b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
@@ -0,0 +1,161 @@
+// 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 "content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h"
+
+#include <limits>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/memory/shared_memory.h"
+#include "base/memory/shared_memory_handle.h"
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "base/sync_socket.h"
+#include "content/browser/renderer_host/media/audio_input_device_manager.h"
+#include "content/browser/renderer_host/media/media_stream_manager.h"
+#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "media/audio/audio_system_impl.h"
+#include "media/audio/mock_audio_manager.h"
+#include "media/audio/test_audio_thread.h"
+#include "media/base/audio_parameters.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+using testing::Test;
+
+const size_t kShmemSize = 1234;
+const int kSessionId = 234;
+const bool kAGC = false;
+const uint32_t kSharedMemoryCount = 345;
+const int kSampleFrequency = 44100;
+const int kBitsPerSample = 16;
+const int kSamplesPerBuffer = kSampleFrequency / 100;
+const bool kInitiallyMuted = false;
+
+media::AudioParameters GetTestAudioParameters() {
+  return media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+                                media::CHANNEL_LAYOUT_MONO, kSampleFrequency,
+                                kBitsPerSample, kSamplesPerBuffer);
+}
+
+class FakeAudioInputDelegate : public media::AudioInputDelegate {
+ public:
+  FakeAudioInputDelegate() {}
+
+  ~FakeAudioInputDelegate() override {}
+
+  int GetStreamId() override { return 0; };
+  void OnRecordStream() override{};
+  void OnSetVolume(double volume) override{};
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeAudioInputDelegate);
+};
+
+class FakeAudioInputStreamClient : public media::mojom::AudioInputStreamClient {
+ public:
+  void OnMutedStateChanged(bool is_muted) override {}
+  void OnError() override {}
+};
+
+class MockRendererAudioInputStreamFactoryClient
+    : public mojom::RendererAudioInputStreamFactoryClient {
+ public:
+  MOCK_METHOD0(Created, void());
+
+  void StreamCreated(media::mojom::AudioInputStreamPtr input_stream,
+                     media::mojom::AudioInputStreamClientRequest client_request,
+                     mojo::ScopedSharedBufferHandle shared_buffer,
+                     mojo::ScopedHandle socket_descriptor,
+                     bool initially_muted) override {
+    Created();
+  }
+};
+
+// Creates a fake delegate and saves the provided event handler in
+// |event_handler_out|.
+std::unique_ptr<media::AudioInputDelegate> CreateFakeDelegate(
+    media::AudioInputDelegate::EventHandler** event_handler_out,
+    AudioInputDeviceManager* audio_input_device_manager,
+    media::AudioLog* audio_log,
+    AudioInputDeviceManager::KeyboardMicRegistration keyboard_mic_registration,
+    uint32_t shared_memory_count,
+    int stream_id,
+    int session_id,
+    bool automatic_gain_control,
+    const media::AudioParameters& parameters,
+    media::AudioInputDelegate::EventHandler* event_handler) {
+  *event_handler_out = event_handler;
+  return std::make_unique<FakeAudioInputDelegate>();
+}
+
+}  // namespace
+
+class RenderFrameAudioInputStreamFactoryTest : public testing::Test {
+ public:
+  RenderFrameAudioInputStreamFactoryTest()
+      : thread_bundle_(base::in_place),
+        audio_manager_(std::make_unique<media::TestAudioThread>()),
+        audio_system_(&audio_manager_),
+        media_stream_manager_(&audio_system_, audio_manager_.GetTaskRunner()),
+        client_binding_(&client_, mojo::MakeRequest(&client_ptr_)),
+        factory_handle_(RenderFrameAudioInputStreamFactoryHandle::CreateFactory(
+            base::BindRepeating(&CreateFakeDelegate, &event_handler_),
+            &media_stream_manager_,
+            mojo::MakeRequest(&factory_ptr_))) {}
+
+  ~RenderFrameAudioInputStreamFactoryTest() override {
+    audio_manager_.Shutdown();
+    thread_bundle_.reset();
+  }
+
+  base::Optional<TestBrowserThreadBundle> thread_bundle_;
+  media::MockAudioManager audio_manager_;
+  media::AudioSystemImpl audio_system_;
+  MediaStreamManager media_stream_manager_;
+  mojom::RendererAudioInputStreamFactoryPtr factory_ptr_;
+  media::mojom::AudioInputStreamPtr stream_ptr_;
+  MockRendererAudioInputStreamFactoryClient client_;
+  mojom::RendererAudioInputStreamFactoryClientPtr client_ptr_;
+  media::AudioInputDelegate::EventHandler* event_handler_ = nullptr;
+  mojo::Binding<mojom::RendererAudioInputStreamFactoryClient> client_binding_;
+  UniqueAudioInputStreamFactoryPtr factory_handle_;
+};
+
+TEST_F(RenderFrameAudioInputStreamFactoryTest, CreateStream) {
+  factory_ptr_->CreateStream(std::move(client_ptr_), kSessionId,
+                             GetTestAudioParameters(), kAGC,
+                             kSharedMemoryCount);
+
+  // Wait for delegate to be created and |event_handler| set.
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(event_handler_);
+  base::SharedMemoryCreateOptions shmem_options;
+  shmem_options.size = kShmemSize;
+  shmem_options.share_read_only = true;
+  base::SharedMemory shared_memory;
+  shared_memory.Create(shmem_options);
+  shared_memory.Map(kShmemSize);
+  auto local = std::make_unique<base::CancelableSyncSocket>();
+  auto remote = std::make_unique<base::CancelableSyncSocket>();
+  ASSERT_TRUE(
+      base::CancelableSyncSocket::CreatePair(local.get(), remote.get()));
+  event_handler_->OnStreamCreated(/*stream_id, irrelevant*/ 0, &shared_memory,
+                                  std::move(remote), kInitiallyMuted);
+
+  EXPECT_CALL(client_, Created());
+  base::RunLoop().RunUntilIdle();
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
index 7135214..52d36b2 100644
--- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
+++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
@@ -75,22 +75,12 @@
 
 void RenderFrameAudioOutputStreamFactory::RequestDeviceAuthorization(
     media::mojom::AudioOutputStreamProviderRequest stream_provider_request,
-    int64_t session_id,
+    int32_t session_id,
     const std::string& device_id,
     RequestDeviceAuthorizationCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   const base::TimeTicks auth_start_time = base::TimeTicks::Now();
 
-  if (!base::IsValueInRangeForNumericType<int>(session_id)) {
-    mojo::ReportBadMessage("session_id is not in integer range");
-    // Note: We must call the callback even though we are killing the renderer.
-    // This is mandated by mojo.
-    std::move(callback).Run(
-        media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
-        media::AudioParameters::UnavailableDeviceParams(), std::string());
-    return;
-  }
-
   context_->RequestDeviceAuthorization(
       render_frame_id_, session_id, device_id,
       base::BindOnce(
@@ -143,11 +133,7 @@
     media::mojom::AudioOutputStreamProvider* stream_provider) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  base::EraseIf(
-      stream_providers_,
-      [stream_provider](
-          const std::unique_ptr<media::mojom::AudioOutputStreamProvider>&
-              other) { return other.get() == stream_provider; });
+  stream_providers_.erase(stream_provider);
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h
index 0f75bdc7..4f598ad 100644
--- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h
+++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/containers/flat_set.h"
+#include "base/containers/unique_ptr_comparator.h"
 #include "base/threading/thread_checker.h"
 #include "content/common/content_export.h"
 #include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
@@ -33,12 +34,13 @@
 
  private:
   using OutputStreamProviderSet =
-      base::flat_set<std::unique_ptr<media::mojom::AudioOutputStreamProvider>>;
+      base::flat_set<std::unique_ptr<media::mojom::AudioOutputStreamProvider>,
+                     base::UniquePtrComparator>;
 
   // mojom::RendererAudioOutputStreamFactory implementation.
   void RequestDeviceAuthorization(
       media::mojom::AudioOutputStreamProviderRequest stream_provider,
-      int64_t session_id,
+      int32_t session_id,
       const std::string& device_id,
       RequestDeviceAuthorizationCallback callback) override;
 
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
index 6603b1c..f6940e2 100644
--- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
+++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
@@ -19,7 +19,6 @@
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "media/base/audio_parameters.h"
-#include "mojo/edk/embedder/embedder.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -343,38 +342,4 @@
   EXPECT_TRUE(delegate_is_destructed);
 }
 
-TEST(RenderFrameAudioOutputStreamFactoryTest, OutOfRangeSessionId_BadMessage) {
-  // This test checks that we get a bad message if session_id is too large
-  // to fit in an integer. This ensures that we don't overflow when casting the
-  // int64_t to an int
-  if (sizeof(int) >= sizeof(int64_t)) {
-    // In this case, any int64_t would fit in an int, and the case we are
-    // checking for is impossible.
-    return;
-  }
-
-  bool got_bad_message = false;
-  mojo::edk::SetDefaultProcessErrorCallback(
-      base::Bind([](bool* got_bad_message,
-                    const std::string& s) { *got_bad_message = true; },
-                 &got_bad_message));
-
-  TestBrowserThreadBundle thread_bundle;
-
-  AudioOutputStreamProviderPtr output_provider;
-  auto factory_context = std::make_unique<MockContext>(true);
-  auto factory_ptr = factory_context->CreateFactory();
-
-  int64_t session_id = std::numeric_limits<int>::max();
-  ++session_id;
-
-  EXPECT_FALSE(got_bad_message);
-  factory_ptr->RequestDeviceAuthorization(
-      mojo::MakeRequest(&output_provider), session_id, "default",
-      base::BindOnce([](media::OutputDeviceStatus,
-                        const media::AudioParameters&, const std::string&) {}));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(got_bad_message);
-}
-
 }  // namespace content
diff --git a/content/browser/webauth/cbor/cbor_reader.cc b/content/browser/webauth/cbor/cbor_reader.cc
index 893a4e7..e61565c 100644
--- a/content/browser/webauth/cbor/cbor_reader.cc
+++ b/content/browser/webauth/cbor/cbor_reader.cc
@@ -231,7 +231,7 @@
 }
 
 bool CBORReader::HasValidUTF8Format(const std::string& string_data) {
-  if (!base::IsStringUTF8(string_data.data())) {
+  if (!base::IsStringUTF8(string_data)) {
     error_code_ = DecoderError::INVALID_UTF8;
     return false;
   }
diff --git a/content/browser/webauth/cbor/cbor_reader_unittest.cc b/content/browser/webauth/cbor/cbor_reader_unittest.cc
index 0df2d1c..fe3a99f 100644
--- a/content/browser/webauth/cbor/cbor_reader_unittest.cc
+++ b/content/browser/webauth/cbor/cbor_reader_unittest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "content/browser/webauth/cbor/cbor_reader.h"
-#include "base/strings/stringprintf.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -112,8 +111,7 @@
 
   for (const StringTestCase& test_case : kStringTestCases) {
     testing::Message scope_message;
-    scope_message << "testing string value : "
-                  << base::StringPrintf("%s", test_case.value.data());
+    scope_message << "testing string value : " << test_case.value;
     SCOPED_TRACE(scope_message);
 
     base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
@@ -123,6 +121,50 @@
   }
 }
 
+TEST(CBORReaderTest, TestReadStringWithNUL) {
+  static const struct {
+    const std::string value;
+    const std::vector<uint8_t> cbor_data;
+  } kStringTestCases[] = {
+      {std::string("string_without_nul"),
+       {0x72, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x5F, 0x77, 0x69, 0x74, 0x68,
+        0x6F, 0x75, 0x74, 0x5F, 0x6E, 0x75, 0x6C}},
+      {std::string("nul_terminated_string\0", 22),
+       {0x76, 0x6E, 0x75, 0x6C, 0x5F, 0x74, 0x65, 0x72, 0x6D, 0x69, 0x6E, 0x61,
+        0x74, 0x65, 0x64, 0x5F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x00}},
+      {std::string("embedded\0nul", 12),
+       {0x6C, 0x65, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x00, 0x6E, 0x75,
+        0x6C}},
+      {std::string("trailing_nuls\0\0", 15),
+       {0x6F, 0x74, 0x72, 0x61, 0x69, 0x6C, 0x69, 0x6E, 0x67, 0x5F, 0x6E, 0x75,
+        0x6C, 0x73, 0x00, 0x00}},
+  };
+
+  for (const auto& test_case : kStringTestCases) {
+    SCOPED_TRACE(testing::Message()
+                 << "testing string with nul bytes :" << test_case.value);
+
+    base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+    ASSERT_TRUE(cbor.has_value());
+    ASSERT_EQ(cbor.value().type(), CBORValue::Type::STRING);
+    EXPECT_EQ(cbor.value().GetString(), test_case.value);
+  }
+}
+
+TEST(CBORReaderTest, TestReadStringWithInvalidByteSequenceAfterNUL) {
+  // UTF-8 validation should not stop at the first NUL character in the string.
+  // That is, a string with an invalid byte sequence should fail UTF-8
+  // validation even if the invalid character is located after one or more NUL
+  // characters. Here, 0xA6 is an unexpected continuation byte.
+  static const std::vector<uint8_t> string_with_invalid_continuation_byte = {
+      0x63, 0x00, 0x00, 0xA6};
+  CBORReader::DecoderError error_code;
+  base::Optional<CBORValue> cbor =
+      CBORReader::Read(string_with_invalid_continuation_byte, &error_code);
+  EXPECT_FALSE(cbor.has_value());
+  EXPECT_EQ(error_code, CBORReader::DecoderError::INVALID_UTF8);
+}
+
 TEST(CBORReaderTest, TestReadArray) {
   static const std::vector<uint8_t> kArrayTestCaseCbor = {
       // clang-format off
diff --git a/content/browser/webauth/cbor/cbor_values.h b/content/browser/webauth/cbor/cbor_values.h
index 3e993d90..83bbd49 100644
--- a/content/browser/webauth/cbor/cbor_values.h
+++ b/content/browser/webauth/cbor/cbor_values.h
@@ -109,6 +109,7 @@
   // These will all fatally assert if the type doesn't match.
   uint64_t GetUnsigned() const;
   const BinaryValue& GetBytestring() const;
+  // Returned string may contain NUL characters.
   const std::string& GetString() const;
   const ArrayValue& GetArray() const;
   const MapValue& GetMap() const;
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 44b4789..bd8ad82 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -557,6 +557,7 @@
     "leveldb_wrapper.mojom",
     "manifest_observer.mojom",
     "media/media_stream.mojom",
+    "media/renderer_audio_input_stream_factory.mojom",
     "media/renderer_audio_output_stream_factory.mojom",
     "memory_coordinator.mojom",
     "native_types.mojom",
diff --git a/content/common/media/renderer_audio_input_stream_factory.mojom b/content/common/media/renderer_audio_input_stream_factory.mojom
new file mode 100644
index 0000000..f74174a4
--- /dev/null
+++ b/content/common/media/renderer_audio_input_stream_factory.mojom
@@ -0,0 +1,36 @@
+// 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.
+
+module content.mojom;
+
+import "media/mojo/interfaces/audio_input_stream.mojom";
+import "media/mojo/interfaces/audio_parameters.mojom";
+import "media/mojo/interfaces/media_types.mojom";
+
+// This interface is used by the renderer to ask the browser to create input
+// streams. The renderer supplies the desired audio parameters, and a client
+// to send the stream to when it's ready. The lifetime of the stream is limited
+// by the lifetime of the client.
+interface RendererAudioInputStreamFactory {
+  CreateStream(
+      RendererAudioInputStreamFactoryClient client,
+      int32 session_id,
+      media.mojom.AudioParameters params,
+      bool automatic_gain_control,
+      uint32 shared_memory_count);
+};
+
+interface RendererAudioInputStreamFactoryClient {
+  // Called when a stream has been created. Will only be called once for every
+  // CreateStream call.
+  // TODO(crbug.com/787806): There are plans to allow this function to be called
+  // serveral times in the future. If the stream is terminated e.g. due to the
+  // process hosting it crashing, this function should be called again with a
+  // fresh stream.
+  StreamCreated(
+      media.mojom.AudioInputStream stream,
+      media.mojom.AudioInputStreamClient& client_request,
+      handle<shared_buffer> shared_buffer, handle socket_descriptor,
+      bool initially_muted);
+};
diff --git a/content/common/media/renderer_audio_output_stream_factory.mojom b/content/common/media/renderer_audio_output_stream_factory.mojom
index d099278..71195456 100644
--- a/content/common/media/renderer_audio_output_stream_factory.mojom
+++ b/content/common/media/renderer_audio_output_stream_factory.mojom
@@ -17,7 +17,7 @@
   // (in case of an error).
   RequestDeviceAuthorization(
       media.mojom.AudioOutputStreamProvider& stream_provider_request,
-      int64 session_id,
+      int32 session_id,
       string device_id) =>
       (media.mojom.OutputDeviceStatus state,
        media.mojom.AudioParameters output_params,
diff --git a/content/renderer/media/audio_ipc_factory_unittest.cc b/content/renderer/media/audio_ipc_factory_unittest.cc
index 88b1773..a8caa5c 100644
--- a/content/renderer/media/audio_ipc_factory_unittest.cc
+++ b/content/renderer/media/audio_ipc_factory_unittest.cc
@@ -41,7 +41,7 @@
 
   void RequestDeviceAuthorization(
       media::mojom::AudioOutputStreamProviderRequest stream_provider,
-      int64_t session_id,
+      int32_t session_id,
       const std::string& device_id,
       RequestDeviceAuthorizationCallback callback) override {
     std::move(callback).Run(
diff --git a/content/renderer/media/mojo_audio_output_ipc.cc b/content/renderer/media/mojo_audio_output_ipc.cc
index 7013306..13eb0d09 100644
--- a/content/renderer/media/mojo_audio_output_ipc.cc
+++ b/content/renderer/media/mojo_audio_output_ipc.cc
@@ -176,6 +176,8 @@
     return false;
   }
 
+  static_assert(sizeof(int) == sizeof(int32_t),
+                "sizeof(int) == sizeof(int32_t)");
   factory->RequestDeviceAuthorization(MakeProviderRequest(), session_id,
                                       device_id, std::move(callback));
   return true;
diff --git a/content/renderer/media/mojo_audio_output_ipc_unittest.cc b/content/renderer/media/mojo_audio_output_ipc_unittest.cc
index c5624ace..6e7d20d 100644
--- a/content/renderer/media/mojo_audio_output_ipc_unittest.cc
+++ b/content/renderer/media/mojo_audio_output_ipc_unittest.cc
@@ -98,7 +98,7 @@
 
   void RequestDeviceAuthorization(
       media::mojom::AudioOutputStreamProviderRequest stream_provider_request,
-      int64_t session_id,
+      int32_t session_id,
       const std::string& device_id,
       RequestDeviceAuthorizationCallback callback) override {
     EXPECT_EQ(session_id, expected_session_id_);
@@ -119,7 +119,7 @@
   }
 
   void PrepareProviderForAuthorization(
-      int64_t session_id,
+      int32_t session_id,
       const std::string& device_id,
       std::unique_ptr<TestStreamProvider> provider) {
     EXPECT_FALSE(expect_request_);
@@ -130,7 +130,7 @@
     std::swap(provider_, provider);
   }
 
-  void RefuseNextRequest(int64_t session_id, const std::string& device_id) {
+  void RefuseNextRequest(int32_t session_id, const std::string& device_id) {
     EXPECT_FALSE(expect_request_);
     expect_request_ = true;
     expected_session_id_ = session_id;
@@ -158,7 +158,7 @@
   mojom::RendererAudioOutputStreamFactory* get() { return this_proxy_.get(); }
 
   bool expect_request_;
-  int64_t expected_session_id_;
+  int32_t expected_session_id_;
   std::string expected_device_id_;
 
   mojom::RendererAudioOutputStreamFactoryPtr this_proxy_;
diff --git a/content/shell/test_runner/pixel_dump.cc b/content/shell/test_runner/pixel_dump.cc
index bf55f681..837ce15 100644
--- a/content/shell/test_runner/pixel_dump.cc
+++ b/content/shell/test_runner/pixel_dump.cc
@@ -153,7 +153,7 @@
                      base::OnceCallback<void(const SkBitmap&)> callback) {
   DCHECK(web_frame);
   DCHECK(!callback.is_null());
-  web_frame->GetTaskRunner(blink::TaskType::kUnthrottled)
+  web_frame->GetTaskRunner(blink::TaskType::kInternalTest)
       ->PostTask(FROM_HERE, base::BindOnce(&CapturePixelsForPrinting,
                                            base::Unretained(web_frame),
                                            base::Passed(std::move(callback))));
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index a170958..a3991b0 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1368,6 +1368,7 @@
     "../browser/renderer_host/media/audio_input_delegate_impl_unittest.cc",
     "../browser/renderer_host/media/audio_input_device_manager_unittest.cc",
     "../browser/renderer_host/media/audio_input_renderer_host_unittest.cc",
+    "../browser/renderer_host/media/audio_input_stream_handle_unittest.cc",
     "../browser/renderer_host/media/audio_input_sync_writer_unittest.cc",
     "../browser/renderer_host/media/audio_output_authorization_handler_unittest.cc",
     "../browser/renderer_host/media/audio_output_delegate_impl_unittest.cc",
@@ -1384,6 +1385,7 @@
     "../browser/renderer_host/media/media_stream_ui_proxy_unittest.cc",
     "../browser/renderer_host/media/mock_video_capture_provider.cc",
     "../browser/renderer_host/media/mock_video_capture_provider.h",
+    "../browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc",
     "../browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc",
     "../browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc",
     "../browser/renderer_host/media/service_video_capture_provider_unittest.cc",
diff --git a/extensions/browser/api/file_system/OWNERS b/extensions/browser/api/file_system/OWNERS
index ac81da7..64f6677 100644
--- a/extensions/browser/api/file_system/OWNERS
+++ b/extensions/browser/api/file_system/OWNERS
@@ -1,3 +1,2 @@
 benwells@chromium.org
-mtomasz@chromium.org
 sammc@chromium.org
diff --git a/media/capture/video/chromeos/camera_device_context.cc b/media/capture/video/chromeos/camera_device_context.cc
index 15cb775..8a8e3d6 100644
--- a/media/capture/video/chromeos/camera_device_context.cc
+++ b/media/capture/video/chromeos/camera_device_context.cc
@@ -8,7 +8,10 @@
 
 CameraDeviceContext::CameraDeviceContext(
     std::unique_ptr<VideoCaptureDevice::Client> client)
-    : state_(State::kStopped), rotation_(0), client_(std::move(client)) {
+    : state_(State::kStopped),
+      sensor_orientation_(0),
+      screen_rotation_(0),
+      client_(std::move(client)) {
   DCHECK(client_);
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
@@ -45,14 +48,23 @@
     const VideoCaptureFormat& frame_format,
     base::TimeTicks reference_time,
     base::TimeDelta timestamp) {
-  client_->OnIncomingCapturedData(data, length, frame_format, rotation_,
+  int total_rotation = (sensor_orientation_ + screen_rotation_) % 360;
+  client_->OnIncomingCapturedData(data, length, frame_format, total_rotation,
                                   reference_time, timestamp);
 }
 
-void CameraDeviceContext::SetRotation(int rotation) {
+void CameraDeviceContext::SetSensorOrientation(int sensor_orientation) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(rotation >= 0 && rotation < 360 && rotation % 90 == 0);
-  rotation_ = rotation;
+  DCHECK(sensor_orientation >= 0 && sensor_orientation < 360 &&
+         sensor_orientation % 90 == 0);
+  sensor_orientation_ = sensor_orientation;
+}
+
+void CameraDeviceContext::SetScreenRotation(int screen_rotation) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(screen_rotation >= 0 && screen_rotation < 360 &&
+         screen_rotation % 90 == 0);
+  screen_rotation_ = screen_rotation;
 }
 
 }  // namespace media
diff --git a/media/capture/video/chromeos/camera_device_context.h b/media/capture/video/chromeos/camera_device_context.h
index 33f950d..5b537284 100644
--- a/media/capture/video/chromeos/camera_device_context.h
+++ b/media/capture/video/chromeos/camera_device_context.h
@@ -112,7 +112,9 @@
                           base::TimeTicks reference_time,
                           base::TimeDelta timestamp);
 
-  void SetRotation(int rotation);
+  void SetSensorOrientation(int sensor_orientation);
+
+  void SetScreenRotation(int screen_rotation);
 
  private:
   friend class StreamBufferManagerTest;
@@ -122,8 +124,14 @@
   // The state the CameraDeviceDelegate currently is in.
   State state_;
 
-  // Clockwise rotation in degrees. This value should be 0, 90, 180, or 270.
-  int rotation_;
+  // Clockwise angle through which the output image needs to be rotated to be
+  // upright on the device screen in its native orientation.  This value should
+  // be 0, 90, 180, or 270.
+  int sensor_orientation_;
+
+  // Clockwise screen rotation in degrees. This value should be 0, 90, 180, or
+  // 270.
+  int screen_rotation_;
 
   std::unique_ptr<VideoCaptureDevice::Client> client_;
 
diff --git a/media/capture/video/chromeos/camera_device_delegate.cc b/media/capture/video/chromeos/camera_device_delegate.cc
index 68550c9..714cf5e 100644
--- a/media/capture/video/chromeos/camera_device_delegate.cc
+++ b/media/capture/video/chromeos/camera_device_delegate.cc
@@ -136,7 +136,7 @@
 void CameraDeviceDelegate::SetRotation(int rotation) {
   DCHECK(ipc_task_runner_->BelongsToCurrentThread());
   DCHECK(rotation >= 0 && rotation < 360 && rotation % 90 == 0);
-  device_context_->SetRotation(rotation);
+  device_context_->SetScreenRotation(rotation);
 }
 
 base::WeakPtr<CameraDeviceDelegate> CameraDeviceDelegate::GetWeakPtr() {
@@ -203,6 +203,20 @@
     return;
   }
   static_metadata_ = std::move(camera_info->static_camera_characteristics);
+
+  const arc::mojom::CameraMetadataEntryPtr* sensor_orientation =
+      GetMetadataEntry(
+          static_metadata_,
+          arc::mojom::CameraMetadataTag::ANDROID_SENSOR_ORIENTATION);
+  if (sensor_orientation) {
+    device_context_->SetSensorOrientation(
+        *reinterpret_cast<int32_t*>((*sensor_orientation)->data.data()));
+  } else {
+    device_context_->SetErrorState(
+        FROM_HERE, "Camera is missing required sensor orientation info");
+    return;
+  }
+
   // |device_ops_| is bound after the MakeRequest call.
   arc::mojom::Camera3DeviceOpsRequest device_ops_request =
       mojo::MakeRequest(&device_ops_);
diff --git a/media/capture/video/chromeos/camera_device_delegate_unittest.cc b/media/capture/video/chromeos/camera_device_delegate_unittest.cc
index 1cc27e5c..2c9da84 100644
--- a/media/capture/video/chromeos/camera_device_delegate_unittest.cc
+++ b/media/capture/video/chromeos/camera_device_delegate_unittest.cc
@@ -154,6 +154,16 @@
     arc::mojom::CameraInfoPtr camera_info = arc::mojom::CameraInfo::New();
     arc::mojom::CameraMetadataPtr static_metadata =
         arc::mojom::CameraMetadata::New();
+    arc::mojom::CameraMetadataEntryPtr entry =
+        arc::mojom::CameraMetadataEntry::New();
+    entry->index = 0;
+    entry->tag = arc::mojom::CameraMetadataTag::ANDROID_SENSOR_ORIENTATION;
+    entry->type = arc::mojom::EntryType::TYPE_INT32;
+    entry->count = 1;
+    entry->data = std::vector<uint8_t>(4, 0);
+    static_metadata->entries =
+        std::vector<arc::mojom::CameraMetadataEntryPtr>();
+    static_metadata->entries->push_back(std::move(entry));
     switch (camera_id) {
       case 0:
         camera_info->facing = arc::mojom::CameraFacing::CAMERA_FACING_FRONT;
diff --git a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
index 17929aa..b0508f0 100644
--- a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
@@ -244,7 +244,7 @@
                                         parent_frame_task_runners_.Get());
     worker_thread_->WaitForInit();
     worker_loading_task_runner_ =
-        worker_thread_->GetTaskRunner(TaskType::kUnspecedLoading);
+        worker_thread_->GetTaskRunner(TaskType::kInternalTest);
   }
 
   void OnServeRequests() override { testing::RunPendingTasks(); }
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderTest.cpp b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderTest.cpp
index 00db69e..90f4cd0 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderTest.cpp
@@ -193,8 +193,8 @@
   global_scope_->SetModuleResponsesMapProxyForTesting(
       WorkletModuleResponsesMapProxy::Create(
           new WorkletModuleResponsesMap(modulator_->Fetcher()),
-          GetDocument().GetTaskRunner(TaskType::kUnspecedLoading),
-          global_scope_->GetTaskRunner(TaskType::kUnspecedLoading)));
+          GetDocument().GetTaskRunner(TaskType::kInternalTest),
+          global_scope_->GetTaskRunner(TaskType::kInternalTest)));
 }
 
 void ModuleScriptLoaderTest::TestFetchDataURL(
diff --git a/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp b/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp
index 10d5781..c77d173 100644
--- a/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp
+++ b/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp
@@ -49,7 +49,7 @@
     EXPECT_TRUE(IsCurrentThread());
     GlobalScope()->CountFeature(feature);
     GetParentFrameTaskRunners()
-        ->Get(TaskType::kUnspecedTimer)
+        ->Get(TaskType::kInternalTest)
         ->PostTask(BLINK_FROM_HERE, CrossThreadBind(&testing::ExitRunLoop));
   }
 
@@ -64,17 +64,17 @@
     EXPECT_TRUE(console_message.Contains("deprecated"));
 
     GetParentFrameTaskRunners()
-        ->Get(TaskType::kUnspecedTimer)
+        ->Get(TaskType::kInternalTest)
         ->PostTask(BLINK_FROM_HERE, CrossThreadBind(&testing::ExitRunLoop));
   }
 
   void TestTaskRunner() {
     EXPECT_TRUE(IsCurrentThread());
     scoped_refptr<WebTaskRunner> task_runner =
-        GlobalScope()->GetTaskRunner(TaskType::kUnspecedTimer);
+        GlobalScope()->GetTaskRunner(TaskType::kInternalTest);
     EXPECT_TRUE(task_runner->RunsTasksInCurrentSequence());
     GetParentFrameTaskRunners()
-        ->Get(TaskType::kUnspecedTimer)
+        ->Get(TaskType::kInternalTest)
         ->PostTask(BLINK_FROM_HERE, CrossThreadBind(&testing::ExitRunLoop));
   }
 };
@@ -223,7 +223,7 @@
   // on the Document.
   EXPECT_FALSE(UseCounter::IsCounted(GetDocument(), kFeature1));
   GetWorkerThread()
-      ->GetTaskRunner(TaskType::kUnspecedTimer)
+      ->GetTaskRunner(TaskType::kInternalTest)
       ->PostTask(
           BLINK_FROM_HERE,
           CrossThreadBind(&DedicatedWorkerThreadForTest::CountFeature,
@@ -234,7 +234,7 @@
   // API use should be reported to the Document only one time. See comments in
   // DedicatedWorkerObjectProxyForTest::CountFeature.
   GetWorkerThread()
-      ->GetTaskRunner(TaskType::kUnspecedTimer)
+      ->GetTaskRunner(TaskType::kInternalTest)
       ->PostTask(
           BLINK_FROM_HERE,
           CrossThreadBind(&DedicatedWorkerThreadForTest::CountFeature,
@@ -248,7 +248,7 @@
   // UseCounter on the Document.
   EXPECT_FALSE(UseCounter::IsCounted(GetDocument(), kFeature2));
   GetWorkerThread()
-      ->GetTaskRunner(TaskType::kUnspecedTimer)
+      ->GetTaskRunner(TaskType::kInternalTest)
       ->PostTask(
           BLINK_FROM_HERE,
           CrossThreadBind(&DedicatedWorkerThreadForTest::CountDeprecation,
@@ -259,7 +259,7 @@
   // API use should be reported to the Document only one time. See comments in
   // DedicatedWorkerObjectProxyForTest::CountDeprecation.
   GetWorkerThread()
-      ->GetTaskRunner(TaskType::kUnspecedTimer)
+      ->GetTaskRunner(TaskType::kInternalTest)
       ->PostTask(
           BLINK_FROM_HERE,
           CrossThreadBind(&DedicatedWorkerThreadForTest::CountDeprecation,
@@ -272,7 +272,7 @@
   WorkerMessagingProxy()->StartWithSourceCode(source_code);
 
   GetWorkerThread()
-      ->GetTaskRunner(TaskType::kUnspecedTimer)
+      ->GetTaskRunner(TaskType::kInternalTest)
       ->PostTask(BLINK_FROM_HERE,
                  CrossThreadBind(&DedicatedWorkerThreadForTest::TestTaskRunner,
                                  CrossThreadUnretained(GetWorkerThread())));
diff --git a/third_party/WebKit/Source/core/workers/MainThreadWorkletTest.cpp b/third_party/WebKit/Source/core/workers/MainThreadWorkletTest.cpp
index 3cf05a4..afc53c00 100644
--- a/third_party/WebKit/Source/core/workers/MainThreadWorkletTest.cpp
+++ b/third_party/WebKit/Source/core/workers/MainThreadWorkletTest.cpp
@@ -135,7 +135,7 @@
 
 TEST_F(MainThreadWorkletTest, TaskRunner) {
   scoped_refptr<WebTaskRunner> task_runner =
-      global_scope_->GetTaskRunner(TaskType::kUnthrottled);
+      global_scope_->GetTaskRunner(TaskType::kInternalTest);
   EXPECT_TRUE(task_runner->RunsTasksInCurrentSequence());
 }
 
diff --git a/third_party/WebKit/Source/core/workers/ParentFrameTaskRunners.cpp b/third_party/WebKit/Source/core/workers/ParentFrameTaskRunners.cpp
index c43f4a7..048712f 100644
--- a/third_party/WebKit/Source/core/workers/ParentFrameTaskRunners.cpp
+++ b/third_party/WebKit/Source/core/workers/ParentFrameTaskRunners.cpp
@@ -27,10 +27,10 @@
 ParentFrameTaskRunners::ParentFrameTaskRunners(LocalFrame* frame)
     : ContextLifecycleObserver(frame ? frame->GetDocument() : nullptr) {
   // For now we only support very limited task types.
-  for (auto type :
-       {TaskType::kUnspecedTimer, TaskType::kUnspecedLoading,
-        TaskType::kNetworking, TaskType::kPostedMessage,
-        TaskType::kCanvasBlobSerialization, TaskType::kUnthrottled}) {
+  for (auto type : {TaskType::kUnspecedTimer, TaskType::kUnspecedLoading,
+                    TaskType::kNetworking, TaskType::kPostedMessage,
+                    TaskType::kCanvasBlobSerialization, TaskType::kUnthrottled,
+                    TaskType::kInternalTest}) {
     auto task_runner =
         frame ? frame->GetTaskRunner(type)
               : Platform::Current()->MainThread()->GetWebTaskRunner();
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletTest.cpp b/third_party/WebKit/Source/core/workers/ThreadedWorkletTest.cpp
index d983e695..60e5902f 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedWorkletTest.cpp
+++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletTest.cpp
@@ -84,7 +84,7 @@
     EXPECT_TRUE(global_scope->GetSecurityOrigin()->IsUnique());
     EXPECT_FALSE(global_scope->DocumentSecurityOrigin()->IsUnique());
     GetParentFrameTaskRunners()
-        ->Get(TaskType::kUnspecedTimer)
+        ->Get(TaskType::kInternalTest)
         ->PostTask(BLINK_FROM_HERE, CrossThreadBind(&testing::ExitRunLoop));
   }
 
@@ -108,7 +108,7 @@
         IntegrityMetadataSet(), kParserInserted));
 
     GetParentFrameTaskRunners()
-        ->Get(TaskType::kUnspecedTimer)
+        ->Get(TaskType::kInternalTest)
         ->PostTask(BLINK_FROM_HERE, CrossThreadBind(&testing::ExitRunLoop));
   }
 
@@ -117,7 +117,7 @@
     EXPECT_TRUE(IsCurrentThread());
     GlobalScope()->CountFeature(feature);
     GetParentFrameTaskRunners()
-        ->Get(TaskType::kUnspecedTimer)
+        ->Get(TaskType::kInternalTest)
         ->PostTask(BLINK_FROM_HERE, CrossThreadBind(&testing::ExitRunLoop));
   }
 
@@ -132,17 +132,17 @@
     EXPECT_TRUE(console_message.Contains("deprecated"));
 
     GetParentFrameTaskRunners()
-        ->Get(TaskType::kUnspecedTimer)
+        ->Get(TaskType::kInternalTest)
         ->PostTask(BLINK_FROM_HERE, CrossThreadBind(&testing::ExitRunLoop));
   }
 
   void TestTaskRunner() {
     EXPECT_TRUE(IsCurrentThread());
     scoped_refptr<WebTaskRunner> task_runner =
-        GlobalScope()->GetTaskRunner(TaskType::kUnspecedTimer);
+        GlobalScope()->GetTaskRunner(TaskType::kInternalTest);
     EXPECT_TRUE(task_runner->RunsTasksInCurrentSequence());
     GetParentFrameTaskRunners()
-        ->Get(TaskType::kUnspecedTimer)
+        ->Get(TaskType::kInternalTest)
         ->PostTask(BLINK_FROM_HERE, CrossThreadBind(&testing::ExitRunLoop));
   }
 
@@ -232,7 +232,7 @@
   MessagingProxy()->Start();
 
   GetWorkerThread()
-      ->GetTaskRunner(TaskType::kUnspecedTimer)
+      ->GetTaskRunner(TaskType::kInternalTest)
       ->PostTask(
           BLINK_FROM_HERE,
           CrossThreadBind(&ThreadedWorkletThreadForTest::TestSecurityOrigin,
@@ -252,7 +252,7 @@
   MessagingProxy()->Start();
 
   GetWorkerThread()
-      ->GetTaskRunner(TaskType::kUnspecedTimer)
+      ->GetTaskRunner(TaskType::kInternalTest)
       ->PostTask(BLINK_FROM_HERE,
                  CrossThreadBind(
                      &ThreadedWorkletThreadForTest::TestContentSecurityPolicy,
@@ -270,7 +270,7 @@
   // on the Document.
   EXPECT_FALSE(UseCounter::IsCounted(GetDocument(), kFeature1));
   GetWorkerThread()
-      ->GetTaskRunner(TaskType::kUnspecedTimer)
+      ->GetTaskRunner(TaskType::kInternalTest)
       ->PostTask(
           BLINK_FROM_HERE,
           CrossThreadBind(&ThreadedWorkletThreadForTest::CountFeature,
@@ -281,7 +281,7 @@
   // API use should be reported to the Document only one time. See comments in
   // ThreadedWorkletGlobalScopeForTest::CountFeature.
   GetWorkerThread()
-      ->GetTaskRunner(TaskType::kUnspecedTimer)
+      ->GetTaskRunner(TaskType::kInternalTest)
       ->PostTask(
           BLINK_FROM_HERE,
           CrossThreadBind(&ThreadedWorkletThreadForTest::CountFeature,
@@ -295,7 +295,7 @@
   // UseCounter on the Document.
   EXPECT_FALSE(UseCounter::IsCounted(GetDocument(), kFeature2));
   GetWorkerThread()
-      ->GetTaskRunner(TaskType::kUnspecedTimer)
+      ->GetTaskRunner(TaskType::kInternalTest)
       ->PostTask(
           BLINK_FROM_HERE,
           CrossThreadBind(&ThreadedWorkletThreadForTest::CountDeprecation,
@@ -306,7 +306,7 @@
   // API use should be reported to the Document only one time. See comments in
   // ThreadedWorkletGlobalScopeForTest::CountDeprecation.
   GetWorkerThread()
-      ->GetTaskRunner(TaskType::kUnspecedTimer)
+      ->GetTaskRunner(TaskType::kInternalTest)
       ->PostTask(
           BLINK_FROM_HERE,
           CrossThreadBind(&ThreadedWorkletThreadForTest::CountDeprecation,
@@ -318,7 +318,7 @@
   MessagingProxy()->Start();
 
   GetWorkerThread()
-      ->GetTaskRunner(TaskType::kUnspecedTimer)
+      ->GetTaskRunner(TaskType::kInternalTest)
       ->PostTask(BLINK_FROM_HERE,
                  CrossThreadBind(&ThreadedWorkletThreadForTest::TestTaskRunner,
                                  CrossThreadUnretained(GetWorkerThread())));
diff --git a/third_party/WebKit/Source/core/workers/WorkerThreadTest.cpp b/third_party/WebKit/Source/core/workers/WorkerThreadTest.cpp
index f45ff5cc..3e4b95f3 100644
--- a/third_party/WebKit/Source/core/workers/WorkerThreadTest.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerThreadTest.cpp
@@ -58,7 +58,7 @@
 
   // Notify the main thread that the debugger task is waiting for the signal.
   worker_thread->GetParentFrameTaskRunners()
-      ->Get(TaskType::kUnspecedTimer)
+      ->Get(TaskType::kInternalTest)
       ->PostTask(BLINK_FROM_HERE, CrossThreadBind(&testing::ExitRunLoop));
   waitable_event->Wait();
 }
diff --git a/third_party/WebKit/Source/modules/animationworklet/AnimationWorkletGlobalScopeTest.cpp b/third_party/WebKit/Source/modules/animationworklet/AnimationWorkletGlobalScopeTest.cpp
index 985af3a..23207f5a 100644
--- a/third_party/WebKit/Source/modules/animationworklet/AnimationWorkletGlobalScopeTest.cpp
+++ b/third_party/WebKit/Source/modules/animationworklet/AnimationWorkletGlobalScopeTest.cpp
@@ -78,7 +78,7 @@
   void RunTestOnWorkletThread(TestCalback callback) {
     std::unique_ptr<WorkerThread> worklet = CreateAnimationWorkletThread();
     WaitableEvent waitable_event;
-    worklet->GetTaskRunner(TaskType::kUnthrottled)
+    worklet->GetTaskRunner(TaskType::kInternalTest)
         ->PostTask(BLINK_FROM_HERE,
                    CrossThreadBind(callback, CrossThreadUnretained(this),
                                    CrossThreadUnretained(worklet.get()),
diff --git a/third_party/WebKit/Source/modules/speech/testing/PlatformSpeechSynthesizerMock.cpp b/third_party/WebKit/Source/modules/speech/testing/PlatformSpeechSynthesizerMock.cpp
index 94899da..61cfb35 100644
--- a/third_party/WebKit/Source/modules/speech/testing/PlatformSpeechSynthesizerMock.cpp
+++ b/third_party/WebKit/Source/modules/speech/testing/PlatformSpeechSynthesizerMock.cpp
@@ -46,11 +46,11 @@
     ExecutionContext* context)
     : PlatformSpeechSynthesizer(client),
       speaking_error_occurred_timer_(
-          context->GetTaskRunner(TaskType::kUnspecedTimer),
+          context->GetTaskRunner(TaskType::kInternalTest),
           this,
           &PlatformSpeechSynthesizerMock::SpeakingErrorOccurred),
       speaking_finished_timer_(
-          context->GetTaskRunner(TaskType::kUnspecedTimer),
+          context->GetTaskRunner(TaskType::kInternalTest),
           this,
           &PlatformSpeechSynthesizerMock::SpeakingFinished) {}
 
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScopeTest.cpp b/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScopeTest.cpp
index 4e5e058..d8618b0 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScopeTest.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScopeTest.cpp
@@ -84,7 +84,7 @@
 
   void RunBasicTest(WorkerThread* thread) {
     WaitableEvent waitable_event;
-    thread->GetTaskRunner(TaskType::kUnthrottled)
+    thread->GetTaskRunner(TaskType::kInternalTest)
         ->PostTask(
             BLINK_FROM_HERE,
             CrossThreadBind(
@@ -96,7 +96,7 @@
 
   void RunSimpleProcessTest(WorkerThread* thread) {
     WaitableEvent waitable_event;
-    thread->GetTaskRunner(TaskType::kUnthrottled)
+    thread->GetTaskRunner(TaskType::kInternalTest)
         ->PostTask(BLINK_FROM_HERE,
                    CrossThreadBind(&AudioWorkletGlobalScopeTest::
                                        RunSimpleProcessTestOnWorkletThread,
@@ -108,7 +108,7 @@
 
   void RunParsingTest(WorkerThread* thread) {
     WaitableEvent waitable_event;
-    thread->GetTaskRunner(TaskType::kUnthrottled)
+    thread->GetTaskRunner(TaskType::kInternalTest)
         ->PostTask(
             BLINK_FROM_HERE,
             CrossThreadBind(
@@ -120,7 +120,7 @@
 
   void RunParsingParameterDescriptorTest(WorkerThread* thread) {
     WaitableEvent waitable_event;
-    thread->GetTaskRunner(TaskType::kUnthrottled)
+    thread->GetTaskRunner(TaskType::kInternalTest)
         ->PostTask(
             BLINK_FROM_HERE,
             CrossThreadBind(
diff --git a/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h b/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
index a59a5b7..a9b6b05d 100644
--- a/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
+++ b/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
@@ -106,7 +106,7 @@
   }
 
   scoped_refptr<WebTaskRunner> GetLoadingTaskRunner() override {
-    return frame_scheduler_->GetTaskRunner(TaskType::kUnspecedLoading);
+    return frame_scheduler_->GetTaskRunner(TaskType::kInternalTest);
   }
 
  private:
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_global_scope_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/child/worker_global_scope_scheduler.cc
index a0d27a77..3c8975ef 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/worker_global_scope_scheduler.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/worker_global_scope_scheduler.cc
@@ -56,6 +56,7 @@
     case TaskType::kUnspecedTimer:
     case TaskType::kUnspecedLoading:
     case TaskType::kUnthrottled:
+    case TaskType::kInternalTest:
       // UnthrottledTaskRunner is generally discouraged in future.
       // TODO(nhiroki): Identify which tasks can be throttled / suspendable and
       // move them into other task runners. See also comments in
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_global_scope_scheduler_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/worker_global_scope_scheduler_unittest.cc
index 62ff5e4..8d820b4 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/worker_global_scope_scheduler_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/worker_global_scope_scheduler_unittest.cc
@@ -51,7 +51,7 @@
   // Helper for posting a task.
   void PostTestTask(std::vector<std::string>* run_order,
                     const std::string& task_descriptor) {
-    global_scope_scheduler_->GetTaskRunner(TaskType::kUnthrottled)
+    global_scope_scheduler_->GetTaskRunner(TaskType::kInternalTest)
         ->PostTask(FROM_HERE,
                    WTF::Bind(&AppendToVectorTestTask,
                              WTF::Unretained(run_order), task_descriptor));
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
index 1e93634..1e42413 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
@@ -260,6 +260,7 @@
     case TaskType::kMediaElementEvent:
       return WebTaskRunnerImpl::Create(PausableTaskQueue(), type);
     case TaskType::kUnthrottled:
+    case TaskType::kInternalTest:
       return WebTaskRunnerImpl::Create(UnpausableTaskQueue(), type);
     case TaskType::kCount:
       NOTREACHED();
diff --git a/third_party/WebKit/public/platform/TaskType.h b/third_party/WebKit/public/platform/TaskType.h
index e5734bd0..918227c 100644
--- a/third_party/WebKit/public/platform/TaskType.h
+++ b/third_party/WebKit/public/platform/TaskType.h
@@ -10,6 +10,10 @@
 // A list of task sources known to Blink according to the spec.
 // This enum is used for a histogram and it should not be re-numbered.
 enum class TaskType : unsigned {
+  ///////////////////////////////////////
+  // Speced tasks should use one of the following task types
+  ///////////////////////////////////////
+
   // Speced tasks and related internal tasks should be posted to one of
   // the following task runners. These task runners may be throttled.
 
@@ -108,6 +112,10 @@
   // The task runner may be throttled.
   kMiscPlatformAPI = 22,
 
+  ///////////////////////////////////////
+  // The following task types are DEPRECATED! Use kInternal* instead.
+  ///////////////////////////////////////
+
   // Other internal tasks that cannot fit any of the above task runners
   // can be posted here, but the usage is not encouraged. The task runner
   // may be throttled.
@@ -121,7 +129,14 @@
   // should be very limited.
   kUnthrottled = 25,
 
-  kCount = 26,
+  ///////////////////////////////////////
+  // Not-speced tasks should use one of the following task types
+  ///////////////////////////////////////
+
+  // Tasks for tests or mock objects.
+  kInternalTest = 26,
+
+  kCount = 27,
 };
 
 }  // namespace blink
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 9aeb4dd..849d3ab 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -36140,6 +36140,7 @@
   <int value="23" label="UnspecedTimer"/>
   <int value="24" label="UnspecedLoading"/>
   <int value="25" label="Unthrottled"/>
+  <int value="26" label="InternalTest"/>
 </enum>
 
 <enum name="RendererSchedulerThreadType">