diff --git a/DEPS b/DEPS
index 211f07b..7c142294 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'eccf352a2843bd5c732abfd6cc8a8449cde97a26',
+  'skia_revision': 'e79b473714866682dea85b66c005c5bb2ff6a397',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'b860a49fb15b1e6f70e69aef93a591cbcd7793f0',
+  'v8_revision': '17189bf456b4b671a3c404724d4b1599678c77a4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'e0b592236db902e3e8cbca7ec64f8e2b192e1935',
+  'pdfium_revision': 'aeee187c927c07f47a9e5886a417dcc58badefb6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index a67d721..bc78d24 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -428,6 +428,8 @@
     "system/palette/tools/laser_pointer_mode.h",
     "system/palette/tools/magnifier_mode.cc",
     "system/palette/tools/magnifier_mode.h",
+    "system/palette/tools/metalayer_mode.cc",
+    "system/palette/tools/metalayer_mode.h",
     "system/power/battery_notification.cc",
     "system/power/battery_notification.h",
     "system/power/dual_role_notification.cc",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 7ade540..3b3d467 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -394,6 +394,9 @@
       <message name="IDS_ASH_STYLUS_TOOLS_MAGNIFIER_MODE" desc="Title of the magnification mode in the stylus tools. Clicking this button opens up a magnifier. The magnifier remains active until the user turns it off by tapping the same button again.">
         Magnifying glass mode
       </message>
+      <message name="IDS_ASH_STYLUS_TOOLS_METALAYER_MODE" desc="Title of the metalayer mode in the stylus tools. Clicking this button opens up the voice interaction overlay. The overlay remains active until the user completes the interaction.">
+        Metalayer mode
+      </message>
       <message name="IDS_ASH_STYLUS_TOOLS_TITLE" desc="The title of the stylus tools dialog in the ash shelf.">
         Stylus tools
       </message>
diff --git a/ash/palette_delegate.h b/ash/palette_delegate.h
index 942f09e..8f370d6b 100644
--- a/ash/palette_delegate.h
+++ b/ash/palette_delegate.h
@@ -54,6 +54,17 @@
   // Cancels any active partial screenshot session.
   virtual void CancelPartialScreenshot() = 0;
 
+  // Returns true if the metalayer is available.
+  virtual bool IsMetalayerSupported() = 0;
+
+  // Shows the metalayer.
+  // |closed| will be invoked when the metalayer is closed or
+  // if the metalayer could not be shown.
+  virtual void ShowMetalayer(const base::Closure& closed) = 0;
+
+  // Hides the metalayer.
+  virtual void HideMetalayer() = 0;
+
  private:
   DISALLOW_ASSIGN(PaletteDelegate);
 };
diff --git a/ash/public/interfaces/session_controller.mojom b/ash/public/interfaces/session_controller.mojom
index ed066cbd..0dd24b16 100644
--- a/ash/public/interfaces/session_controller.mojom
+++ b/ash/public/interfaces/session_controller.mojom
@@ -143,6 +143,14 @@
   // active user session.
   SetUserSessionOrder(array<uint32> user_session_ids);
 
+  // Runs the pre-lock animation to start locking ash. When the call returns,
+  // |locked| == true means that the post-lock animation is finished and ash is
+  // fully locked. Otherwise |locked| is false, which means something is wrong
+  // for the lock and ash is not locked. When the call returns with a true
+  // |locked|, screen locker runs the post lock jobs such as a11y announcement
+  // etc. Invoked by the screen locker during initialization.
+  StartLock() => (bool locked);
+
   // Runs the pre-unlock animation. Invoked by the screen locker before
   // dismissing. When the mojo call returns, screen locker takes that as a
   // signal of finished unlock animation and dismisses itself.
diff --git a/ash/session/session_controller.cc b/ash/session/session_controller.cc
index 873f5776..94ee2bfb 100644
--- a/ash/session/session_controller.cc
+++ b/ash/session/session_controller.cc
@@ -42,9 +42,14 @@
 
 }  // namespace
 
-SessionController::SessionController() : state_(GetDefaultSessionState()) {}
+SessionController::SessionController()
+    : state_(GetDefaultSessionState()), weak_ptr_factory_(this) {}
 
-SessionController::~SessionController() {}
+SessionController::~SessionController() {
+  // Abort pending start lock request.
+  if (!start_lock_callback_.is_null())
+    std::move(start_lock_callback_).Run(false /* locked */);
+}
 
 void SessionController::BindRequest(mojom::SessionControllerRequest request) {
   bindings_.AddBinding(this, std::move(request));
@@ -228,6 +233,19 @@
   }
 }
 
+void SessionController::StartLock(const StartLockCallback& callback) {
+  DCHECK(start_lock_callback_.is_null());
+  start_lock_callback_ = callback;
+
+  LockStateController* const lock_state_controller =
+      Shell::Get()->lock_state_controller();
+
+  lock_state_controller->SetLockScreenDisplayedCallback(
+      base::Bind(&SessionController::OnLockAnimationFinished,
+                 weak_ptr_factory_.GetWeakPtr()));
+  lock_state_controller->OnStartingLock();
+}
+
 void SessionController::RunUnlockAnimation(
     const RunUnlockAnimationCallback& callback) {
   is_unlocking_ = true;
@@ -353,4 +371,9 @@
     observer.OnLoginStatusChanged(login_status_);
 }
 
+void SessionController::OnLockAnimationFinished() {
+  if (!start_lock_callback_.is_null())
+    std::move(start_lock_callback_).Run(true /* locked */);
+}
+
 }  // namespace ash
diff --git a/ash/session/session_controller.h b/ash/session/session_controller.h
index fa594e1..6bab9fe 100644
--- a/ash/session/session_controller.h
+++ b/ash/session/session_controller.h
@@ -13,7 +13,9 @@
 #include "ash/login_status.h"
 #include "ash/public/cpp/session_types.h"
 #include "ash/public/interfaces/session_controller.mojom.h"
+#include "base/callback.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 
@@ -117,6 +119,7 @@
   void UpdateUserSession(mojom::UserSessionPtr user_session) override;
   void SetUserSessionOrder(
       const std::vector<uint32_t>& user_session_order) override;
+  void StartLock(const StartLockCallback& callback) override;
   void RunUnlockAnimation(const RunUnlockAnimationCallback& callback) override;
   void NotifyChromeTerminating() override;
 
@@ -138,6 +141,11 @@
   // Update the |login_status_| and notify observers.
   void UpdateLoginStatus();
 
+  // Used as lock screen displayed callback of LockStateController and invoked
+  // when post lock animation finishes and ash is fully locked. It would then
+  // run |start_lock_callback_| to indicate ash is locked successfully.
+  void OnLockAnimationFinished();
+
   // Bindings for mojom::SessionController interface.
   mojo::BindingSet<mojom::SessionController> bindings_;
 
@@ -167,8 +175,13 @@
   // animation starts and reset when session state is no longer LOCKED.
   bool is_unlocking_ = false;
 
+  // Pending callback for the StartLock request.
+  base::OnceCallback<void(bool)> start_lock_callback_;
+
   base::ObserverList<ash::SessionObserver> observers_;
 
+  base::WeakPtrFactory<SessionController> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(SessionController);
 };
 
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index 8aab1ae..6474dd5f 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -51,6 +51,9 @@
       done.Run();
   }
   void CancelPartialScreenshot() override {}
+  bool IsMetalayerSupported() override { return false; }
+  void ShowMetalayer(const base::Closure& closed) override {}
+  void HideMetalayer() override {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(PaletteDelegateImpl);
diff --git a/ash/system/palette/palette_ids.cc b/ash/system/palette/palette_ids.cc
index 1e2338f4..63614e8 100644
--- a/ash/system/palette/palette_ids.cc
+++ b/ash/system/palette/palette_ids.cc
@@ -21,6 +21,8 @@
       return "LASER_POINTER";
     case PaletteToolId::MAGNIFY:
       return "MAGNIFY";
+    case PaletteToolId::METALAYER:
+      return "METALAYER";
   }
 
   NOTREACHED();
@@ -53,6 +55,8 @@
       return PALETTE_LASER_POINTER;
     case PaletteToolId::MAGNIFY:
       return PALETTE_MAGNIFY;
+    case PaletteToolId::METALAYER:
+      return PALETTE_METALAYER;
   }
 
   NOTREACHED();
diff --git a/ash/system/palette/palette_ids.h b/ash/system/palette/palette_ids.h
index d3369a26..5bfd47f 100644
--- a/ash/system/palette/palette_ids.h
+++ b/ash/system/palette/palette_ids.h
@@ -25,6 +25,7 @@
   CAPTURE_SCREEN,
   LASER_POINTER,
   MAGNIFY,
+  METALAYER,
 };
 
 // Usage of each pen palette option. This enum is used to back an UMA histogram
@@ -38,6 +39,7 @@
   PALETTE_NEW_NOTE,
   PALETTE_MAGNIFY,
   PALETTE_LASER_POINTER,
+  PALETTE_METALAYER,
   PALETTE_OPTIONS_COUNT
 };
 
diff --git a/ash/system/palette/palette_tool.cc b/ash/system/palette/palette_tool.cc
index 74b88a0..44957a1 100644
--- a/ash/system/palette/palette_tool.cc
+++ b/ash/system/palette/palette_tool.cc
@@ -11,6 +11,7 @@
 #include "ash/system/palette/tools/create_note_action.h"
 #include "ash/system/palette/tools/laser_pointer_mode.h"
 #include "ash/system/palette/tools/magnifier_mode.h"
+#include "ash/system/palette/tools/metalayer_mode.h"
 #include "base/memory/ptr_util.h"
 #include "ui/gfx/paint_vector_icon.h"
 
@@ -21,6 +22,7 @@
   tool_manager->AddTool(base::MakeUnique<CaptureRegionMode>(tool_manager));
   tool_manager->AddTool(base::MakeUnique<CaptureScreenAction>(tool_manager));
   tool_manager->AddTool(base::MakeUnique<CreateNoteAction>(tool_manager));
+  tool_manager->AddTool(base::MakeUnique<MetalayerMode>(tool_manager));
   tool_manager->AddTool(base::MakeUnique<LaserPointerMode>(tool_manager));
   tool_manager->AddTool(base::MakeUnique<MagnifierMode>(tool_manager));
 }
diff --git a/ash/system/palette/tools/metalayer_mode.cc b/ash/system/palette/tools/metalayer_mode.cc
new file mode 100644
index 0000000..ff3a8a7
--- /dev/null
+++ b/ash/system/palette/tools/metalayer_mode.cc
@@ -0,0 +1,65 @@
+// 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 "ash/system/palette/tools/metalayer_mode.h"
+
+#include "ash/palette_delegate.h"
+#include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/shell.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "ash/system/palette/palette_ids.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace ash {
+
+MetalayerMode::MetalayerMode(Delegate* delegate)
+    : CommonPaletteTool(delegate), weak_factory_(this) {}
+
+MetalayerMode::~MetalayerMode() {}
+
+PaletteGroup MetalayerMode::GetGroup() const {
+  return PaletteGroup::MODE;
+}
+
+PaletteToolId MetalayerMode::GetToolId() const {
+  return PaletteToolId::METALAYER;
+}
+
+void MetalayerMode::OnEnable() {
+  CommonPaletteTool::OnEnable();
+
+  Shell::Get()->palette_delegate()->ShowMetalayer(
+      base::Bind(&MetalayerMode::OnMetalayerDone, weak_factory_.GetWeakPtr()));
+  delegate()->HidePalette();
+}
+
+void MetalayerMode::OnDisable() {
+  CommonPaletteTool::OnDisable();
+
+  Shell::Get()->palette_delegate()->HideMetalayer();
+}
+
+const gfx::VectorIcon& MetalayerMode::GetActiveTrayIcon() const {
+  // TODO(kaznacheev) replace with the correct icon when it is available
+  return kPaletteTrayIconCaptureRegionIcon;
+}
+
+const gfx::VectorIcon& MetalayerMode::GetPaletteIcon() const {
+  // TODO(kaznacheev) replace with the correct icon when it is available
+  return kPaletteActionCaptureRegionIcon;
+}
+
+views::View* MetalayerMode::CreateView() {
+  if (!Shell::Get()->palette_delegate()->IsMetalayerSupported())
+    return nullptr;
+
+  return CreateDefaultView(
+      l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_METALAYER_MODE));
+}
+
+void MetalayerMode::OnMetalayerDone() {
+  delegate()->DisableTool(GetToolId());
+}
+
+}  // namespace ash
diff --git a/ash/system/palette/tools/metalayer_mode.h b/ash/system/palette/tools/metalayer_mode.h
new file mode 100644
index 0000000..c839fa9
--- /dev/null
+++ b/ash/system/palette/tools/metalayer_mode.h
@@ -0,0 +1,42 @@
+// 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 ASH_SYSTEM_PALETTE_TOOLS_METALAYER_MODE_H_
+#define ASH_SYSTEM_PALETTE_TOOLS_METALAYER_MODE_H_
+
+#include "ash/ash_export.h"
+#include "ash/system/palette/common_palette_tool.h"
+#include "base/memory/weak_ptr.h"
+
+namespace ash {
+
+// A palette tool that lets the user select a screen region to be passed
+// to the voice interaction framework.
+class ASH_EXPORT MetalayerMode : public CommonPaletteTool {
+ public:
+  explicit MetalayerMode(Delegate* delegate);
+  ~MetalayerMode() override;
+
+ private:
+  // PaletteTool:
+  PaletteGroup GetGroup() const override;
+  PaletteToolId GetToolId() const override;
+  void OnEnable() override;
+  void OnDisable() override;
+  const gfx::VectorIcon& GetActiveTrayIcon() const override;
+  views::View* CreateView() override;
+
+  // CommonPaletteTool:
+  const gfx::VectorIcon& GetPaletteIcon() const override;
+
+  void OnMetalayerDone();
+
+  base::WeakPtrFactory<MetalayerMode> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(MetalayerMode);
+};
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_PALETTE_TOOLS_METALAYER_MODE_H_
diff --git a/ash/test/test_palette_delegate.cc b/ash/test/test_palette_delegate.cc
index 49881d3..5110f266 100644
--- a/ash/test/test_palette_delegate.cc
+++ b/ash/test/test_palette_delegate.cc
@@ -44,4 +44,12 @@
 
 void TestPaletteDelegate::CancelPartialScreenshot() {}
 
+bool TestPaletteDelegate::IsMetalayerSupported() {
+  return false;
+}
+
+void TestPaletteDelegate::ShowMetalayer(const base::Closure& closed) {}
+
+void TestPaletteDelegate::HideMetalayer() {}
+
 }  // namespace ash
diff --git a/ash/test/test_palette_delegate.h b/ash/test/test_palette_delegate.h
index a572eb3..4fee8b0 100644
--- a/ash/test/test_palette_delegate.h
+++ b/ash/test/test_palette_delegate.h
@@ -51,6 +51,9 @@
   void TakeScreenshot() override;
   void TakePartialScreenshot(const base::Closure& done) override;
   void CancelPartialScreenshot() override;
+  bool IsMetalayerSupported() override;
+  void ShowMetalayer(const base::Closure& closed) override;
+  void HideMetalayer() override;
 
   int create_note_count_ = 0;
   int has_note_app_count_ = 0;
diff --git a/ash/wm/lock_state_controller.cc b/ash/wm/lock_state_controller.cc
index 2370054f..0b996a1 100644
--- a/ash/wm/lock_state_controller.cc
+++ b/ash/wm/lock_state_controller.cc
@@ -181,8 +181,9 @@
 }
 
 void LockStateController::SetLockScreenDisplayedCallback(
-    const base::Closure& callback) {
-  lock_screen_displayed_callback_ = callback;
+    base::OnceClosure callback) {
+  DCHECK(lock_screen_displayed_callback_.is_null());
+  lock_screen_displayed_callback_ = std::move(callback);
 }
 
 void LockStateController::OnHostCloseRequested(
@@ -496,10 +497,9 @@
   VLOG(1) << "PostLockAnimationFinished";
   ShellPort::Get()->OnLockStateEvent(
       LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED);
-  if (!lock_screen_displayed_callback_.is_null()) {
-    lock_screen_displayed_callback_.Run();
-    lock_screen_displayed_callback_.Reset();
-  }
+  if (!lock_screen_displayed_callback_.is_null())
+    std::move(lock_screen_displayed_callback_).Run();
+
   CHECK(!views::MenuController::GetActiveInstance());
   if (shutdown_after_lock_) {
     shutdown_after_lock_ = false;
diff --git a/ash/wm/lock_state_controller.h b/ash/wm/lock_state_controller.h
index bbda1be..aa4530c3 100644
--- a/ash/wm/lock_state_controller.h
+++ b/ash/wm/lock_state_controller.h
@@ -116,7 +116,7 @@
 
   // Sets up the callback that should be called once lock animation is finished.
   // Callback is guaranteed to be called once and then discarded.
-  void SetLockScreenDisplayedCallback(const base::Closure& callback);
+  void SetLockScreenDisplayedCallback(base::OnceClosure callback);
 
   // aura::WindowTreeHostObserver override:
   void OnHostCloseRequested(const aura::WindowTreeHost* host) override;
@@ -240,7 +240,7 @@
   // etc. are shut down.
   base::OneShotTimer real_shutdown_timer_;
 
-  base::Closure lock_screen_displayed_callback_;
+  base::OnceClosure lock_screen_displayed_callback_;
 
   ScopedSessionObserver scoped_session_observer_;
 
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h
index 86fac9c..2c3d506 100644
--- a/base/mac/sdk_forward_declarations.h
+++ b/base/mac/sdk_forward_declarations.h
@@ -187,6 +187,7 @@
 
 @interface NSObject (ElCapitanSDK)
 - (NSLayoutConstraint*)constraintEqualToConstant:(CGFloat)c;
+- (NSLayoutConstraint*)constraintGreaterThanOrEqualToConstant:(CGFloat)c;
 @end
 
 @interface NSView (ElCapitanSDK)
@@ -246,6 +247,10 @@
                                     action:(SEL)action;
 @end
 
+@interface NSApplication (SierraPointOneSDK)
+@property BOOL automaticCustomizeTouchBarMenuItemEnabled;
+@end
+
 #endif  // MAC_OS_X_VERSION_10_12_1
 
 // ----------------------------------------------------------------------------
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 3b77c055..6a495cc 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -20,6 +20,9 @@
 if (is_mac) {
   import("//build/config/mac/symbols.gni")
 }
+if (is_ios) {
+  import("//build/config/ios/ios_sdk.gni")
+}
 
 declare_args() {
   # Default to warnings as errors for default workflow, where we catch
@@ -1102,6 +1105,17 @@
         # TODO(thakis ): https://crbug.com/683349
         "-Wno-user-defined-warnings",
       ]
+    } else if (use_xcode_clang &&
+               (xcode_version == "0830" || xcode_version == "0831" ||
+                xcode_version == "0832")) {
+      # This is necessary to allow a progressive transition from using xcode 8 to 8.3. Remove when all bots are migrated to 8.3.
+      cflags += [
+        # TODO(thakis): https://crbug.com/604888
+        "-Wno-undefined-var-template",
+
+        # TODO(hans): https://crbug.com/637306
+        "-Wno-address-of-packed-member",
+      ]
     }
   }
 }
diff --git a/cc/layers/surface_layer_unittest.cc b/cc/layers/surface_layer_unittest.cc
index 0ee4e83..4c354a7 100644
--- a/cc/layers/surface_layer_unittest.cc
+++ b/cc/layers/surface_layer_unittest.cc
@@ -32,6 +32,9 @@
 namespace cc {
 namespace {
 
+using testing::_;
+using testing::Eq;
+
 static constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
 
 class SurfaceLayerTest : public testing::Test {
@@ -63,33 +66,20 @@
   FakeLayerTreeHostImpl host_impl_;
 };
 
-class TestSurfaceReferenceFactory : public SequenceSurfaceReferenceFactory {
- protected:
-  void SatisfySequence(const SurfaceSequence& seq) const override {
-    *out_seq_ = seq;
-  }
-
-  void RequireSequence(const SurfaceId& id,
-                       const SurfaceSequence& seq) const override {
-    *out_id_ = id;
-    out_set_->insert(seq);
-  }
-
+class MockSurfaceReferenceFactory : public SequenceSurfaceReferenceFactory {
  public:
-  TestSurfaceReferenceFactory(SurfaceSequence* out_seq,
-                              SurfaceId* out_id,
-                              std::set<SurfaceSequence>* out_set)
-      : out_seq_(out_seq), out_id_(out_id), out_set_(out_set) {}
+  MockSurfaceReferenceFactory() {}
+
+  // SequenceSurfaceReferenceFactory implementation.
+  MOCK_CONST_METHOD1(SatisfySequence, void(const SurfaceSequence&));
+  MOCK_CONST_METHOD2(RequireSequence,
+                     void(const SurfaceId&, const SurfaceSequence&));
 
  protected:
-  ~TestSurfaceReferenceFactory() override = default;
+  ~MockSurfaceReferenceFactory() override = default;
 
  private:
-  SurfaceSequence* out_seq_;
-  SurfaceId* out_id_;
-  std::set<SurfaceSequence>* out_set_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestSurfaceReferenceFactory);
+  DISALLOW_COPY_AND_ASSIGN(MockSurfaceReferenceFactory);
 };
 
 // Check that one surface can be referenced by multiple LayerTreeHosts, and
@@ -97,17 +87,26 @@
 TEST_F(SurfaceLayerTest, MultipleFramesOneSurface) {
   const base::UnguessableToken kArbitraryToken =
       base::UnguessableToken::Create();
-  SurfaceSequence blank_change;  // Receives sequence if commit doesn't happen.
-
-  SurfaceId required_id;
-  std::set<SurfaceSequence> required_seq;
-  scoped_refptr<SurfaceReferenceFactory> ref_factory =
-      new TestSurfaceReferenceFactory(&blank_change, &required_id,
-                                      &required_seq);
-  auto layer = SurfaceLayer::Create(ref_factory);
-  SurfaceInfo info(
+  const SurfaceInfo info(
       SurfaceId(kArbitraryFrameSinkId, LocalSurfaceId(1, kArbitraryToken)), 1.f,
       gfx::Size(1, 1));
+  const SurfaceSequence expected_seq1(FrameSinkId(1, 1), 1u);
+  const SurfaceSequence expected_seq2(FrameSinkId(2, 2), 1u);
+  const SurfaceId expected_id(kArbitraryFrameSinkId,
+                              LocalSurfaceId(1, kArbitraryToken));
+
+  scoped_refptr<MockSurfaceReferenceFactory> ref_factory =
+      new testing::StrictMock<MockSurfaceReferenceFactory>();
+
+  // We are going to set up the SurfaceLayers and LayerTreeHosts. Each layer
+  // will require a sequence and no sequence should be satisfied for now.
+  EXPECT_CALL(*ref_factory, RequireSequence(Eq(expected_id), Eq(expected_seq1)))
+      .Times(1);
+  EXPECT_CALL(*ref_factory, RequireSequence(Eq(expected_id), Eq(expected_seq2)))
+      .Times(1);
+  EXPECT_CALL(*ref_factory, SatisfySequence(_)).Times(0);
+
+  auto layer = SurfaceLayer::Create(ref_factory);
   layer->SetPrimarySurfaceInfo(info);
   layer_tree_host_->GetSurfaceSequenceGenerator()->set_frame_sink_id(
       FrameSinkId(1, 1));
@@ -117,57 +116,40 @@
   std::unique_ptr<FakeLayerTreeHost> layer_tree_host2 =
       FakeLayerTreeHost::Create(&fake_client_, &task_graph_runner_,
                                 animation_host2.get());
-  auto layer2 = SurfaceLayer::Create(std::move(ref_factory));
+  auto layer2 = SurfaceLayer::Create(ref_factory);
   layer2->SetPrimarySurfaceInfo(info);
   layer_tree_host2->GetSurfaceSequenceGenerator()->set_frame_sink_id(
       FrameSinkId(2, 2));
   layer_tree_host2->SetRootLayer(layer2);
 
-  // Layers haven't been removed, so no sequence should be satisfied.
-  EXPECT_FALSE(blank_change.is_valid());
+  testing::Mock::VerifyAndClearExpectations(ref_factory.get());
 
-  SurfaceSequence expected1(FrameSinkId(1, 1), 1u);
-  SurfaceSequence expected2(FrameSinkId(2, 2), 1u);
-
+  // Destroy the second LayerTreeHost. The sequence generated by its
+  // SurfaceLayer must be satisfied and no new sequences must be required.
+  EXPECT_CALL(*ref_factory, SatisfySequence(Eq(expected_seq2))).Times(1);
   layer_tree_host2->SetRootLayer(nullptr);
   layer_tree_host2.reset();
   animation_host2 = nullptr;
-
-  // Layer was removed so sequence from second LayerTreeHost should be
-  // satisfied.
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(blank_change == expected2);
+  testing::Mock::VerifyAndClearExpectations(ref_factory.get());
 
-  // Set of sequences that need to be satisfied should include sequences from
-  // both trees.
-  EXPECT_TRUE(required_id == SurfaceId(kArbitraryFrameSinkId,
-                                       LocalSurfaceId(1, kArbitraryToken)));
-  EXPECT_EQ(2u, required_seq.size());
-  EXPECT_TRUE(required_seq.count(expected1));
-  EXPECT_TRUE(required_seq.count(expected2));
-
+  // Destroy the first LayerTreeHost. The sequence generated by its
+  // SurfaceLayer must be satisfied and no new sequences must be required.
+  EXPECT_CALL(*ref_factory, SatisfySequence(expected_seq1)).Times(1);
+  EXPECT_CALL(*ref_factory, RequireSequence(_, _)).Times(0);
   layer_tree_host_->SetRootLayer(nullptr);
   layer_tree_host_.reset();
-
-  // Layer was removed so sequence from first LayerTreeHost should be
-  // satisfied.
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(blank_change == expected1);
-
-  // No more SurfaceSequences should have been generated that need to have be
-  // satisfied.
-  EXPECT_EQ(2u, required_seq.size());
+  testing::Mock::VerifyAndClearExpectations(ref_factory.get());
 }
 
 // This test verifies that the primary and fallback SurfaceInfo are pushed
 // across from SurfaceLayer to SurfaceLayerImpl.
 TEST_F(SurfaceLayerTest, SurfaceInfoPushProperties) {
-  SurfaceSequence blank_change;
-  SurfaceId required_id;
-  std::set<SurfaceSequence> required_sequences;
+  // We use a nice mock here because we are not really interested in calls to
+  // MockSurfaceReferenceFactory and we don't want warnings printed.
   scoped_refptr<SurfaceReferenceFactory> ref_factory =
-      new TestSurfaceReferenceFactory(&blank_change, &required_id,
-                                      &required_sequences);
+      new testing::NiceMock<MockSurfaceReferenceFactory>();
 
   scoped_refptr<SurfaceLayer> layer = SurfaceLayer::Create(ref_factory);
   layer_tree_host_->SetRootLayer(layer);
@@ -208,24 +190,34 @@
   void BeginTest() override {
     layer_tree_host()->GetSurfaceSequenceGenerator()->set_frame_sink_id(
         FrameSinkId(1, 1));
-    layer_ = SurfaceLayer::Create(new TestSurfaceReferenceFactory(
-        &satisfied_sequence_, &required_id_, &required_set_));
+    ref_factory_ = new testing::StrictMock<MockSurfaceReferenceFactory>();
+
+    // Create a SurfaceLayer but don't add it to the tree yet. No sequence
+    // should be required / satisfied.
+    EXPECT_CALL(*ref_factory_, SatisfySequence(_)).Times(0);
+    EXPECT_CALL(*ref_factory_, RequireSequence(_, _)).Times(0);
+    layer_ = SurfaceLayer::Create(ref_factory_);
     SurfaceInfo info(
         SurfaceId(kArbitraryFrameSinkId, LocalSurfaceId(1, kArbitraryToken)),
         1.f, gfx::Size(1, 1));
     layer_->SetPrimarySurfaceInfo(info);
+    testing::Mock::VerifyAndClearExpectations(ref_factory_.get());
 
-    // Layer hasn't been added to tree so no SurfaceSequence generated yet.
-    EXPECT_EQ(0u, required_set_.size());
-
+    // Add the layer to the tree. A sequence must be required.
+    SurfaceSequence expected_seq(kArbitraryFrameSinkId, 1u);
+    SurfaceId expected_id(kArbitraryFrameSinkId,
+                          LocalSurfaceId(1, kArbitraryToken));
+    EXPECT_CALL(*ref_factory_, SatisfySequence(_)).Times(0);
+    EXPECT_CALL(*ref_factory_,
+                RequireSequence(Eq(expected_id), Eq(expected_seq)))
+        .Times(1);
     layer_tree_host()->SetRootLayer(layer_);
+    testing::Mock::VerifyAndClearExpectations(ref_factory_.get());
 
-    // Should have SurfaceSequence from first tree.
-    SurfaceSequence expected(kArbitraryFrameSinkId, 1u);
-    EXPECT_TRUE(required_id_ == SurfaceId(kArbitraryFrameSinkId,
-                                          LocalSurfaceId(1, kArbitraryToken)));
-    EXPECT_EQ(1u, required_set_.size());
-    EXPECT_TRUE(required_set_.count(expected));
+    // By the end of the test, the required sequence must be satisfied and no
+    // more sequence must be required.
+    EXPECT_CALL(*ref_factory_, SatisfySequence(Eq(expected_seq))).Times(1);
+    EXPECT_CALL(*ref_factory_, RequireSequence(_, _)).Times(0);
 
     gfx::Size bounds(100, 100);
     layer_tree_host()->SetViewportSize(bounds);
@@ -245,15 +237,15 @@
                                   base::Unretained(this)));
   }
 
+  void AfterTest() override {}
+
  protected:
   int commit_count_;
   bool sequence_was_satisfied_;
   scoped_refptr<SurfaceLayer> layer_;
   scoped_refptr<Layer> blank_layer_;
-  SurfaceSequence satisfied_sequence_;
+  scoped_refptr<MockSurfaceReferenceFactory> ref_factory_;
 
-  SurfaceId required_id_;
-  std::set<SurfaceSequence> required_set_;
   const base::UnguessableToken kArbitraryToken =
       base::UnguessableToken::Create();
 };
@@ -276,14 +268,6 @@
         break;
     }
   }
-
-  void AfterTest() override {
-    EXPECT_TRUE(required_id_ == SurfaceId(kArbitraryFrameSinkId,
-                                          LocalSurfaceId(1, kArbitraryToken)));
-    EXPECT_EQ(1u, required_set_.size());
-    EXPECT_TRUE(satisfied_sequence_ ==
-                SurfaceSequence(kArbitraryFrameSinkId, 1u));
-  }
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(SurfaceLayerSwapPromiseWithDraw);
@@ -315,14 +299,6 @@
         break;
     }
   }
-
-  void AfterTest() override {
-    EXPECT_TRUE(required_id_ == SurfaceId(kArbitraryFrameSinkId,
-                                          LocalSurfaceId(1, kArbitraryToken)));
-    EXPECT_EQ(1u, required_set_.size());
-    EXPECT_TRUE(satisfied_sequence_ ==
-                SurfaceSequence(kArbitraryFrameSinkId, 1u));
-  }
 };
 
 MULTI_THREAD_TEST_F(SurfaceLayerSwapPromiseWithoutDraw);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 3a9b80d..d940da6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1528,13 +1528,12 @@
             return true;
         }
 
-        // Close the bottom sheet before trying to navigate back.
+        // Close the bottom sheet before trying to navigate back. If the tab is on the NTP, fall
+        // through to decide if the browser should be sent into the background.
         if (getBottomSheet() != null
-                && getBottomSheet().getSheetState() != BottomSheet.SHEET_STATE_PEEK) {
+                && getBottomSheet().getSheetState() != BottomSheet.SHEET_STATE_PEEK
+                && !(currentTab.getNativePage() instanceof ChromeHomeNewTabPage)) {
             getBottomSheet().setSheetState(BottomSheet.SHEET_STATE_PEEK, true);
-            if (currentTab.getNativePage() instanceof ChromeHomeNewTabPage) {
-                getCurrentTabModel().closeTab(currentTab, true, false, false);
-            }
             return true;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
index 3d61957..1b6af8d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
@@ -11,7 +11,6 @@
 import android.support.v4.view.GravityCompat;
 import android.support.v4.widget.DrawerLayout;
 import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.Toolbar;
 import android.text.TextUtils;
 import android.view.View;
 import android.view.ViewGroup;
@@ -28,6 +27,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.widget.selection.SelectableListLayout;
+import org.chromium.chrome.browser.widget.selection.SelectableListToolbar;
 import org.chromium.chrome.browser.widget.selection.SelectableListToolbar.SearchDelegate;
 import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
 import org.chromium.components.bookmarks.BookmarkId;
@@ -244,7 +244,7 @@
     /**
      * See {@link SelectableListLayout#detachToolbarView()}.
      */
-    public Toolbar detachToolbarView() {
+    public SelectableListToolbar detachToolbarView() {
         return mSelectableListLayout.detachToolbarView();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSheetContent.java
index ba7a661..c76c9e8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSheetContent.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.bookmarks;
 
-import android.support.v7.widget.Toolbar;
 import android.view.View;
 
 import org.chromium.chrome.browser.ChromeActivity;
@@ -12,24 +11,31 @@
 import org.chromium.chrome.browser.toolbar.BottomToolbarPhone;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContentController;
+import org.chromium.chrome.browser.widget.selection.SelectableListToolbar;
 
 /**
  * A {@link BottomSheetContent} holding a {@link BookmarkManager} for display in the BottomSheet.
  */
 public class BookmarkSheetContent implements BottomSheetContent {
     private final View mContentView;
-    private final Toolbar mToolbarView;
+    private final SelectableListToolbar mToolbarView;
     private BookmarkManager mBookmarkManager;
 
     /**
      * @param activity The activity displaying the bookmark manager UI.
      * @param snackbarManager The {@link SnackbarManager} used to display snackbars.
      */
-    public BookmarkSheetContent(ChromeActivity activity, SnackbarManager snackbarManager) {
+    public BookmarkSheetContent(final ChromeActivity activity, SnackbarManager snackbarManager) {
         mBookmarkManager = new BookmarkManager(activity, false, snackbarManager);
         mBookmarkManager.updateForUrl(BookmarkUtils.getLastUsedUrl(activity));
         mContentView = mBookmarkManager.getView();
         mToolbarView = mBookmarkManager.detachToolbarView();
+        mToolbarView.addObserver(new SelectableListToolbar.SelectableListToolbarObserver() {
+            @Override
+            public void onThemeColorChanged(boolean isLightTheme) {
+                activity.getBottomSheet().updateHandleTint();
+            }
+        });
         ((BottomToolbarPhone) activity.getToolbarManager().getToolbar())
                 .setOtherToolbarStyle(mToolbarView);
     }
@@ -45,6 +51,11 @@
     }
 
     @Override
+    public boolean isUsingLightToolbarTheme() {
+        return mToolbarView.isLightTheme();
+    }
+
+    @Override
     public int getVerticalScrollOffset() {
         return mBookmarkManager.getVerticalScrollOffset();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java
index a67c88b..0f074d3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.download;
 
 import android.app.Activity;
-import android.support.v7.widget.Toolbar;
 import android.view.View;
 
 import org.chromium.base.ActivityState;
@@ -18,13 +17,14 @@
 import org.chromium.chrome.browser.toolbar.BottomToolbarPhone;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContentController;
+import org.chromium.chrome.browser.widget.selection.SelectableListToolbar;
 
 /**
  * A {@link BottomSheetContent} holding a {@link DownloadManagerUi} for display in the BottomSheet.
  */
 public class DownloadSheetContent implements BottomSheetContent {
     private final View mContentView;
-    private final Toolbar mToolbarView;
+    private final SelectableListToolbar mToolbarView;
     private final ActivityStateListener mActivityStateListener;
     private DownloadManagerUi mDownloadManager;
 
@@ -33,14 +33,20 @@
      * @param isIncognito Whether the activity is currently displaying an incognito tab.
      * @param snackbarManager The {@link SnackbarManager} used to display snackbars.
      */
-    public DownloadSheetContent(
-            ChromeActivity activity, final boolean isIncognito, SnackbarManager snackbarManager) {
+    public DownloadSheetContent(final ChromeActivity activity, final boolean isIncognito,
+            SnackbarManager snackbarManager) {
         ThreadUtils.assertOnUiThread();
 
         mDownloadManager = new DownloadManagerUi(
                 activity, isIncognito, activity.getComponentName(), false, snackbarManager);
         mContentView = mDownloadManager.getView();
         mToolbarView = mDownloadManager.detachToolbarView();
+        mToolbarView.addObserver(new SelectableListToolbar.SelectableListToolbarObserver() {
+            @Override
+            public void onThemeColorChanged(boolean isLightTheme) {
+                activity.getBottomSheet().updateHandleTint();
+            }
+        });
         ((BottomToolbarPhone) activity.getToolbarManager().getToolbar())
                 .setOtherToolbarStyle(mToolbarView);
 
@@ -72,6 +78,11 @@
     }
 
     @Override
+    public boolean isUsingLightToolbarTheme() {
+        return mToolbarView.isLightTheme();
+    }
+
+    @Override
     public int getVerticalScrollOffset() {
         return mDownloadManager.getVerticalScrollOffset();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
index 366feb3..45bcb76 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
@@ -14,7 +14,6 @@
 import android.support.v4.widget.DrawerLayout;
 import android.support.v4.widget.DrawerLayout.DrawerListener;
 import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.Toolbar;
 import android.support.v7.widget.Toolbar.OnMenuItemClickListener;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -39,6 +38,7 @@
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController;
 import org.chromium.chrome.browser.widget.selection.SelectableListLayout;
+import org.chromium.chrome.browser.widget.selection.SelectableListToolbar;
 import org.chromium.chrome.browser.widget.selection.SelectableListToolbar.SearchDelegate;
 import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
 import org.chromium.ui.base.DeviceFormFactor;
@@ -305,7 +305,7 @@
     /**
      * See {@link SelectableListLayout#detachToolbarView()}.
      */
-    public Toolbar detachToolbarView() {
+    public SelectableListToolbar detachToolbarView() {
         return mSelectableListLayout.detachToolbarView();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java
index 9870372..74b4d4f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryManager.java
@@ -17,7 +17,6 @@
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.OnScrollListener;
-import android.support.v7.widget.Toolbar;
 import android.support.v7.widget.Toolbar.OnMenuItemClickListener;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
@@ -41,6 +40,7 @@
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController;
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.chrome.browser.widget.selection.SelectableListLayout;
+import org.chromium.chrome.browser.widget.selection.SelectableListToolbar;
 import org.chromium.chrome.browser.widget.selection.SelectableListToolbar.SearchDelegate;
 import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
 import org.chromium.chrome.browser.widget.selection.SelectionDelegate.SelectionObserver;
@@ -227,7 +227,7 @@
     /**
      * See {@link SelectableListLayout#detachToolbarView()}.
      */
-    public Toolbar detachToolbarView() {
+    public SelectableListToolbar detachToolbarView() {
         return mSelectableListLayout.detachToolbarView();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistorySheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistorySheetContent.java
index 635dffd..0c82317 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistorySheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistorySheetContent.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.history;
 
-import android.support.v7.widget.Toolbar;
 import android.view.View;
 
 import org.chromium.chrome.browser.ChromeActivity;
@@ -12,23 +11,30 @@
 import org.chromium.chrome.browser.toolbar.BottomToolbarPhone;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContentController;
+import org.chromium.chrome.browser.widget.selection.SelectableListToolbar;
 
 /**
  * A {@link BottomSheetContent} holding a {@link HistoryManager} for display in the BottomSheet.
  */
 public class HistorySheetContent implements BottomSheetContent {
     private final View mContentView;
-    private final Toolbar mToolbarView;
+    private final SelectableListToolbar mToolbarView;
     private HistoryManager mHistoryManager;
 
     /**
      * @param activity The activity displaying the history manager UI.
      * @param snackbarManager The {@link SnackbarManager} used to display snackbars.
      */
-    public HistorySheetContent(ChromeActivity activity, SnackbarManager snackbarManager) {
+    public HistorySheetContent(final ChromeActivity activity, SnackbarManager snackbarManager) {
         mHistoryManager = new HistoryManager(activity, false, snackbarManager);
         mContentView = mHistoryManager.getView();
         mToolbarView = mHistoryManager.detachToolbarView();
+        mToolbarView.addObserver(new SelectableListToolbar.SelectableListToolbarObserver() {
+            @Override
+            public void onThemeColorChanged(boolean isLightTheme) {
+                activity.getBottomSheet().updateHandleTint();
+            }
+        });
         ((BottomToolbarPhone) activity.getToolbarManager().getToolbar())
                 .setOtherToolbarStyle(mToolbarView);
     }
@@ -44,6 +50,11 @@
     }
 
     @Override
+    public boolean isUsingLightToolbarTheme() {
+        return mToolbarView.isLightTheme();
+    }
+
+    @Override
     public int getVerticalScrollOffset() {
         return mHistoryManager.getVerticalScrollOffset();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoBottomSheetContent.java
index 465102a..ced1746 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoBottomSheetContent.java
@@ -71,6 +71,11 @@
     }
 
     @Override
+    public boolean isUsingLightToolbarTheme() {
+        return false;
+    }
+
+    @Override
     public int getVerticalScrollOffset() {
         return mScrollView.getScrollY();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 6c01ec4..b232c7f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -22,6 +22,7 @@
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.NormalizedAddressRequestDelegate;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
 import org.chromium.chrome.browser.page_info.CertificateChainHelper;
 import org.chromium.chrome.browser.payments.ui.Completable;
@@ -84,11 +85,12 @@
  * Android implementation of the PaymentRequest service defined in
  * components/payments/content/payment_request.mojom.
  */
-public class PaymentRequestImpl
-        implements PaymentRequest, PaymentRequestUI.Client, PaymentApp.InstrumentsCallback,
-                   PaymentInstrument.InstrumentDetailsCallback,
-                   PaymentAppFactory.PaymentAppCreatedCallback,
-                   PaymentResponseHelper.PaymentResponseRequesterDelegate, FocusChangedObserver {
+public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Client,
+                                           PaymentApp.InstrumentsCallback,
+                                           PaymentInstrument.InstrumentDetailsCallback,
+                                           PaymentAppFactory.PaymentAppCreatedCallback,
+                                           PaymentResponseHelper.PaymentResponseRequesterDelegate,
+                                           FocusChangedObserver, NormalizedAddressRequestDelegate {
     /**
      * A test-only observer for the PaymentRequest service implementation.
      */
@@ -974,8 +976,7 @@
             AutofillAddress address = (AutofillAddress) option;
             if (address.isComplete()) {
                 mShippingAddressesSection.setSelectedItem(option);
-                // This updates the line items and the shipping options asynchronously.
-                mClient.onShippingAddressChange(address.toPaymentAddress());
+                startShippingAddressChangeNormalization(address);
             } else {
                 editAddress(address);
             }
@@ -1110,9 +1111,7 @@
                                     PaymentRequestUI.TYPE_CONTACT_DETAILS, mContactSection);
                         }
 
-                        // This updates the line items and the shipping options asynchronously by
-                        // sending the new address to the merchant website.
-                        mClient.onShippingAddressChange(editedAddress.toPaymentAddress());
+                        startShippingAddressChangeNormalization(editedAddress);
                     }
                 } else {
                     providePaymentInformation();
@@ -1593,6 +1592,38 @@
         mUI.updateSection(PaymentRequestUI.TYPE_SHIPPING_ADDRESSES, mShippingAddressesSection);
     }
 
+    @Override
+    public void onAddressNormalized(AutofillProfile profile) {
+        ChromeActivity chromeActivity = ChromeActivity.fromWebContents(mWebContents);
+
+        // Can happen if the tab is closed during the normalization process.
+        if (chromeActivity == null) {
+            recordAbortReasonHistogram(PaymentRequestMetrics.ABORT_REASON_OTHER);
+            disconnectFromClientWithDebugMessage("Unable to find Chrome activity");
+            if (sObserverForTest != null) sObserverForTest.onPaymentRequestServiceShowFailed();
+            return;
+        }
+
+        // Don't reuse the selected address because it is formatted for display.
+        AutofillAddress shippingAddress = new AutofillAddress(chromeActivity, profile);
+
+        // This updates the line items and the shipping options asynchronously.
+        mClient.onShippingAddressChange(shippingAddress.toPaymentAddress());
+    }
+
+    @Override
+    public void onCouldNotNormalize(AutofillProfile profile) {
+        // Since the phone number is formatted in either case, this profile should be used.
+        onAddressNormalized(profile);
+    }
+
+    /** Starts the normalization of the new shipping address. Will call back into either
+     * onAddressNormalized or onCouldNotNormalize which will send the result to the merchant. */
+    private void startShippingAddressChangeNormalization(AutofillAddress address) {
+        PersonalDataManager.getInstance().normalizeAddress(
+                address.getProfile(), AutofillAddress.getCountryCode(address.getProfile()), this);
+    }
+
     /**
      * Closes the UI. If the client is still connected, then it's notified of UI hiding.
      *
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
index 011b54f..9d6131f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
@@ -139,6 +139,11 @@
     }
 
     @Override
+    public boolean isUsingLightToolbarTheme() {
+        return false;
+    }
+
+    @Override
     public int getVerticalScrollOffset() {
         return mRecyclerView.computeVerticalScrollOffset();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
index 314eebe2..26b0d8cb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
@@ -119,6 +119,21 @@
                 context.getResources(), R.drawable.toolbar_handle_light);
     }
 
+    /**
+     * Set the color of the pull handle used by the toolbar.
+     * @param useLightDrawable If the handle color should be light.
+     */
+    public void updateHandleTint(boolean useLightDrawable) {
+        mToolbarHandleView.setImageDrawable(useLightDrawable ? mHandleLight : mHandleDark);
+    }
+
+    /**
+     * @return Whether or not the toolbar is currently using a light theme color.
+     */
+    public boolean isLightTheme() {
+        return !ColorUtils.shouldUseLightForegroundOnBackground(getTabThemeColor());
+    }
+
     @Override
     protected int getProgressBarTopMargin() {
         // In the case where the toolbar is at the bottom of the screen, the progress bar should
@@ -235,8 +250,7 @@
         // The tab switcher's background color should not affect the toolbar handle; it should only
         // switch color based on the static tab's theme color. This is done so fade in/out looks
         // correct.
-        boolean isLight = ColorUtils.shouldUseLightForegroundOnBackground(getTabThemeColor());
-        mToolbarHandleView.setImageDrawable(isLight ? mHandleLight : mHandleDark);
+        mToolbarHandleView.setImageDrawable(isLightTheme() ? mHandleDark : mHandleLight);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index 36c00f1..97b0e44 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -40,6 +40,7 @@
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.toolbar.BottomToolbarPhone;
 import org.chromium.chrome.browser.util.MathUtils;
 import org.chromium.chrome.browser.widget.FadingBackgroundView;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContentController.ContentType;
@@ -193,7 +194,7 @@
      * The default toolbar view. This is shown when the current bottom sheet content doesn't have
      * its own toolbar and when the bottom sheet is closed.
      */
-    private View mDefaultToolbarView;
+    private BottomToolbarPhone mDefaultToolbarView;
 
     /** Whether the {@link BottomSheet} and its children should react to touch events. */
     private boolean mIsTouchEnabled = true;
@@ -227,6 +228,11 @@
         View getToolbarView();
 
         /**
+         * @return Whether or not the toolbar is currently using a lightly colored background.
+         */
+        boolean isUsingLightToolbarTheme();
+
+        /**
          * @return The vertical scroll offset of the content view.
          */
         int getVerticalScrollOffset();
@@ -555,7 +561,22 @@
         mBottomSheetContentContainer.addView(mPlaceholder, placeHolderParams);
 
         mToolbarHolder = (FrameLayout) mControlContainer.findViewById(R.id.toolbar_holder);
-        mDefaultToolbarView = mControlContainer.findViewById(R.id.toolbar);
+        mDefaultToolbarView = (BottomToolbarPhone) mControlContainer.findViewById(R.id.toolbar);
+    }
+
+    /**
+     * Set the color of the pull handle used by the toolbar.
+     */
+    public void updateHandleTint() {
+        boolean isLightToolbarTheme = mDefaultToolbarView.isLightTheme();
+
+        // If the current sheet content's toolbar is using a special theme, use that.
+        if (mSheetContent != null && mSheetContent.getToolbarView() != null) {
+            isLightToolbarTheme = mSheetContent.isUsingLightToolbarTheme();
+        }
+
+        // A light toolbar theme means the handle should be dark.
+        mDefaultToolbarView.updateHandleTint(!isLightToolbarTheme);
     }
 
     @Override
@@ -696,6 +717,7 @@
                     currentToolbar.setVisibility(View.GONE);
                 }
                 mToolbarFadeAnimator = null;
+                updateHandleTint();
             }
         });
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListLayout.java
index 89a815ee..82bda12 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListLayout.java
@@ -17,7 +17,6 @@
 import android.support.v7.widget.RecyclerView.AdapterDataObserver;
 import android.support.v7.widget.RecyclerView.ItemAnimator;
 import android.support.v7.widget.RecyclerView.OnScrollListener;
-import android.support.v7.widget.Toolbar;
 import android.support.v7.widget.Toolbar.OnMenuItemClickListener;
 import android.util.AttributeSet;
 import android.view.Gravity;
@@ -315,7 +314,7 @@
      * elsewhere.
      * @return The toolbar view.
      */
-    public Toolbar detachToolbarView() {
+    public SelectableListToolbar detachToolbarView() {
         removeView(mToolbar);
 
         // The top margin for the content and shadow needs to be removed now that the toolbar
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java
index 74c5980..a483eb00 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java
@@ -27,6 +27,7 @@
 import android.widget.TextView.OnEditorActionListener;
 
 import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.ObserverList;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.widget.NumberRollView;
@@ -68,6 +69,18 @@
         void onEndSearch();
     }
 
+    /**
+     * An interface to observe events on this toolbar.
+     */
+    public interface SelectableListToolbarObserver {
+        /**
+         * A notification that the theme color of the toolbar has changed.
+         * @param isLightTheme Whether or not the toolbar is using a light theme. When this
+         *                     parameter is true, it indicates that dark drawables should be used.
+         */
+        void onThemeColorChanged(boolean isLightTheme);
+    }
+
     /** No navigation button is displayed. **/
     protected static final int NAVIGATION_BUTTON_NONE = 0;
     /** Button to open the DrawerLayout. Only valid if mDrawerLayout is set. **/
@@ -77,6 +90,9 @@
     /** Button to clear the selection. **/
     protected static final int NAVIGATION_BUTTON_SELECTION_BACK = 3;
 
+    /** An observer list for this toolbar. */
+    private final ObserverList<SelectableListToolbarObserver> mObservers = new ObserverList<>();
+
     protected boolean mIsSelectionEnabled;
     protected SelectionDelegate<E> mSelectionDelegate;
     protected boolean mIsSearching;
@@ -86,6 +102,7 @@
     private EditText mSearchEditText;
     private TintedImageButton mClearTextButton;
     private SearchDelegate mSearchDelegate;
+    private boolean mIsLightTheme = true;
 
     protected NumberRollView mNumberRollView;
     private DrawerLayout mDrawerLayout;
@@ -128,6 +145,7 @@
     void destroy() {
         mIsDestroyed = true;
         if (mSelectionDelegate != null) mSelectionDelegate.removeObserver(this);
+        mObservers.clear();
         UiUtils.hideKeyboard(mSearchEditText);
     }
 
@@ -483,6 +501,20 @@
     }
 
     /**
+     * @return Whether or not the toolbar is currently using a light theme.
+     */
+    public boolean isLightTheme() {
+        return mIsLightTheme;
+    }
+
+    /**
+     * @param observer The observer to add to this toolbar.
+     */
+    public void addObserver(SelectableListToolbarObserver observer) {
+        mObservers.addObserver(observer);
+    }
+
+    /**
      * Set up ActionBarDrawerToggle, a.k.a. hamburger button.
      */
     private void initActionBarDrawerToggle() {
@@ -509,6 +541,7 @@
         mNumberRollView.setVisibility(View.GONE);
         mNumberRollView.setNumber(0, false);
 
+        onThemeChanged(true);
         updateDisplayStyleIfNecessary();
     }
 
@@ -528,6 +561,7 @@
 
         if (mIsSearching) UiUtils.hideKeyboard(mSearchEditText);
 
+        onThemeChanged(false);
         updateDisplayStyleIfNecessary();
     }
 
@@ -539,9 +573,19 @@
         setNavigationButton(NAVIGATION_BUTTON_BACK);
         setBackgroundColor(mSearchBackgroundColor);
 
+        onThemeChanged(true);
         updateDisplayStyleIfNecessary();
     }
 
+    /**
+     * Update internal state and notify observers that the theme color changed.
+     * @param isLightTheme Whether or not the theme color is light.
+     */
+    private void onThemeChanged(boolean isLightTheme) {
+        mIsLightTheme = isLightTheme;
+        for (SelectableListToolbarObserver o : mObservers) o.onThemeColorChanged(isLightTheme);
+    }
+
     private void updateDisplayStyleIfNecessary() {
         if (mUiConfig != null) onDisplayStyleChanged(mUiConfig.getCurrentDisplayStyle());
     }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 08fb529d..67973c3 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1508,6 +1508,7 @@
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServerCardTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressTest.java",
+  "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
index bdeecda..6c9620e4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
@@ -24,12 +24,12 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.RetryOnFailure;
+import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.test.ChromeTabbedActivityTestBase;
-import org.chromium.chrome.test.MultiActivityTestBase;
 import org.chromium.chrome.test.util.ApplicationTestUtils;
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.content.browser.test.util.Criteria;
@@ -633,9 +633,25 @@
             }
         }));
 
+        // Defines one gigantic link spanning the whole page that creates a new
+        // window with chrome/test/data/android/google.html.
+        final String hrefLink = UrlUtils.encodeHtmlDataUri("<html>"
+                + "  <head>"
+                + "    <title>href link page</title>"
+                + "    <meta name='viewport'"
+                + "        content='width=device-width initial-scale=0.5, maximum-scale=0.5'>"
+                + "    <style>"
+                + "      body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}"
+                + "    </style>"
+                + "  </head>"
+                + "  <body>"
+                + "    <a href='" + mTestServer.getURL("/chrome/test/data/android/google.html")
+                + "' target='_blank'><div></div></a>"
+                + "  </body>"
+                + "</html>");
+
         // Open a tab via an external application.
-        final Intent intent = new Intent(
-                Intent.ACTION_VIEW, Uri.parse(MultiActivityTestBase.HREF_LINK));
+        final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(hrefLink));
         intent.setClassName(getInstrumentation().getTargetContext().getPackageName(),
                 ChromeTabbedActivity.class.getName());
         intent.putExtra(Browser.EXTRA_APPLICATION_ID, "com.legit.totes");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java
new file mode 100644
index 0000000..4491c2c
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java
@@ -0,0 +1,60 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.payments;
+
+import android.support.test.filters.MediumTest;
+
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A payment integration test for a merchant that requires shipping address to calculate shipping.
+ */
+public class PaymentRequestShippingAddressChangeTest extends PaymentRequestTestBase {
+    public PaymentRequestShippingAddressChangeTest() {
+        // This merchant requests the shipping address first before providing any shipping options.
+        // The result printed from this site is the shipping address change, not the Payment
+        // Response.
+        super("payment_request_shipping_address_change_test.html");
+    }
+
+    @Override
+    public void onMainActivityStarted()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        AutofillTestHelper helper = new AutofillTestHelper();
+        // The user has a shipping address on disk.
+        String billingAddressId = helper.setProfile(new AutofillProfile("", "https://example.com",
+                true, "Jon Doe", "Google", "340 Main St", "California", "Los Angeles", "", "90291",
+                "", "US", "650-253-0000", "", "en-US"));
+        helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
+                "4111111111111111", "1111", "12", "2050", "visa", R.drawable.pr_visa,
+                billingAddressId, "" /* serverId */));
+    }
+
+    /**
+     * Tests the format of the shipping address that is sent to the merchant when the user changes
+     * the shipping address selection.
+     */
+    @MediumTest
+    @Feature({"Payments"})
+    public void testShippingAddressChangeFormat()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        // Select a shipping address and cancel out.
+        triggerUIAndWait(mReadyForInput);
+        clickInShippingSummaryAndWait(R.id.payments_section, mReadyForInput);
+        clickOnShippingAddressSuggestionOptionAndWait(0, mReadyForInput);
+        clickAndWait(R.id.close_button, mDismissed);
+
+        // The phone number should be formatted to the internation format.
+        expectResultContains(new String[] {"Jon Doe", "Google", "340 Main St", "CA", "Los Angeles",
+                "90291", "+16502530000", "US"});
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java
index a1b13303..540f792a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java
@@ -33,6 +33,7 @@
 import org.chromium.content.browser.test.util.JavaScriptUtils;
 import org.chromium.content.browser.test.util.TouchCommon;
 import org.chromium.content_public.common.ScreenOrientationValues;
+import org.chromium.net.test.EmbeddedTestServer;
 
 /**
  * Tests that WebappActivities are launched correctly.
@@ -61,6 +62,8 @@
             + "IWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wQIFB4cxOfiSQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdG"
             + "ggR0lNUFeBDhcAAAAMSURBVAjXY2AUawEAALcAnI/TkI8AAAAASUVORK5CYII=";
 
+    private EmbeddedTestServer mTestServer;
+
     private Intent createIntent(String id, String url, String title, String icon, boolean addMac) {
         Intent intent = new Intent();
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -115,6 +118,14 @@
                                 WEBAPP_1_ID, WEBAPP_1_URL, WEBAPP_1_TITLE, WEBAPP_ICON, true));
                     }
                 });
+
+        mTestServer = EmbeddedTestServer.createAndStartServer(getInstrumentation().getContext());
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mTestServer.stopAndDestroyServer();
+        super.tearDown();
     }
 
     /**
@@ -245,7 +256,7 @@
     @MediumTest
     @Feature({"Webapps"})
     public void testWebappHandlesWindowOpenInTabbedMode() throws Exception {
-        triggerWindowOpenAndWaitForLoad(ChromeTabbedActivity.class, ONCLICK_LINK, true);
+        triggerWindowOpenAndWaitForLoad(ChromeTabbedActivity.class, getOnClickLinkUrl(), true);
     }
 
     /**
@@ -254,7 +265,8 @@
     @MediumTest
     @Feature({"Webapps"})
     public void testWebappHandlesSuppressedWindowOpenInTabbedMode() throws Exception {
-        triggerWindowOpenAndWaitForLoad(ChromeTabbedActivity.class, HREF_NO_REFERRER_LINK, false);
+        triggerWindowOpenAndWaitForLoad(
+                ChromeTabbedActivity.class, getHrefNoReferrerLinkUrl(), false);
     }
 
     private <T extends ChromeActivity> void triggerWindowOpenAndWaitForLoad(
@@ -283,10 +295,10 @@
         };
         ChromeActivity secondActivity = ActivityUtils.waitForActivity(
                 getInstrumentation(), classToWaitFor, fgTrigger);
-        waitForFullLoad(secondActivity, "Page 4");
+        waitForFullLoad(secondActivity, "The Google");
         if (checkContents) {
-            assertEquals("New WebContents was not created",
-                    SUCCESS_URL, firstActivity.getActivityTab().getUrl());
+            assertEquals("New WebContents was not created", "SUCCESS",
+                    firstActivity.getActivityTab().getTitle());
         }
         assertNotSame("Wrong Activity in foreground",
                 firstActivity, ApplicationStatus.getLastTrackedFocusedActivity());
@@ -336,4 +348,49 @@
 
         return true;
     }
+
+    /** Defines one gigantic link spanning the whole page that creates a new
+     *  window with chrome/test/data/android/google.html. Disallowing a referrer from being
+     *  sent triggers another codepath.
+     */
+    private String getHrefNoReferrerLinkUrl() {
+        return UrlUtils.encodeHtmlDataUri("<html>"
+                + "  <head>"
+                + "    <title>href no referrer link page</title>"
+                + "    <meta name='viewport'"
+                + "        content='width=device-width initial-scale=0.5, maximum-scale=0.5'>"
+                + "    <style>"
+                + "      body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}"
+                + "    </style>"
+                + "  </head>"
+                + "  <body>"
+                + "    <a href='" + mTestServer.getURL("/chrome/test/data/android/google.html")
+                + "' target='_blank' rel='noreferrer'><div></div></a>"
+                + "  </body>");
+    }
+
+    /** Returns a URL where clicking the body triggers a window.open() call to open
+     * chrome/test/data/android/google.html. */
+    private String getOnClickLinkUrl() {
+        return UrlUtils.encodeHtmlDataUri("<html>"
+                + "  <head>"
+                + "    <title>window.open page</title>"
+                + "    <meta name='viewport'"
+                + "        content='width=device-width initial-scale=0.5, maximum-scale=0.5'>"
+                + "    <style>"
+                + "      body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}"
+                + "    </style>"
+                + "    <script>"
+                + "      function openNewWindow() {"
+                + "        var site = window.open('"
+                + mTestServer.getURL("/chrome/test/data/android/google.html") + "');"
+                + "        document.title = site ? 'SUCCESS' : 'FAILURE';"
+                + "      }"
+                + "    </script>"
+                + "  </head>"
+                + "  <body id='body'>"
+                + "    <div onclick='openNewWindow()'></div>"
+                + "  </body>"
+                + "</html>");
+    }
 }
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java
index d09e427..aebb750 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java
@@ -15,9 +15,12 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.RetryOnFailure;
+import org.chromium.chrome.browser.TabState;
+import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
+import org.chromium.components.sync.SyncConstants;
 import org.chromium.components.sync.protocol.EntitySpecifics;
 import org.chromium.components.sync.protocol.SessionHeader;
 import org.chromium.components.sync.protocol.SessionSpecifics;
@@ -177,6 +180,26 @@
         waitForLocalTabsForClient(FAKE_CLIENT);
     }
 
+    // Test
+    @LargeTest
+    @Feature({"Sync"})
+    public void testTabGetsValidSyncId() throws Exception {
+        Tab tab = loadUrlInNewTab(URL);
+
+        TabState state = tab.getState();
+        assertFalse(state.syncId == SyncConstants.INVALID_TAB_NODE_ID);
+    }
+
+    // Test
+    @LargeTest
+    @Feature({"Sync"})
+    public void testIncognitoTabGetsInvalidSyncId() throws Exception {
+        Tab tab = loadUrlInNewTab(URL, /*incognito=*/true);
+
+        TabState state = tab.getState();
+        assertEquals(state.syncId, SyncConstants.INVALID_TAB_NODE_ID);
+    }
+
     private String makeSessionTag() {
         return SESSION_TAG_PREFIX + (mSessionTagCounter++);
     }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 9c25080..4936da7 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1926,13 +1926,32 @@
                    desc="Text for the search button in the touch bar when Google is not the default search provider. Pressing the button will bring focus to the omnibox. $1 is the name of the search provider)">
           Search <ph name="SEARCH_ENGINE">$1<ex>Bing</ex></ph>
         </message>
-
         <message name="IDS_TOOLTIP_TOUCH_BAR_BACK" desc="The tooltip for the touch bar back button.">
         Touch to go back.
         </message>
         <message name="IDS_TOOLTIP_TOUCH_BAR_FORWARD" desc="The tooltip for the touch bar forward button.">
         Touch to go forward.
         </message>
+        <message name="IDS_TOUCH_BAR_BACK_FORWARD_CUSTOMIZATION_LABEL"
+                   desc="Customization label for the back and forward buttons in the touch bar.">
+          Back/Forward
+        </message>
+        <message name="IDS_TOUCH_BAR_STOP_RELOAD_CUSTOMIZATION_LABEL"
+                   desc="Customization label for the stop or reload button in the touch bar.">
+          Stop/Reload
+        </message>
+        <message name="IDS_TOUCH_BAR_HOME_CUSTOMIZATION_LABEL"
+                   desc="Customization label for the home button in the touch bar.">
+          Home
+        </message>
+        <message name="IDS_TOUCH_BAR_BOOKMARK_CUSTOMIZATION_LABEL"
+                   desc="Customization label for the bookmark button in the touch bar.">
+          Bookmark
+        </message>
+        <message name="IDS_TOUCH_BAR_NEW_TAB_CUSTOMIZATION_LABEL"
+                   desc="Customization label for the new tab button in the touch bar.">
+          New Tab
+        </message>
       </if>
 
       <!-- Remove in-progress downloads confirmation dialog -->
diff --git a/chrome/browser/android/vr_shell/mailbox_to_surface_bridge.cc b/chrome/browser/android/vr_shell/mailbox_to_surface_bridge.cc
index 18e2ec2..d4ca0340 100644
--- a/chrome/browser/android/vr_shell/mailbox_to_surface_bridge.cc
+++ b/chrome/browser/android/vr_shell/mailbox_to_surface_bridge.cc
@@ -30,9 +30,10 @@
 
 /* clang-format off */
 const char kQuadCopyVertex[] = SHADER(
+    precision mediump float;
     attribute vec4 a_Position;
     attribute vec2 a_TexCoordinate;
-    varying vec2 v_TexCoordinate;
+    varying highp vec2 v_TexCoordinate;
     void main() {
       v_TexCoordinate = a_TexCoordinate;
       gl_Position = a_Position;
diff --git a/chrome/browser/android/vr_shell/vr_shell_renderer.cc b/chrome/browser/android/vr_shell/vr_shell_renderer.cc
index 7951074d..262116cb 100644
--- a/chrome/browser/android/vr_shell/vr_shell_renderer.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_renderer.cc
@@ -77,6 +77,7 @@
     case vr_shell::ShaderID::CONTROLLER_VERTEX_SHADER:
       return SHADER(
           /* clang-format off */
+          precision mediump float;
           uniform mat4 u_ModelViewProjMatrix;
           attribute vec4 a_Position;
           attribute vec2 a_TexCoordinate;
@@ -91,6 +92,7 @@
     case vr_shell::ShaderID::GRADIENT_GRID_VERTEX_SHADER:
       return SHADER(
           /* clang-format off */
+          precision mediump float;
           uniform mat4 u_ModelViewProjMatrix;
           uniform float u_SceneRadius;
           attribute vec4 a_Position;
@@ -122,9 +124,10 @@
     case vr_shell::ShaderID::WEBVR_VERTEX_SHADER:
       return SHADER(
           /* clang-format off */
+          precision mediump float;
           attribute vec3 a_Position;
           attribute vec2 a_TexCoordinate;
-          varying vec2 v_TexCoordinate;
+          varying highp vec2 v_TexCoordinate;
 
           void main() {
             v_TexCoordinate = a_TexCoordinate;
@@ -145,6 +148,7 @@
     case vr_shell::ShaderID::RETICLE_FRAGMENT_SHADER:
       return SHADER(
           /* clang-format off */
+          precision mediump float;
           varying mediump vec2 v_TexCoordinate;
           uniform lowp vec4 color;
           uniform mediump float ring_diameter;
@@ -218,6 +222,7 @@
     case vr_shell::ShaderID::CONTROLLER_FRAGMENT_SHADER:
       return SHADER(
           /* clang-format off */
+          precision mediump float;
           uniform sampler2D u_texture;
           varying vec2 v_TexCoordinate;
 
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 78d27e24..f6e6ec57 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -741,6 +741,12 @@
 
   handoff_active_url_observer_bridge_.reset(
       new HandoffActiveURLObserverBridge(self));
+
+  NSApplication* application = [NSApplication sharedApplication];
+  if ([application respondsToSelector:
+      @selector(setAutomaticCustomizeTouchBarMenuItemEnabled:)]) {
+    [application setAutomaticCustomizeTouchBarMenuItemEnabled:YES];
+  }
 }
 
 // Helper function for populating and displaying the in progress downloads at
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc
index f12f6f06..4971fa68 100644
--- a/chrome/browser/chrome_navigation_browsertest.cc
+++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -189,6 +189,119 @@
             new_web_contents->GetTitle());
 }
 
+// Tests that verify that ctrl-click results 1) open up in a new renderer
+// process (https://crbug.com/23815) and 2) are in a new browsing instance (e.g.
+// cannot find the opener's window by name - https://crbug.com/658386).
+class CtrlClickShouldEndUpInNewProcessTest
+    : public ChromeNavigationBrowserTest {
+ protected:
+  // Simulates ctrl-clicking an anchor with the given id in |main_contents|.
+  // Verifies that the new contents are in a separate process and separate
+  // browsing instance from |main_contents|.  Returns contents of the newly
+  // opened tab.
+  content::WebContents* SimulateCtrlClick(content::WebContents* main_contents,
+                                          const char* id_of_anchor_to_click) {
+    // Ctrl-click the anchor/link in the page.
+    content::WebContents* new_contents = nullptr;
+    {
+      content::WebContentsAddedObserver new_tab_observer;
+#if defined(OS_MACOSX)
+      const char* new_tab_click_script_template =
+          "simulateClick(\"%s\", { metaKey: true });";
+#else
+      const char* new_tab_click_script_template =
+          "simulateClick(\"%s\", { ctrlKey: true });";
+#endif
+      std::string new_tab_click_script = base::StringPrintf(
+          new_tab_click_script_template, id_of_anchor_to_click);
+      EXPECT_TRUE(ExecuteScript(main_contents, new_tab_click_script));
+
+      // Wait for a new tab to appear (the whole point of this test).
+      new_contents = new_tab_observer.GetWebContents();
+    }
+
+    // Verify that the new tab has the right contents and is in the right, new
+    // place in the tab strip.
+    EXPECT_TRUE(WaitForLoadStop(new_contents));
+    int last_tab_index = browser()->tab_strip_model()->count() - 1;
+    EXPECT_LT(1, browser()->tab_strip_model()->count());  // More than 1 tab?
+    EXPECT_EQ(new_contents,
+              browser()->tab_strip_model()->GetWebContentsAt(last_tab_index));
+    GURL expected_url(embedded_test_server()->GetURL("/title1.html"));
+    EXPECT_EQ(expected_url, new_contents->GetLastCommittedURL());
+
+    // Verify that the new tab is in a different process, SiteInstance and
+    // BrowsingInstance from the old contents.
+    EXPECT_NE(main_contents->GetMainFrame()->GetProcess(),
+              new_contents->GetMainFrame()->GetProcess());
+    EXPECT_NE(main_contents->GetMainFrame()->GetSiteInstance(),
+              new_contents->GetMainFrame()->GetSiteInstance());
+    EXPECT_FALSE(main_contents->GetSiteInstance()->IsRelatedSiteInstance(
+        new_contents->GetSiteInstance()));
+
+    // Verify that the new BrowsingInstance can't see windows from the old one.
+    {
+      // Double-check that main_contents has expected window.name set.
+      // This is a sanity check of test setup; this is not a product test.
+      std::string name_of_main_contents_window;
+      EXPECT_TRUE(ExecuteScriptAndExtractString(
+          main_contents, "window.domAutomationController.send(window.name)",
+          &name_of_main_contents_window));
+      EXPECT_EQ("main_contents", name_of_main_contents_window);
+
+      // Verify that the new contents doesn't have a window.opener set.
+      bool window_opener_cast_to_bool;
+      EXPECT_TRUE(ExecuteScriptAndExtractBool(
+          new_contents, "window.domAutomationController.send(!!window.opener)",
+          &window_opener_cast_to_bool));
+      EXPECT_FALSE(window_opener_cast_to_bool);
+
+      // Verify that the new contents cannot find the old contents via
+      // window.open. (i.e. window.open should open a new window, rather than
+      // returning a reference to main_contents / old window).
+      std::string location_of_opened_window;
+      EXPECT_TRUE(ExecuteScriptAndExtractString(
+          new_contents,
+          "w = window.open('', 'main_contents');"
+          "window.domAutomationController.send(w.location.href);",
+          &location_of_opened_window));
+      EXPECT_EQ(url::kAboutBlankURL, location_of_opened_window);
+    }
+
+    return new_contents;
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInNewProcessTest, NoTarget) {
+  // Navigate to the test page.
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/anchor_to_same_site_location.html"));
+  ui_test_utils::NavigateToURL(browser(), main_url);
+  const char* kIdOfAnchorToClick = "test-anchor-no-target";
+
+  // Verify that there is only 1 active tab (with the right contents committed).
+  EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
+  content::WebContents* main_contents =
+      browser()->tab_strip_model()->GetWebContentsAt(0);
+  EXPECT_EQ(main_url, main_contents->GetLastCommittedURL());
+
+  // Test what happens after ctrl-click.  SimulateCtrlClick will verify
+  // that |new_contents1| is in a separate process and browsing instance
+  // from |main_contents|.
+  content::WebContents* new_contents1 =
+      SimulateCtrlClick(main_contents, kIdOfAnchorToClick);
+
+  // Test that each subsequent ctrl-click also gets a new process.
+  content::WebContents* new_contents2 =
+      SimulateCtrlClick(main_contents, kIdOfAnchorToClick);
+  EXPECT_NE(new_contents1->GetMainFrame()->GetProcess(),
+            new_contents2->GetMainFrame()->GetProcess());
+  EXPECT_NE(new_contents1->GetMainFrame()->GetSiteInstance(),
+            new_contents2->GetMainFrame()->GetSiteInstance());
+  EXPECT_FALSE(new_contents1->GetSiteInstance()->IsRelatedSiteInstance(
+      new_contents2->GetSiteInstance()));
+}
+
 class ChromeNavigationPortMappedBrowserTest : public InProcessBrowserTest {
  public:
   ChromeNavigationPortMappedBrowserTest() {}
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
index 5666ce3b..c1ca630 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
@@ -41,6 +41,10 @@
 }  // namespace
 
 // static
+const char ArcVoiceInteractionFrameworkService::kArcServiceName[] =
+    "arc::ArcVoiceInteractionFrameworkService";
+
+// static
 bool ArcVoiceInteractionFrameworkService::IsVoiceInteractionEnabled() {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
       chromeos::switches::kEnableVoiceInteraction);
@@ -75,6 +79,8 @@
 void ArcVoiceInteractionFrameworkService::OnInstanceClosed() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   ash::Shell::Get()->accelerator_controller()->UnregisterAll(this);
+  if (!metalayer_closed_callback_.is_null())
+    base::ResetAndReturn(&metalayer_closed_callback_).Run();
 }
 
 bool ArcVoiceInteractionFrameworkService::AcceleratorPressed(
@@ -82,12 +88,14 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   if (accelerator.IsShiftDown()) {
+    // Temporary, used for debugging.
+    // Does not take into account or update the palette state.
     mojom::VoiceInteractionFrameworkInstance* framework_instance =
         ARC_GET_INSTANCE_FOR_METHOD(
             arc_bridge_service()->voice_interaction_framework(),
-            ToggleMetalayer);
+            SetMetalayerVisibility);
     DCHECK(framework_instance);
-    framework_instance->ToggleMetalayer();
+    framework_instance->SetMetalayerVisibility(true);
   } else {
     mojom::VoiceInteractionFrameworkInstance* framework_instance =
         ARC_GET_INSTANCE_FOR_METHOD(
@@ -136,4 +144,54 @@
                                  base::Bind(&ScreenshotCallback, callback));
 }
 
+void ArcVoiceInteractionFrameworkService::OnMetalayerClosed() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!metalayer_closed_callback_.is_null())
+    base::ResetAndReturn(&metalayer_closed_callback_).Run();
+}
+
+bool ArcVoiceInteractionFrameworkService::IsMetalayerSupported() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  mojom::VoiceInteractionFrameworkInstance* framework_instance =
+      ARC_GET_INSTANCE_FOR_METHOD(
+          arc_bridge_service()->voice_interaction_framework(),
+          SetMetalayerVisibility);
+  return framework_instance;
+}
+
+void ArcVoiceInteractionFrameworkService::ShowMetalayer(
+    const base::Closure& closed) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!metalayer_closed_callback_.is_null()) {
+    LOG(ERROR) << "Metalayer is already enabled";
+    return;
+  }
+  metalayer_closed_callback_ = closed;
+  SetMetalayerVisibility(true);
+}
+
+void ArcVoiceInteractionFrameworkService::HideMetalayer() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (metalayer_closed_callback_.is_null()) {
+    LOG(ERROR) << "Metalayer is already hidden";
+    return;
+  }
+  metalayer_closed_callback_ = base::Closure();
+  SetMetalayerVisibility(false);
+}
+
+void ArcVoiceInteractionFrameworkService::SetMetalayerVisibility(bool visible) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  mojom::VoiceInteractionFrameworkInstance* framework_instance =
+      ARC_GET_INSTANCE_FOR_METHOD(
+          arc_bridge_service()->voice_interaction_framework(),
+          SetMetalayerVisibility);
+  if (!framework_instance) {
+    if (!metalayer_closed_callback_.is_null())
+      base::ResetAndReturn(&metalayer_closed_callback_).Run();
+    return;
+  }
+  framework_instance->SetMetalayerVisibility(visible);
+}
+
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h
index 015acf8..71583e3a 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h
@@ -42,12 +42,23 @@
   void CaptureFocusedWindow(
       const CaptureFocusedWindowCallback& callback) override;
   void CaptureFullscreen(const CaptureFullscreenCallback& callback) override;
+  void OnMetalayerClosed() override;
+
+  bool IsMetalayerSupported();
+  void ShowMetalayer(const base::Closure& closed);
+  void HideMetalayer();
 
   // Whether enable-voice-interaction switch is present.
   static bool IsVoiceInteractionEnabled();
 
+  // For supporting ArcServiceManager::GetService<T>().
+  static const char kArcServiceName[];
+
  private:
+  void SetMetalayerVisibility(bool visible);
+
   mojo::Binding<mojom::VoiceInteractionFrameworkHost> binding_;
+  base::Closure metalayer_closed_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(ArcVoiceInteractionFrameworkService);
 };
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc
index f47bd70..f0de2b0 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc
@@ -23,6 +23,7 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/browser_context.h"
 #include "extensions/browser/api_test_utils.h"
+#include "extensions/browser/extension_function_registry.h"
 #include "extensions/common/extension.h"
 #include "extensions/test/result_catcher.h"
 #include "storage/browser/fileapi/external_mount_points.h"
@@ -69,6 +70,12 @@
   EXPECT_EQ(expected_contents, test_file_contents);
 }
 
+bool OverrideFunction(const std::string& name,
+                      extensions::ExtensionFunctionFactory factory) {
+  return ExtensionFunctionRegistry::GetInstance()->OverrideFunctionForTesting(
+      name, factory);
+}
+
 // Mocks FileSelector used by FileBrowserHandlerInternalSelectFileFunction.
 // When |SelectFile| is called, it will check that file name suggestion is as
 // expected, and respond to the extension function with specified selection
@@ -267,7 +274,7 @@
   SetTestCases(&test_cases);
 
   // Override extension function that will be used during the test.
-  ASSERT_TRUE(extensions::ExtensionFunctionDispatcher::OverrideFunction(
+  ASSERT_TRUE(OverrideFunction(
       "fileBrowserHandlerInternal.selectFile",
       FileBrowserHandlerExtensionTest::TestSelectFileFunctionFactory));
 
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.cc b/chrome/browser/chromeos/login/lock/screen_locker.cc
index 49de8135..e67e5992a 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker.cc
@@ -9,7 +9,6 @@
 
 #include "ash/shell.h"
 #include "ash/wallpaper/wallpaper_controller.h"
-#include "ash/wm/lock_state_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_state_aura.h"
 #include "ash/wm/window_util.h"
@@ -157,12 +156,6 @@
                       bundle.GetRawDataResource(IDR_SOUND_LOCK_WAV));
   manager->Initialize(SOUND_UNLOCK,
                       bundle.GetRawDataResource(IDR_SOUND_UNLOCK_WAV));
-
-  ash::Shell::Get()->lock_state_controller()->SetLockScreenDisplayedCallback(
-      base::Bind(base::IgnoreResult(&AccessibilityManager::PlayEarcon),
-                 base::Unretained(AccessibilityManager::Get()),
-                 chromeos::SOUND_LOCK,
-                 PlaySoundOption::SPOKEN_FEEDBACK_ENABLED));
 }
 
 void ScreenLocker::Init() {
@@ -182,6 +175,10 @@
       new ScreenlockIconSource(screenlock_icon_provider_->AsWeakPtr());
   content::URLDataSource::Add(web_ui()->GetWebContents()->GetBrowserContext(),
                               screenlock_icon_source);
+
+  // Start locking on ash side.
+  SessionControllerClient::Get()->StartLock(base::Bind(
+      &ScreenLocker::OnStartLockCallback, weak_factory_.GetWeakPtr()));
 }
 
 void ScreenLocker::OnAuthFailure(const AuthFailure& error) {
@@ -355,6 +352,19 @@
   return nullptr;
 }
 
+void ScreenLocker::OnStartLockCallback(bool locked) {
+  // Happens in tests that exit with a pending lock. In real lock failure,
+  // ash::LockStateController would cause the current user session to be
+  // terminated.
+  if (!locked)
+    return;
+
+  web_ui()->OnLockAnimationFinished();
+
+  AccessibilityManager::Get()->PlayEarcon(
+      chromeos::SOUND_LOCK, PlaySoundOption::SPOKEN_FEEDBACK_ENABLED);
+}
+
 void ScreenLocker::ClearErrors() {
   web_ui()->ClearErrors();
 }
@@ -412,7 +422,6 @@
   if (g_screen_lock_observer->session_started() &&
       user_manager::UserManager::Get()->CanCurrentUserLock()) {
     ScreenLocker::Show();
-    ash::Shell::Get()->lock_state_controller()->OnStartingLock();
   } else {
     // If the current user's session cannot be locked or the user has not
     // completed all sign-in steps yet, log out instead. The latter is done to
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.h b/chrome/browser/chromeos/login/lock/screen_locker.h
index 07f65bb99..e15ecd6 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.h
+++ b/chrome/browser/chromeos/login/lock/screen_locker.h
@@ -145,6 +145,11 @@
   // Looks up user in unlock user list.
   const user_manager::User* FindUnlockUser(const AccountId& account_id);
 
+  // Callback to be invoked for ash start lock request. |locked| is true when
+  // ash is fully locked and post lock animation finishes. Otherwise, the start
+  // lock request is failed.
+  void OnStartLockCallback(bool locked);
+
   // WebUIScreenLocker instance in use.
   std::unique_ptr<WebUIScreenLocker> web_ui_;
 
diff --git a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
index e4c0251..8b87e22 100644
--- a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/chromeos/login/lock/webui_screen_locker.h"
 
 #include "ash/shell.h"
-#include "ash/shell_port.h"
 #include "ash/system/power/power_event_observer.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
@@ -124,7 +123,6 @@
       network_state_helper_(new login::NetworkStateHelper),
       weak_factory_(this) {
   set_should_emit_login_prompt_visible(false);
-  ash::ShellPort::Get()->AddLockStateObserver(this);
   display::Screen::GetScreen()->AddObserver(this);
   DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
 }
@@ -132,7 +130,6 @@
 WebUIScreenLocker::~WebUIScreenLocker() {
   DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
   display::Screen::GetScreen()->RemoveObserver(this);
-  ash::ShellPort::Get()->RemoveLockStateObserver(this);
   // In case of shutdown, lock_window_ may be deleted before WebUIScreenLocker.
   if (lock_window_) {
     lock_window_->RemoveObserver(this);
@@ -261,6 +258,14 @@
   ash::Shell::Get()->power_event_observer()->OnLockAnimationsComplete();
 }
 
+void WebUIScreenLocker::OnLockAnimationFinished() {
+  // Release capture if any.
+  aura::client::GetCaptureClient(GetNativeWindow()->GetRootWindow())
+      ->SetCapture(nullptr);
+  GetWebUI()->CallJavascriptFunctionUnsafe(
+      "cr.ui.Oobe.animateOnceFullyDisplayed");
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // WebUIScreenLocker, LoginDisplay::Delegate:
 
@@ -344,25 +349,11 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// SessionLockStateObserver:
-
-void WebUIScreenLocker::OnLockStateEvent(
-    ash::LockStateObserver::EventType event) {
-  if (event == ash::LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED) {
-    // Release capture if any.
-    aura::client::GetCaptureClient(GetNativeWindow()->GetRootWindow())->
-        SetCapture(NULL);
-    GetWebUI()->CallJavascriptFunctionUnsafe(
-        "cr.ui.Oobe.animateOnceFullyDisplayed");
-  }
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // WidgetObserver:
 
 void WebUIScreenLocker::OnWidgetDestroying(views::Widget* widget) {
   lock_window_->RemoveObserver(this);
-  lock_window_ = NULL;
+  lock_window_ = nullptr;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/chromeos/login/lock/webui_screen_locker.h b/chrome/browser/chromeos/login/lock/webui_screen_locker.h
index fea1b72..b8b87180 100644
--- a/chrome/browser/chromeos/login/lock/webui_screen_locker.h
+++ b/chrome/browser/chromeos/login/lock/webui_screen_locker.h
@@ -10,7 +10,6 @@
 #include <memory>
 #include <string>
 
-#include "ash/wm/lock_state_observer.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
@@ -45,7 +44,6 @@
 // Displays a WebUI lock screen based on the Oobe account picker screen.
 class WebUIScreenLocker : public WebUILoginView,
                           public LoginDisplay::Delegate,
-                          public ash::LockStateObserver,
                           public views::WidgetObserver,
                           public PowerManagerClient::Observer,
                           public display::DisplayObserver,
@@ -88,6 +86,9 @@
   // Called when the webui header bar becomes visible.
   void OnHeaderBarVisible();
 
+  // Called by ScreenLocker to notify that ash lock animation finishes.
+  void OnLockAnimationFinished();
+
  private:
   friend class test::WebUIScreenLockerTester;
 
@@ -119,9 +120,6 @@
   void Signout() override;
   bool IsUserWhitelisted(const AccountId& account_id) override;
 
-  // LockStateObserver:
-  void OnLockStateEvent(ash::LockStateObserver::EventType event) override;
-
   // WidgetObserver:
   void OnWidgetDestroying(views::Widget* widget) override;
 
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index 844c92e..0f2380d 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -1724,13 +1724,7 @@
 }
 
 // Tests that toolbox window is loaded when DevTools window is undocked.
-// Crashes on Linux only.  https://crbug.com/702641
-#if defined(OS_LINUX)
-#define MAYBE_TestToolboxLoadedUndocked DISABLED_TestToolboxLoadedUndocked
-#else
-#define MAYBE_TestToolboxLoadedUndocked TestToolboxLoadedUndocked
-#endif
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestToolboxLoadedUndocked) {
+IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestToolboxLoadedUndocked) {
   OpenDevToolsWindow(kDebuggerTestPage, false);
   ASSERT_TRUE(toolbox_web_contents());
   DevToolsWindow* on_self =
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index ef9f2557..a9ccfbb 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -621,8 +621,17 @@
     chrome::NavigateParams navigate_params(new_window, url,
                                            ui::PAGE_TRANSITION_LINK);
     navigate_params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+
+    // The next 2 statements put the new contents in the same BrowsingInstance
+    // as their opener.  Note that |force_new_process_for_new_contents = false|
+    // means that new contents might still end up in a new renderer
+    // (if they open a web URL and are transferred out of an extension
+    // renderer), but even in this case the flags below ensure findability via
+    // window.open.
+    navigate_params.force_new_process_for_new_contents = false;
     navigate_params.source_site_instance =
         render_frame_host()->GetSiteInstance();
+
     chrome::Navigate(&navigate_params);
   }
 
diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc
index 17bc023..e0afb588 100644
--- a/chrome/browser/extensions/api/tabs/tabs_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -39,6 +39,7 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/notification_service.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/page_zoom.h"
 #include "content/public/common/url_constants.h"
@@ -2116,7 +2117,7 @@
 }
 
 // Regression test for crbug.com/660498.
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Foo) {
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TemporaryAddressSpoof) {
   ASSERT_TRUE(StartEmbeddedTestServer());
   content::WebContents* first_web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -2144,4 +2145,45 @@
   EXPECT_EQ(url, second_web_contents->GetVisibleURL());
 }
 
+// Window created by chrome.windows.create should be in the same SiteInstance
+// and BrowsingInstance as the opener - this is a regression test for
+// hangouts-vs-isolate-extensions-trouble (see also https://crbug.com/597750).
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowsCreateVsSiteInstance) {
+  const extensions::Extension* extension =
+      LoadExtension(test_data_dir_.AppendASCII("../simple_with_file"));
+  ASSERT_TRUE(extension);
+
+  // Navigate a tab to an extension page.
+  GURL extension_url = extension->GetResourceURL("file.html");
+  ui_test_utils::NavigateToURL(browser(), extension_url);
+  content::WebContents* old_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  // Execute chrome.windows.create and store the new tab in |new_contents|.
+  content::WebContents* new_contents = nullptr;
+  {
+    content::WebContentsAddedObserver observer;
+    ASSERT_TRUE(content::ExecuteScript(old_contents,
+                                       "window.name = 'test-name';\n"
+                                       "chrome.windows.create({url: '" +
+                                           extension_url.spec() + "'})"));
+    new_contents = observer.GetWebContents();
+  }
+
+  // Verify that the old and new tab are in the same process and SiteInstance.
+  // Note: both test assertions are important - one observed failure mode was
+  // having the same process, but different SiteInstance.
+  EXPECT_EQ(old_contents->GetMainFrame()->GetProcess(),
+            new_contents->GetMainFrame()->GetProcess());
+  EXPECT_EQ(old_contents->GetMainFrame()->GetSiteInstance(),
+            new_contents->GetMainFrame()->GetSiteInstance());
+
+  // Verify that the |new_contents| doesn't have a |window.opener| set.
+  bool window_opener_cast_to_bool = true;
+  EXPECT_TRUE(ExecuteScriptAndExtractBool(
+      new_contents, "window.domAutomationController.send(!!window.opener)",
+      &window_opener_cast_to_bool));
+  EXPECT_FALSE(window_opener_cast_to_bool);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index d1ba3ed..f20bc0b 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1209,11 +1209,10 @@
 #if defined(OS_ANDROID)
 
 const char kEnableDataReductionProxyMainMenuName[] =
-    "Enable Data Saver main menu item";
+    "Enable Data Saver main menu footer";
 
 const char kEnableDataReductionProxyMainMenuDescription[] =
-    "Enables the Data Saver menu item in the main menu rather than under "
-    "Settings.";
+    "Enables the Data Saver footer in the main menu";
 
 const char kEnableDataReductionProxySiteBreakdownName[] =
     "Data Saver Site Breakdown";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 41117360..3e28987 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1339,12 +1339,11 @@
 
 #if defined(OS_ANDROID)
 
-// An about:flags experiment title to enable the Data Saver menu item in the
-// main menu rather than under settings on Android
+// An about:flags experiment title to enable the Data Saver footer on Android
 extern const char kEnableDataReductionProxyMainMenuName[];
 
-// Describes an about:flags experiment to enable the Data Saver menu item in the
-// main menu rather than under settings on Android
+// Describes an about:flags experiment to enable the Data Saver footer in the
+// main menu on Android
 extern const char kEnableDataReductionProxyMainMenuDescription[];
 
 // An about:flags experiment title to enable the site breakdown on the Data
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller.cc b/chrome/browser/media/webrtc/media_stream_devices_controller.cc
index c7df704..2a8db3e 100644
--- a/chrome/browser/media/webrtc/media_stream_devices_controller.cc
+++ b/chrome/browser/media/webrtc/media_stream_devices_controller.cc
@@ -357,13 +357,29 @@
 
 void MediaStreamDevicesController::PromptAnswered(ContentSetting setting,
                                                   bool persist) {
-  ContentSetting audio_setting = GetNewSetting(
-      CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, old_audio_setting_, setting);
-  ContentSetting video_setting = GetNewSetting(
-      CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, old_video_setting_, setting);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  if (persist)
-    StorePermission(audio_setting, video_setting);
+  HostContentSettingsMap* host_content_settings_map =
+      HostContentSettingsMapFactory::GetForProfile(profile_);
+  ContentSetting audio_setting = old_audio_setting_;
+  if (old_audio_setting_ == CONTENT_SETTING_ASK) {
+    if (persist && setting != CONTENT_SETTING_ASK) {
+      host_content_settings_map->SetContentSettingDefaultScope(
+          request_.security_origin, GURL(),
+          CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string(), setting);
+    }
+    audio_setting = setting;
+  }
+
+  ContentSetting video_setting = old_video_setting_;
+  if (old_video_setting_ == CONTENT_SETTING_ASK) {
+    if (persist && setting != CONTENT_SETTING_ASK) {
+      host_content_settings_map->SetContentSettingDefaultScope(
+          request_.security_origin, GURL(),
+          CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(), setting);
+    }
+    video_setting = setting;
+  }
 
   content::MediaStreamRequestResult denial_reason = content::MEDIA_DEVICE_OK;
   if (setting == CONTENT_SETTING_ASK)
@@ -455,6 +471,9 @@
     const content::MediaStreamRequest& request,
     const content::MediaResponseCallback& callback)
     : web_contents_(web_contents), request_(request), callback_(callback) {
+  DCHECK(content::IsOriginSecure(request_.security_origin) ||
+         request_.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY);
+
   profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext());
   content_settings_ = TabSpecificContentSettings::FromWebContents(web_contents);
 
@@ -625,28 +644,6 @@
   base::ResetAndReturn(&callback_).Run(devices, request_result, std::move(ui));
 }
 
-void MediaStreamDevicesController::StorePermission(
-    ContentSetting new_audio_setting,
-    ContentSetting new_video_setting) const {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(content::IsOriginSecure(request_.security_origin) ||
-         request_.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY);
-
-  if (IsAskingForAudio() && new_audio_setting != CONTENT_SETTING_ASK) {
-    HostContentSettingsMapFactory::GetForProfile(profile_)
-        ->SetContentSettingDefaultScope(request_.security_origin, GURL(),
-                                        CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
-                                        std::string(), new_audio_setting);
-  }
-  if (IsAskingForVideo() && new_video_setting != CONTENT_SETTING_ASK) {
-    HostContentSettingsMapFactory::GetForProfile(profile_)
-        ->SetContentSettingDefaultScope(
-            request_.security_origin, GURL(),
-            CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(),
-            new_video_setting);
-  }
-}
-
 void MediaStreamDevicesController::UpdateTabSpecificContentSettings(
     ContentSetting audio_setting,
     ContentSetting video_setting) const {
@@ -735,16 +732,6 @@
   return result.content_setting;
 }
 
-ContentSetting MediaStreamDevicesController::GetNewSetting(
-    ContentSettingsType content_type,
-    ContentSetting old_setting,
-    ContentSetting user_decision) const {
-  ContentSetting result = old_setting;
-  if (old_setting == CONTENT_SETTING_ASK)
-    result = user_decision;
-  return result;
-}
-
 bool MediaStreamDevicesController::IsUserAcceptAllowed(
     ContentSettingsType content_type) const {
 #if defined(OS_ANDROID)
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller.h b/chrome/browser/media/webrtc/media_stream_devices_controller.h
index bcf5ce0..4b8dd59 100644
--- a/chrome/browser/media/webrtc/media_stream_devices_controller.h
+++ b/chrome/browser/media/webrtc/media_stream_devices_controller.h
@@ -145,11 +145,6 @@
                    ContentSetting video_setting,
                    content::MediaStreamRequestResult denial_reason);
 
-  // Store the permission to use media devices for the origin of the request.
-  // This is triggered when the user makes a decision.
-  void StorePermission(ContentSetting new_audio_setting,
-                       ContentSetting new_video_setting) const;
-
   // Called when the permission has been set to update the
   // TabSpecificContentSettings.
   void UpdateTabSpecificContentSettings(ContentSetting audio_setting,
@@ -161,14 +156,6 @@
       const content::MediaStreamRequest& request,
       content::MediaStreamRequestResult* denial_reason) const;
 
-  // Returns the content setting that should apply given an old content setting
-  // and a user decision that has been made. If a user isn't being asked for one
-  // of audio/video then we shouldn't change that setting, even if they accept
-  // the dialog.
-  ContentSetting GetNewSetting(ContentSettingsType content_type,
-                               ContentSetting old_setting,
-                               ContentSetting user_decision) const;
-
   // Returns true if clicking allow on the dialog should give access to the
   // requested devices.
   bool IsUserAcceptAllowed(ContentSettingsType content_type) const;
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index d3e6e4b..f2a9a285 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -82,6 +82,7 @@
 #include "net/base/load_flags.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/port_util.h"
+#include "net/dns/mock_host_resolver.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_fetcher.h"
@@ -761,28 +762,18 @@
   clients_.clear();
 }
 
-void SyncTest::SetUpInProcessBrowserTestFixture() {
-  // We don't take a reference to |resolver|, but mock_host_resolver_override_
-  // does, so effectively assumes ownership.
-  net::RuleBasedHostResolverProc* resolver =
-      new net::RuleBasedHostResolverProc(host_resolver());
-  resolver->AllowDirectLookup("*.google.com");
+void SyncTest::SetUpOnMainThread() {
+  host_resolver()->AllowDirectLookup("*.google.com");
 
   // Allow connection to googleapis.com for oauth token requests in E2E tests.
-  resolver->AllowDirectLookup("*.googleapis.com");
+  host_resolver()->AllowDirectLookup("*.googleapis.com");
 
   // On Linux, we use Chromium's NSS implementation which uses the following
   // hosts for certificate verification. Without these overrides, running the
   // integration tests on Linux causes error as we make external DNS lookups.
-  resolver->AllowDirectLookup("*.thawte.com");
-  resolver->AllowDirectLookup("*.geotrust.com");
-  resolver->AllowDirectLookup("*.gstatic.com");
-  mock_host_resolver_override_ =
-      base::MakeUnique<net::ScopedDefaultHostResolverProc>(resolver);
-}
-
-void SyncTest::TearDownInProcessBrowserTestFixture() {
-  mock_host_resolver_override_.reset();
+  host_resolver()->AllowDirectLookup("*.thawte.com");
+  host_resolver()->AllowDirectLookup("*.geotrust.com");
+  host_resolver()->AllowDirectLookup("*.gstatic.com");
 }
 
 void SyncTest::WaitForDataModels(Profile* profile) {
diff --git a/chrome/browser/sync/test/integration/sync_test.h b/chrome/browser/sync/test/integration/sync_test.h
index ba2b818..313ccd37 100644
--- a/chrome/browser/sync/test/integration/sync_test.h
+++ b/chrome/browser/sync/test/integration/sync_test.h
@@ -18,7 +18,6 @@
 #include "components/sync/protocol/sync_protocol_error.h"
 #include "components/sync/test/fake_server/fake_server.h"
 #include "components/sync/test/local_sync_test_server.h"
-#include "net/dns/mock_host_resolver.h"
 #include "net/http/http_status_code.h"
 #include "net/url_request/url_request_status.h"
 
@@ -62,7 +61,6 @@
 
 namespace net {
 class FakeURLFetcherFactory;
-class ScopedDefaultHostResolverProc;
 class URLFetcherImplFactory;
 }  // namespace net
 
@@ -264,18 +262,10 @@
   // on by default yet.
   virtual void AddOptionalTypesToCommandLine(base::CommandLine* cl);
 
-  // BrowserTestBase override. Destroys all the sync clients and sync
-  // profiles created by a test.
+  // BrowserTestBase implementation:
+  void SetUpOnMainThread() override;
   void TearDownOnMainThread() override;
 
-  // InProcessBrowserTest override. Changes behavior of the default host
-  // resolver to avoid DNS lookup errors.
-  void SetUpInProcessBrowserTestFixture() override;
-
-  // InProcessBrowserTest override. Resets the host resolver its default
-  // behavior.
-  void TearDownInProcessBrowserTestFixture() override;
-
   // Implementations of the EnableNotifications() and DisableNotifications()
   // functions defined above.
   void DisableNotificationsImpl();
@@ -456,12 +446,6 @@
   // creation via http requests.
   bool create_gaia_account_at_runtime_;
 
-  // Sync integration tests need to make live DNS requests for access to
-  // GAIA and sync server URLs under google.com. We use a scoped version
-  // to override the default resolver while the test is active.
-  std::unique_ptr<net::ScopedDefaultHostResolverProc>
-      mock_host_resolver_override_;
-
   // Used to start and stop the local test server.
   base::Process test_server_;
 
diff --git a/chrome/browser/ui/ash/palette_delegate_chromeos.cc b/chrome/browser/ui/ash/palette_delegate_chromeos.cc
index b9a52a7..cfa9553 100644
--- a/chrome/browser/ui/ash/palette_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/palette_delegate_chromeos.cc
@@ -179,8 +179,7 @@
   auto* screenshot_controller = ash::Shell::Get()->screenshot_controller();
 
   ash::ScreenshotDelegate* screenshot_delegate;
-  if (arc::ArcVoiceInteractionFrameworkService::IsVoiceInteractionEnabled() &&
-      arc::IsArcAllowedForProfile(profile_)) {
+  if (IsMetalayerSupported()) {
     // This is an experimental mode. It will be either taken out or grow
     // into a separate tool next to "Capture region".
     if (!voice_interaction_screenshot_delegate_) {
@@ -206,4 +205,35 @@
   ash::Shell::Get()->screenshot_controller()->CancelScreenshotSession();
 }
 
+bool PaletteDelegateChromeOS::IsMetalayerSupported() {
+  if (!arc::IsArcAllowedForProfile(profile_))
+    return false;
+
+  arc::ArcVoiceInteractionFrameworkService* service =
+      arc::ArcServiceManager::Get()
+          ->GetService<arc::ArcVoiceInteractionFrameworkService>();
+  return service && service->IsMetalayerSupported();
+}
+
+void PaletteDelegateChromeOS::ShowMetalayer(const base::Closure& closed) {
+  arc::ArcVoiceInteractionFrameworkService* service =
+      arc::ArcServiceManager::Get()
+          ->GetService<arc::ArcVoiceInteractionFrameworkService>();
+  if (!service) {
+    if (!closed.is_null())
+      closed.Run();
+    return;
+  }
+  service->ShowMetalayer(closed);
+}
+
+void PaletteDelegateChromeOS::HideMetalayer() {
+  arc::ArcVoiceInteractionFrameworkService* service =
+      arc::ArcServiceManager::Get()
+          ->GetService<arc::ArcVoiceInteractionFrameworkService>();
+  if (!service)
+    return;
+  service->HideMetalayer();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/ui/ash/palette_delegate_chromeos.h b/chrome/browser/ui/ash/palette_delegate_chromeos.h
index ac059a8..f303e51 100644
--- a/chrome/browser/ui/ash/palette_delegate_chromeos.h
+++ b/chrome/browser/ui/ash/palette_delegate_chromeos.h
@@ -45,6 +45,9 @@
   void TakeScreenshot() override;
   void TakePartialScreenshot(const base::Closure& done) override;
   void CancelPartialScreenshot() override;
+  bool IsMetalayerSupported() override;
+  void ShowMetalayer(const base::Closure& closed) override;
+  void HideMetalayer() override;
 
   // user_manager::UserManager::UserSessionStateObserver:
   void ActiveUserChanged(const user_manager::User* active_user) override;
diff --git a/chrome/browser/ui/ash/session_controller_client.cc b/chrome/browser/ui/ash/session_controller_client.cc
index 3325fa21..693ad99 100644
--- a/chrome/browser/ui/ash/session_controller_client.cc
+++ b/chrome/browser/ui/ash/session_controller_client.cc
@@ -118,6 +118,10 @@
   return g_instance;
 }
 
+void SessionControllerClient::StartLock(StartLockCallback callback) {
+  session_controller_->StartLock(callback);
+}
+
 void SessionControllerClient::RunUnlockAnimation(
     base::Closure animation_finished_callback) {
   session_controller_->RunUnlockAnimation(animation_finished_callback);
diff --git a/chrome/browser/ui/ash/session_controller_client.h b/chrome/browser/ui/ash/session_controller_client.h
index ab9ba3f9..bad771a1 100644
--- a/chrome/browser/ui/ash/session_controller_client.h
+++ b/chrome/browser/ui/ash/session_controller_client.h
@@ -37,6 +37,13 @@
 
   static SessionControllerClient* Get();
 
+  // Calls SessionController to start locking ash. |callback| will be invoked
+  // to indicate whether the lock is successful. If |locked| is true, the post
+  // lock animation is finished and ash is fully locked. Otherwise, the lock
+  // is failed somehow.
+  using StartLockCallback = base::Callback<void(bool locked)>;
+  void StartLock(StartLockCallback callback);
+
   // Calls ash SessionController to run unlock animation.
   // |animation_finished_callback| will be invoked when the animation finishes.
   void RunUnlockAnimation(base::Closure animation_finished_callback);
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index 1a7e806..e8190f6 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -356,7 +356,7 @@
                                            const GURL& url) {
   WebContents::CreateParams create_params(
       params.browser->profile(),
-      params.source_site_instance
+      params.source_site_instance && !params.force_new_process_for_new_contents
           ? params.source_site_instance
           : tab_util::GetSiteInstanceForNewTab(params.browser->profile(), url));
   create_params.main_frame_name = params.frame_name;
diff --git a/chrome/browser/ui/browser_navigator_params.cc b/chrome/browser/ui/browser_navigator_params.cc
index 49b860b..c4a6264 100644
--- a/chrome/browser/ui/browser_navigator_params.cc
+++ b/chrome/browser/ui/browser_navigator_params.cc
@@ -26,6 +26,7 @@
       target_contents(a_target_contents),
       source_contents(nullptr),
       disposition(WindowOpenDisposition::CURRENT_TAB),
+      force_new_process_for_new_contents(false),
       trusted_source(false),
       transition(ui::PAGE_TRANSITION_LINK),
       is_renderer_initiated(false),
@@ -49,6 +50,7 @@
       target_contents(NULL),
       source_contents(NULL),
       disposition(WindowOpenDisposition::CURRENT_TAB),
+      force_new_process_for_new_contents(false),
       trusted_source(false),
       transition(a_transition),
       is_renderer_initiated(false),
@@ -71,6 +73,7 @@
       target_contents(a_target_contents),
       source_contents(NULL),
       disposition(WindowOpenDisposition::CURRENT_TAB),
+      force_new_process_for_new_contents(false),
       trusted_source(false),
       transition(ui::PAGE_TRANSITION_LINK),
       is_renderer_initiated(false),
@@ -96,6 +99,7 @@
       target_contents(NULL),
       source_contents(NULL),
       disposition(WindowOpenDisposition::NEW_FOREGROUND_TAB),
+      force_new_process_for_new_contents(false),
       trusted_source(false),
       transition(a_transition),
       is_renderer_initiated(false),
@@ -126,6 +130,8 @@
   nav_params->redirect_chain = params.redirect_chain;
   nav_params->extra_headers = params.extra_headers;
   nav_params->disposition = params.disposition;
+  nav_params->force_new_process_for_new_contents =
+      params.force_new_process_for_new_contents;
   nav_params->trusted_source = false;
   nav_params->is_renderer_initiated = params.is_renderer_initiated;
   nav_params->should_replace_current_entry =
diff --git a/chrome/browser/ui/browser_navigator_params.h b/chrome/browser/ui/browser_navigator_params.h
index bf40e67..10778a1b 100644
--- a/chrome/browser/ui/browser_navigator_params.h
+++ b/chrome/browser/ui/browser_navigator_params.h
@@ -132,6 +132,12 @@
   // |tabstrip_add_types|.
   WindowOpenDisposition disposition;
 
+  // Controls creation of new web contents (in case |disposition| asks for a new
+  // tab or window).  If |force_new_process_for_new_contents| is true, then we
+  // try to put the new contents in a new renderer, even if they are same-site
+  // as |source_site_instance| (this is subject to renderer process limits).
+  bool force_new_process_for_new_contents;
+
   // Sets browser->is_trusted_source. Default is false.
   bool trusted_source;
 
diff --git a/chrome/browser/ui/cocoa/browser_window_touch_bar.mm b/chrome/browser/ui/cocoa/browser_window_touch_bar.mm
index a840011..d884dd1 100644
--- a/chrome/browser/ui/cocoa/browser_window_touch_bar.mm
+++ b/chrome/browser/ui/cocoa/browser_window_touch_bar.mm
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/mac/foundation_util.h"
 #include "base/mac/mac_util.h"
 #import "base/mac/scoped_nsobject.h"
 #import "base/mac/sdk_forward_declarations.h"
@@ -53,16 +54,15 @@
 };
 
 // The touch bar's identifier.
-const NSTouchBarCustomizationIdentifier kBrowserWindowTouchBarId =
-    @"BrowserWindowTouchBarId";
+NSString* const kBrowserWindowTouchBarId = @"browser-window";
 
 // Touch bar items identifiers.
-const NSTouchBarItemIdentifier kBackForwardTouchId = @"BackForwardTouchId";
-const NSTouchBarItemIdentifier kReloadOrStopTouchId = @"ReloadOrStopTouchId";
-const NSTouchBarItemIdentifier kHomeTouchId = @"HomeTouchId";
-const NSTouchBarItemIdentifier kSearchTouchId = @"SearchTouchId";
-const NSTouchBarItemIdentifier kStarTouchId = @"StarTouchId";
-const NSTouchBarItemIdentifier kNewTabTouchId = @"NewTabTouchId";
+NSString* const kBackForwardTouchId = @"BACK-FWD";
+NSString* const kReloadOrStopTouchId = @"RELOAD-STOP";
+NSString* const kHomeTouchId = @"HOME";
+NSString* const kSearchTouchId = @"SEARCH";
+NSString* const kStarTouchId = @"BOOKMARK";
+NSString* const kNewTabTouchId = @"NEW-TAB";
 
 // The button indexes in the back and forward segment control.
 const int kBackSegmentIndex = 0;
@@ -75,9 +75,8 @@
 // The size of the touch bar icons.
 const int kTouchBarIconSize = 16;
 
-// The width of the search button in the touch bar.
-const int kSearchBtnWidthWithHomeBtn = 205;
-const int kSearchBtnWidthWithoutHomeBtn = 280;
+// The min width of the search button in the touch bar.
+const int kSearchBtnMinWidth = 205;
 
 // Creates an NSImage from the given VectorIcon.
 NSImage* CreateNSImageFromIcon(const gfx::VectorIcon& icon,
@@ -102,6 +101,18 @@
   return button;
 }
 
+NSString* GetTouchBarId(NSString* const touch_bar_id) {
+  NSString* chrome_bundle_id =
+      base::SysUTF8ToNSString(base::mac::BaseBundleID());
+  return [NSString stringWithFormat:@"%@.%@", chrome_bundle_id, touch_bar_id];
+}
+
+NSString* GetTouchBarItemId(NSString* const touch_bar_id,
+                            NSString* const item_id) {
+  return [NSString
+      stringWithFormat:@"%@-%@", GetTouchBarId(touch_bar_id), item_id];
+}
+
 TouchBarAction TouchBarActionFromCommand(int command) {
   switch (command) {
     case IDC_BACK:
@@ -205,22 +216,29 @@
 
   base::scoped_nsobject<NSTouchBar> touchBar(
       [[NSClassFromString(@"NSTouchBar") alloc] init]);
-  NSArray* touchBarItemIdentifiers;
-  if (showHomeButton_.GetValue()) {
-    touchBarItemIdentifiers = @[
-      kBackForwardTouchId, kReloadOrStopTouchId, kHomeTouchId, kSearchTouchId,
-      kStarTouchId, kNewTabTouchId
-    ];
-  } else {
-    touchBarItemIdentifiers = @[
-      kBackForwardTouchId, kReloadOrStopTouchId, kSearchTouchId, kStarTouchId,
-      kNewTabTouchId
-    ];
+  NSMutableArray* customIdentifiers = [NSMutableArray arrayWithCapacity:7];
+  NSMutableArray* defaultIdentifiers = [NSMutableArray arrayWithCapacity:6];
+
+  NSArray* touchBarItems = @[
+    kBackForwardTouchId, kReloadOrStopTouchId, kHomeTouchId, kSearchTouchId,
+    kStarTouchId, kNewTabTouchId
+  ];
+
+  for (NSString* item in touchBarItems) {
+    NSString* itemIdentifier =
+        GetTouchBarItemId(kBrowserWindowTouchBarId, item);
+    [customIdentifiers addObject:itemIdentifier];
+
+    // Don't add the home button if it's not shown in the toolbar.
+    if (showHomeButton_.GetValue() || ![item isEqualTo:kHomeTouchId])
+      [defaultIdentifiers addObject:itemIdentifier];
   }
 
-  [touchBar setCustomizationIdentifier:kBrowserWindowTouchBarId];
-  [touchBar setDefaultItemIdentifiers:touchBarItemIdentifiers];
-  [touchBar setCustomizationAllowedItemIdentifiers:touchBarItemIdentifiers];
+  [customIdentifiers addObject:NSTouchBarItemIdentifierFlexibleSpace];
+
+  [touchBar setCustomizationIdentifier:GetTouchBarId(kBrowserWindowTouchBarId)];
+  [touchBar setDefaultItemIdentifiers:defaultIdentifiers];
+  [touchBar setCustomizationAllowedItemIdentifiers:customIdentifiers];
   [touchBar setDelegate:self];
 
   return touchBar.autorelease();
@@ -233,23 +251,35 @@
 
   base::scoped_nsobject<NSCustomTouchBarItem> touchBarItem([[NSClassFromString(
       @"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier]);
-  if ([identifier isEqualTo:kBackForwardTouchId]) {
+  if ([identifier hasSuffix:kBackForwardTouchId]) {
     [touchBarItem setView:[self backOrForwardTouchBarView]];
-  } else if ([identifier isEqualTo:kReloadOrStopTouchId]) {
+    [touchBarItem setCustomizationLabel:
+                      l10n_util::GetNSString(
+                          IDS_TOUCH_BAR_BACK_FORWARD_CUSTOMIZATION_LABEL)];
+  } else if ([identifier hasSuffix:kReloadOrStopTouchId]) {
     const gfx::VectorIcon& icon =
         isPageLoading_ ? kNavigateStopIcon : kNavigateReloadIcon;
     int commandId = isPageLoading_ ? IDC_STOP : IDC_RELOAD;
     int tooltipId = isPageLoading_ ? IDS_TOOLTIP_STOP : IDS_TOOLTIP_RELOAD;
     [touchBarItem
         setView:CreateTouchBarButton(icon, self, commandId, tooltipId)];
-  } else if ([identifier isEqualTo:kHomeTouchId]) {
+    [touchBarItem setCustomizationLabel:
+                      l10n_util::GetNSString(
+                          IDS_TOUCH_BAR_STOP_RELOAD_CUSTOMIZATION_LABEL)];
+  } else if ([identifier hasSuffix:kHomeTouchId]) {
     [touchBarItem setView:CreateTouchBarButton(kNavigateHomeIcon, self,
                                                IDC_HOME, IDS_TOOLTIP_HOME)];
-  } else if ([identifier isEqualTo:kNewTabTouchId]) {
+    [touchBarItem
+        setCustomizationLabel:l10n_util::GetNSString(
+                                  IDS_TOUCH_BAR_HOME_CUSTOMIZATION_LABEL)];
+  } else if ([identifier hasSuffix:kNewTabTouchId]) {
     [touchBarItem
         setView:CreateTouchBarButton(kNewTabMacTouchbarIcon, self, IDC_NEW_TAB,
                                      IDS_TOOLTIP_NEW_TAB)];
-  } else if ([identifier isEqualTo:kStarTouchId]) {
+    [touchBarItem
+        setCustomizationLabel:l10n_util::GetNSString(
+                                  IDS_TOUCH_BAR_NEW_TAB_CUSTOMIZATION_LABEL)];
+  } else if ([identifier hasSuffix:kStarTouchId]) {
     const gfx::VectorIcon& icon =
         isStarred_ ? toolbar::kStarActiveIcon : toolbar::kStarIcon;
     SkColor iconColor =
@@ -257,8 +287,13 @@
     int tooltipId = isStarred_ ? IDS_TOOLTIP_STARRED : IDS_TOOLTIP_STAR;
     [touchBarItem setView:CreateTouchBarButton(icon, self, IDC_BOOKMARK_PAGE,
                                                tooltipId, iconColor)];
-  } else if ([identifier isEqualTo:kSearchTouchId]) {
+    [touchBarItem
+        setCustomizationLabel:l10n_util::GetNSString(
+                                  IDS_TOUCH_BAR_BOOKMARK_CUSTOMIZATION_LABEL)];
+  } else if ([identifier hasSuffix:kSearchTouchId]) {
     [touchBarItem setView:[self searchTouchBarView]];
+    [touchBarItem setCustomizationLabel:l10n_util::GetNSString(
+                                            IDS_TOUCH_BAR_GOOGLE_SEARCH)];
   }
 
   return touchBarItem.autorelease();
@@ -329,9 +364,12 @@
                          action:@selector(executeCommand:)];
   searchButton.imageHugsTitle = YES;
   searchButton.tag = IDC_FOCUS_LOCATION;
-  int width = showHomeButton_.GetValue() ? kSearchBtnWidthWithHomeBtn
-                                         : kSearchBtnWidthWithoutHomeBtn;
-  [searchButton.widthAnchor constraintEqualToConstant:width].active = YES;
+  [searchButton.widthAnchor
+      constraintGreaterThanOrEqualToConstant:kSearchBtnMinWidth]
+      .active = YES;
+  [searchButton
+      setContentHuggingPriority:1.0
+                 forOrientation:NSLayoutConstraintOrientationHorizontal];
   return searchButton;
 }
 
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm
index 11932109..339f2ebe 100644
--- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm
@@ -409,8 +409,10 @@
                           NSWidth([closeButton frame]) +
                           chrome_style::kCloseButtonPadding;
 
-  bubbleFrame.size.width = std::max(
-      NSWidth(bubbleFrame), std::max(titleRowWidth, maxPermissionLineWidth));
+  bubbleFrame.size.width =
+      std::max(NSWidth(bubbleFrame),
+               std::max(titleRowWidth, maxPermissionLineWidth)) +
+      kHorizontalPadding;
 
   // Now that the bubble's dimensions have been set, lay out the buttons and
   // menus.
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java
index 248cbc47..e6f9f09 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java
@@ -10,7 +10,6 @@
 
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.UrlUtils;
 import org.chromium.base.test.util.parameter.BaseParameter;
 import org.chromium.base.test.util.parameter.Parameter;
 import org.chromium.base.test.util.parameter.Parameterizable;
@@ -38,98 +37,8 @@
         })
 public abstract class MultiActivityTestBase extends InstrumentationTestCase
         implements Parameterizable {
-    protected static final String URL_1 = createTestUrl(1);
-    protected static final String URL_2 = createTestUrl(2);
-    protected static final String URL_3 = createTestUrl(3);
-    protected static final String URL_4 = createTestUrl(4);
-
     private Parameter.Reader mParameterReader;
     private Map<String, BaseParameter> mAvailableParameters;
-
-    /** Defines one gigantic link spanning the whole page that creates a new window with URL_4. */
-    public static final String HREF_LINK = UrlUtils.encodeHtmlDataUri(
-            "<html>"
-            + "  <head>"
-            + "    <title>href link page</title>"
-            + "    <meta name='viewport'"
-            + "        content='width=device-width initial-scale=0.5, maximum-scale=0.5'>"
-            + "    <style>"
-            + "      body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}"
-            + "    </style>"
-            + "  </head>"
-            + "  <body>"
-            + "    <a href='" + URL_4 + "' target='_blank'><div></div></a>"
-            + "  </body>"
-            + "</html>");
-
-    /** Same as HREF_LINK, but disallowing a referrer from being sent triggers another codepath. */
-    protected static final String HREF_NO_REFERRER_LINK = UrlUtils.encodeHtmlDataUri(
-            "<html>"
-            + "  <head>"
-            + "    <title>href no referrer link page</title>"
-            + "    <meta name='viewport'"
-            + "        content='width=device-width initial-scale=0.5, maximum-scale=0.5'>"
-            + "    <style>"
-            + "      body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}"
-            + "    </style>"
-            + "  </head>"
-            + "  <body>"
-            + "    <a href='" + URL_4 + "' target='_blank' rel='noreferrer'><div></div></a>"
-            + "  </body>"
-            + "</html>");
-
-    /** Clicking the body triggers a window.open() call to open URL_4. */
-    protected static final String SUCCESS_URL = UrlUtils.encodeHtmlDataUri("opened!");
-    protected static final String ONCLICK_LINK = UrlUtils.encodeHtmlDataUri(
-            "<html>"
-            + "  <head>"
-            + "    <title>window.open page</title>"
-            + "    <meta name='viewport'"
-            + "        content='width=device-width initial-scale=0.5, maximum-scale=0.5'>"
-            + "    <style>"
-            + "      body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}"
-            + "    </style>"
-            + "    <script>"
-            + "      function openNewWindow() {"
-            + "        var site = window.open('" + URL_4 + "');"
-            + "        if (site) location.href = '" + SUCCESS_URL + "';"
-            + "      }"
-            + "    </script>"
-            + "  </head>"
-            + "  <body id='body'>"
-            + "    <div onclick='openNewWindow()'></div>"
-            + "  </body>"
-            + "</html>");
-
-    /** Opens a new page via window.open(), but get rid of the opener. */
-    protected static final String ONCLICK_NO_REFERRER_LINK = UrlUtils.encodeHtmlDataUri(
-            "<html>"
-            + "  <head>"
-            + "    <title>window.open page, opener set to null</title>"
-            + "    <meta name='viewport'"
-            + "        content='width=device-width initial-scale=0.5, maximum-scale=0.5'>"
-            + "    <style>"
-            + "      body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}"
-            + "    </style>"
-            + "    <script>"
-            + "      function openWithoutReferrer() {"
-            + "        var site = window.open();"
-            + "        site.opener = null;"
-            + "        site.document.open();"
-            + "        site.document.write("
-            + "          '<meta http-equiv=\"refresh\" content=\"0;url=" + URL_4 + "\">');"
-            + "        site.document.close();"
-            + "        if (site) location.href = '" + SUCCESS_URL + "';"
-            + "      }"
-            + "    </script>"
-            + "  </head>"
-            + "  <body>"
-            + "    <a onclick='openWithoutReferrer()'>"
-            + "      <div>The bug that just keeps on coming back.</div>"
-            + "    </a>"
-            + "  </body>"
-            + "</html>");
-
     protected MockStorageDelegate mStorageDelegate;
     protected Context mContext;
 
@@ -243,17 +152,4 @@
     protected Parameter.Reader getParameterReader() {
         return mParameterReader;
     }
-
-    private static final String createTestUrl(int index) {
-        String[] colors = {"#000000", "#ff0000", "#00ff00", "#0000ff", "#ffff00"};
-        return UrlUtils.encodeHtmlDataUri(
-            "<html>"
-            + "  <head>"
-            + "    <title>Page " + index + "</title>"
-            + "    <meta name='viewport' content='width=device-width "
-            + "        initial-scale=0.5 maximum-scale=0.5'>"
-            + "  </head>"
-            + "  <body style='margin: 0em; background: " + colors[index] + ";'></body>"
-            + "</html>");
-    }
 }
diff --git a/chrome/test/data/frame_tree/anchor_to_same_site_location.html b/chrome/test/data/frame_tree/anchor_to_same_site_location.html
new file mode 100644
index 0000000..56ce8037
--- /dev/null
+++ b/chrome/test/data/frame_tree/anchor_to_same_site_location.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<html>
+<head>
+<script>
+window.name = "main_contents";
+function simulateClick(anchor_name, properties) {
+  var evt = new MouseEvent("click", properties);
+
+  target = document.getElementById(anchor_name);
+  return target.dispatchEvent(evt);
+}
+</script>
+</head>
+<body>
+This page helps testing shift-clicking or ctrl-clicking an anchor/link
+that points to the same site.  See also https://crbug.com/23815 and/or
+https://crbug.com/658386.
+<hr>
+<a href="/title1.html"
+   id="test-anchor-no-target">Test link to click while holding ctrl key</a>
+</body>
+</html>
diff --git a/chrome/test/data/payments/payment_request_shipping_address_change_test.html b/chrome/test/data/payments/payment_request_shipping_address_change_test.html
new file mode 100644
index 0000000..c366e4b
--- /dev/null
+++ b/chrome/test/data/payments/payment_request_shipping_address_change_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<!--
+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.
+-->
+<html>
+<head>
+<title>Shipping Address Change Test</title>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<link rel="stylesheet" type="text/css" href="style.css">
+</head>
+<body>
+<button onclick="buy()" id="buy">Shipping Address Change Test</button>
+<pre id="result"></pre>
+<script src="util.js"></script>
+<script src="shipping_address_change.js"></script>
+</body>
+</html>
diff --git a/chrome/test/data/payments/shipping_address_change.js b/chrome/test/data/payments/shipping_address_change.js
new file mode 100644
index 0000000..8bff1ff
--- /dev/null
+++ b/chrome/test/data/payments/shipping_address_change.js
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+/**
+ * Launches the PaymentRequest UI that prints the shipping address received
+ * on shippingAddressChange events at the end of the transaction.
+ */
+function buy() {  // eslint-disable-line no-unused-vars
+  try {
+    var details = {
+      total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
+      displayItems: [
+        {
+          label: 'Pending shipping price',
+          amount: {currency: 'USD', value: '0.00'},
+          pending: true
+        },
+        {
+          label: 'Subtotal',
+          amount: {currency: 'USD', value: '5.00'}
+        }
+      ]
+    };
+
+    var request = new PaymentRequest(
+        [{supportedMethods: ['visa']}], details, {requestShipping: true});
+
+    var shippingAddressChange;
+
+    request.addEventListener('shippingaddresschange', function(evt) {
+      evt.updateWith(new Promise(function(resolve) {
+        print(JSON.stringify(request.shippingAddress, undefined, 2));
+        resolve(details);
+      }));
+    });
+
+    request.show();
+  } catch (error) {
+    print(error.message);
+  }
+}
diff --git a/chromeos/components/tether/BUILD.gn b/chromeos/components/tether/BUILD.gn
index e5bc418..e4ba616 100644
--- a/chromeos/components/tether/BUILD.gn
+++ b/chromeos/components/tether/BUILD.gn
@@ -49,6 +49,8 @@
     "pref_names.h",
     "tether_connector.cc",
     "tether_connector.h",
+    "tether_device_state_manager.cc",
+    "tether_device_state_manager.h",
     "tether_host_fetcher.cc",
     "tether_host_fetcher.h",
     "tether_network_disconnection_handler.cc",
diff --git a/chromeos/components/tether/active_host_network_state_updater_unittest.cc b/chromeos/components/tether/active_host_network_state_updater_unittest.cc
index 2acf577..57e95e5 100644
--- a/chromeos/components/tether/active_host_network_state_updater_unittest.cc
+++ b/chromeos/components/tether/active_host_network_state_updater_unittest.cc
@@ -47,6 +47,8 @@
   void SetUp() override {
     DBusThreadManager::Initialize();
     NetworkStateTest::SetUp();
+    network_state_handler()->SetTetherTechnologyState(
+        NetworkStateHandler::TECHNOLOGY_ENABLED);
     SetUpTetherNetwork();
     SetUpWifiNetwork();
 
diff --git a/chromeos/components/tether/host_scanner_unittest.cc b/chromeos/components/tether/host_scanner_unittest.cc
index e59cb6b..1ca133fc 100644
--- a/chromeos/components/tether/host_scanner_unittest.cc
+++ b/chromeos/components/tether/host_scanner_unittest.cc
@@ -139,6 +139,8 @@
   void SetUp() override {
     DBusThreadManager::Initialize();
     NetworkStateTest::SetUp();
+    network_state_handler()->SetTetherTechnologyState(
+        NetworkStateHandler::TECHNOLOGY_ENABLED);
 
     scanned_device_infos_so_far_.clear();
 
diff --git a/chromeos/components/tether/initializer.cc b/chromeos/components/tether/initializer.cc
index 0eafb693..78a5e42 100644
--- a/chromeos/components/tether/initializer.cc
+++ b/chromeos/components/tether/initializer.cc
@@ -15,6 +15,7 @@
 #include "chromeos/components/tether/local_device_data_provider.h"
 #include "chromeos/components/tether/notification_presenter.h"
 #include "chromeos/components/tether/tether_connector.h"
+#include "chromeos/components/tether/tether_device_state_manager.h"
 #include "chromeos/components/tether/tether_host_fetcher.h"
 #include "chromeos/components/tether/wifi_hotspot_connector.h"
 #include "chromeos/network/network_connect.h"
@@ -152,6 +153,8 @@
   PA_LOG(INFO) << "Successfully set Bluetooth advertisement interval. "
                << "Initializing tether feature.";
 
+  tether_device_state_manager_ =
+      base::MakeUnique<TetherDeviceStateManager>(network_state_handler_);
   tether_host_fetcher_ =
       base::MakeUnique<TetherHostFetcher>(cryptauth_service_);
   local_device_data_provider_ =
diff --git a/chromeos/components/tether/initializer.h b/chromeos/components/tether/initializer.h
index abb4e919..c633bebe 100644
--- a/chromeos/components/tether/initializer.h
+++ b/chromeos/components/tether/initializer.h
@@ -39,6 +39,7 @@
 class LocalDeviceDataProvider;
 class NotificationPresenter;
 class TetherConnector;
+class TetherDeviceStateManager;
 class TetherHostFetcher;
 class WifiHotspotConnector;
 
@@ -94,6 +95,7 @@
   // Declare new objects in the order that they will be created during
   // initialization to ensure that they are destroyed in the correct order. This
   // order will be enforced by InitializerTest.TestCreateAndDestroy.
+  std::unique_ptr<TetherDeviceStateManager> tether_device_state_manager_;
   std::unique_ptr<TetherHostFetcher> tether_host_fetcher_;
   std::unique_ptr<LocalDeviceDataProvider> local_device_data_provider_;
   std::unique_ptr<cryptauth::RemoteBeaconSeedFetcher>
diff --git a/chromeos/components/tether/tether_connector_unittest.cc b/chromeos/components/tether/tether_connector_unittest.cc
index 3384831..dc3ce92 100644
--- a/chromeos/components/tether/tether_connector_unittest.cc
+++ b/chromeos/components/tether/tether_connector_unittest.cc
@@ -148,6 +148,8 @@
   void SetUp() override {
     DBusThreadManager::Initialize();
     NetworkStateTest::SetUp();
+    network_state_handler()->SetTetherTechnologyState(
+        NetworkStateHandler::TECHNOLOGY_ENABLED);
 
     fake_operation_factory_ =
         base::WrapUnique(new FakeConnectTetheringOperationFactory());
diff --git a/chromeos/components/tether/tether_device_state_manager.cc b/chromeos/components/tether/tether_device_state_manager.cc
new file mode 100644
index 0000000..a8c561e
--- /dev/null
+++ b/chromeos/components/tether/tether_device_state_manager.cc
@@ -0,0 +1,38 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/components/tether/tether_device_state_manager.h"
+
+#include "chromeos/network/network_state_handler.h"
+
+namespace chromeos {
+
+namespace tether {
+
+TetherDeviceStateManager::TetherDeviceStateManager(
+    NetworkStateHandler* network_state_handler)
+    : network_state_handler_(network_state_handler) {
+  network_state_handler_->AddObserver(this, FROM_HERE);
+
+  // TODO(hansberry): Set the appropriate value. For now, always set ENABLED.
+  network_state_handler_->SetTetherTechnologyState(
+      NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED);
+}
+
+TetherDeviceStateManager::~TetherDeviceStateManager() {
+  network_state_handler_->RemoveObserver(this, FROM_HERE);
+
+  // TODO(hansberry): Determine if this should be PROHIBITED or UNAVAILABLE
+  // based on reason for shutting down.
+  network_state_handler_->SetTetherTechnologyState(
+      NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE);
+}
+
+void TetherDeviceStateManager::DeviceListChanged() {
+  // TODO(hansberry): Implement.
+}
+
+}  // namespace tether
+
+}  // namespace chromeos
diff --git a/chromeos/components/tether/tether_device_state_manager.h b/chromeos/components/tether/tether_device_state_manager.h
new file mode 100644
index 0000000..4f05e70
--- /dev/null
+++ b/chromeos/components/tether/tether_device_state_manager.h
@@ -0,0 +1,48 @@
+// 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 CHROMEOS_COMPONENTS_TETHER_TETHER_DEVICE_STATE_MANAGER_H_
+#define CHROMEOS_COMPONENTS_TETHER_TETHER_DEVICE_STATE_MANAGER_H_
+
+#include "base/macros.h"
+#include "chromeos/network/network_state_handler.h"
+#include "chromeos/network/network_state_handler_observer.h"
+
+namespace chromeos {
+
+class NetworkStateHandler;
+
+namespace tether {
+
+// Manages the device state of tether networks. The tether state is:
+//   *TECHNOLOGY_PROHIBITED when tethering is disallowed by policy.
+//   *TECHNOLOGY_UNAVAILABLE when tethering is allowed by policy, but either
+//    the device has no Bluetooth capabilities or the logged-in user has no
+//    tether hosts associated with their account.
+//   *TECHNOLOGY_AVAILABLE when tethering is allowed by policy, the device has
+//    Bluetooth capabilities, the logged-in user has tether hosts associated
+//    with their account, but the Instant Tethering setting is disabled.
+//   *TECHNOLOGY_ENABLED when tethering is allowed by policy, the device has
+//    Bluetooth capabilities, the logged-in user has tether hosts associated
+//    with their account, and the Instant Tethering setting is enabled.
+// TODO(hansberry): Complete this class description when implemented.
+class TetherDeviceStateManager : public NetworkStateHandlerObserver {
+ public:
+  explicit TetherDeviceStateManager(NetworkStateHandler* network_state_handler);
+  ~TetherDeviceStateManager() override;
+
+  // NetworkStateHandlerObserver:
+  void DeviceListChanged() override;
+
+ private:
+  NetworkStateHandler* network_state_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(TetherDeviceStateManager);
+};
+
+}  // namespace tether
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_TETHER_TETHER_DEVICE_STATE_MANAGER_H_
diff --git a/chromeos/network/device_state.h b/chromeos/network/device_state.h
index 97ebd0b9..59bd3d82 100644
--- a/chromeos/network/device_state.h
+++ b/chromeos/network/device_state.h
@@ -35,6 +35,7 @@
   // Accessors
   const std::string& mac_address() const { return mac_address_; }
   bool scanning() const { return scanning_; }
+  void set_scanning(bool scanning) { scanning_ = scanning; }
 
   // Cellular specific accessors
   const std::string& home_provider_id() const { return home_provider_id_; }
diff --git a/chromeos/network/managed_state.h b/chromeos/network/managed_state.h
index 1fe17c8..9573af708 100644
--- a/chromeos/network/managed_state.h
+++ b/chromeos/network/managed_state.h
@@ -112,6 +112,7 @@
 
  private:
   friend class NetworkChangeNotifierChromeosUpdateTest;
+  friend class NetworkStateHandler;
 
   ManagedType managed_type_;
 
diff --git a/chromeos/network/network_connect_unittest.cc b/chromeos/network/network_connect_unittest.cc
index 930b3d0..2eb4d44 100644
--- a/chromeos/network/network_connect_unittest.cc
+++ b/chromeos/network/network_connect_unittest.cc
@@ -336,6 +336,9 @@
 TEST_F(NetworkConnectTest, ConnectToTetherNetwork) {
   EXPECT_CALL(*mock_tether_delegate_, ConnectToNetwork(kTether1Guid));
 
+  NetworkHandler::Get()->network_state_handler()->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_ENABLED);
+
   NetworkHandler::Get()->network_state_handler()->AddTetherNetworkState(
       kTether1Guid, "TetherNetwork", "Carrier", 100 /* battery_percentage */,
       100 /* signal_strength */);
@@ -347,6 +350,9 @@
 TEST_F(NetworkConnectTest, ConnectToTetherNetwork_TetherNetworkDoesNotExist) {
   EXPECT_CALL(*mock_tether_delegate_, ConnectToNetwork(_)).Times(0);
 
+  NetworkHandler::Get()->network_state_handler()->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_ENABLED);
+
   NetworkConnect::Get()->SetTetherDelegate(mock_tether_delegate_.get());
   NetworkConnect::Get()->ConnectToNetworkId(kTether1Guid);
 }
@@ -354,6 +360,9 @@
 TEST_F(NetworkConnectTest, ConnectToTetherNetwork_TetherDelegateNotSet) {
   EXPECT_CALL(*mock_tether_delegate_, ConnectToNetwork(_)).Times(0);
 
+  NetworkHandler::Get()->network_state_handler()->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_ENABLED);
+
   NetworkHandler::Get()->network_state_handler()->AddTetherNetworkState(
       kTether1Guid, "TetherNetwork", "Carrier", 100 /* battery_percentage */,
       100 /* signal_strength */);
diff --git a/chromeos/network/network_connection_handler.cc b/chromeos/network/network_connection_handler.cc
index 81d3492..7f372d7 100644
--- a/chromeos/network/network_connection_handler.cc
+++ b/chromeos/network/network_connection_handler.cc
@@ -118,6 +118,8 @@
 const char NetworkConnectionHandler::kErrorUnmanagedNetwork[] =
     "unmanaged-network";
 const char NetworkConnectionHandler::kErrorActivateFailed[] = "activate-failed";
+const char NetworkConnectionHandler::kEnabledOrDisabledWhenNotAvailable[] =
+    "not-available";
 
 struct NetworkConnectionHandler::ConnectRequest {
   ConnectRequest(const std::string& service_path,
diff --git a/chromeos/network/network_connection_handler.h b/chromeos/network/network_connection_handler.h
index af76d47f..e7e86d47 100644
--- a/chromeos/network/network_connection_handler.h
+++ b/chromeos/network/network_connection_handler.h
@@ -102,6 +102,9 @@
   // Network activation failed.
   static const char kErrorActivateFailed[];
 
+  // Network was enabled/disabled when it was not available.
+  static const char kEnabledOrDisabledWhenNotAvailable[];
+
   ~NetworkConnectionHandler() override;
 
   void AddObserver(NetworkConnectionObserver* observer);
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc
index 3268f9f..39ebed6 100644
--- a/chromeos/network/network_state_handler.cc
+++ b/chromeos/network/network_state_handler.cc
@@ -21,7 +21,9 @@
 #include "base/values.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/network/device_state.h"
+#include "chromeos/network/network_connection_handler.h"
 #include "chromeos/network/network_event_log.h"
+#include "chromeos/network/network_handler_callbacks.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler_observer.h"
 #include "chromeos/network/tether_constants.h"
@@ -126,9 +128,7 @@
   std::string technology = GetTechnologyForType(type);
 
   if (technology == kTypeTether) {
-    bool is_tether_enabled = base::CommandLine::ForCurrentProcess()->HasSwitch(
-        chromeos::switches::kEnableTether);
-    return is_tether_enabled ? TECHNOLOGY_ENABLED : TECHNOLOGY_UNAVAILABLE;
+    return tether_technology_state_;
   }
 
   TechnologyState state;
@@ -154,6 +154,25 @@
     const network_handler::ErrorCallback& error_callback) {
   std::vector<std::string> technologies = GetTechnologiesForType(type);
   for (const std::string& technology : technologies) {
+    if (technology == kTypeTether) {
+      if (tether_technology_state_ != TECHNOLOGY_ENABLED &&
+          tether_technology_state_ != TECHNOLOGY_AVAILABLE) {
+        NET_LOG(ERROR) << "SetTechnologyEnabled() called for the Tether "
+                       << "DeviceState, but the current state was not "
+                       << "TECHNOLOGY_ENABLED or TECHNOLOGY_AVAILABLE.";
+        network_handler::RunErrorCallback(
+            error_callback, kTetherDevicePath,
+            NetworkConnectionHandler::kEnabledOrDisabledWhenNotAvailable, "");
+        continue;
+      }
+
+      // Tether does not exist in Shill, so set |tether_technology_state_| and
+      // skip the below interactions with |shill_property_handler_|.
+      tether_technology_state_ =
+          enabled ? TECHNOLOGY_ENABLED : TECHNOLOGY_AVAILABLE;
+      continue;
+    }
+
     if (!shill_property_handler_->IsTechnologyAvailable(technology))
       continue;
     NET_LOG_USER("SetTechnologyEnabled",
@@ -165,11 +184,54 @@
   NotifyDeviceListChanged();
 }
 
+void NetworkStateHandler::SetTetherTechnologyState(
+    TechnologyState technology_state) {
+  if (tether_technology_state_ == technology_state)
+    return;
+
+  tether_technology_state_ = technology_state;
+  EnsureTetherDeviceState();
+
+  // Signal Device/Technology state changed.
+  NotifyDeviceListChanged();
+}
+
+void NetworkStateHandler::SetTetherScanState(bool is_scanning) {
+  DeviceState* tether_device_state =
+      GetModifiableDeviceState(kTetherDevicePath);
+  DCHECK(tether_device_state);
+
+  bool was_scanning = tether_device_state->scanning();
+  tether_device_state->set_scanning(is_scanning);
+
+  if (was_scanning && !is_scanning) {
+    // If a scan was in progress but has completed, notify observers.
+    NotifyScanCompleted(tether_device_state);
+  }
+}
+
 void NetworkStateHandler::SetProhibitedTechnologies(
     const std::vector<std::string>& prohibited_technologies,
     const network_handler::ErrorCallback& error_callback) {
-  shill_property_handler_->SetProhibitedTechnologies(prohibited_technologies,
-                                                     error_callback);
+  // Make a copy of |prohibited_technologies| since the list may be edited
+  // within this function.
+  std::vector<std::string> prohibited_technologies_copy =
+      prohibited_technologies;
+
+  for (auto it = prohibited_technologies_copy.begin();
+       it < prohibited_technologies_copy.end(); ++it) {
+    if (*it == kTypeTether) {
+      // If Tether networks are prohibited, set |tether_technology_state_| and
+      // remove |kTypeTether| from the list before passing it to
+      // |shill_property_handler_| below. Shill does not have a concept of
+      // Tether networks, so it cannot prohibit that technology type.
+      tether_technology_state_ = TECHNOLOGY_PROHIBITED;
+      it = prohibited_technologies_copy.erase(it);
+    }
+  }
+
+  shill_property_handler_->SetProhibitedTechnologies(
+      prohibited_technologies_copy, error_callback);
   // Signal Device/Technology state changed.
   NotifyDeviceListChanged();
 }
@@ -300,7 +362,7 @@
   if (!network_list_sorted_)
     SortNetworkList();  // Sort to ensure visible networks are listed first.
 
-  // If |type| matches tether networks and at least one tether network is
+  // If |type| matches Tether networks and at least one Tether network is
   // present, return the first network (since it has been sorted already).
   if (type.MatchesPattern(NetworkTypePattern::Tether()) &&
       !tether_network_list_.empty()) {
@@ -323,9 +385,14 @@
 std::string NetworkStateHandler::FormattedHardwareAddressForType(
     const NetworkTypePattern& type) const {
   const NetworkState* network = ConnectedNetworkByType(type);
+  if (network && network->type() == kTypeTether) {
+    // If this is a Tether network, get the MAC address corresponding to that
+    // network instead.
+    network = GetNetworkStateFromGuid(network->tether_guid());
+  }
   const DeviceState* device = network ? GetDeviceState(network->device_path())
                                       : GetDeviceStateByType(type);
-  if (!device)
+  if (!device || device->mac_address().empty())
     return std::string();
   return network_util::FormattedMacAddress(device->mac_address());
 }
@@ -361,7 +428,7 @@
 
   if (type.Equals(NetworkTypePattern::Tether()) ||
       (limit != 0 && count >= limit)) {
-    // If only searching for tether networks, there is no need to continue
+    // If only searching for Tether networks, there is no need to continue
     // searching through other network types; likewise, if the limit has already
     // been reached, there is no need to continue searching.
     return;
@@ -432,6 +499,12 @@
   DCHECK(battery_percentage >= 0 && battery_percentage <= 100);
   DCHECK(signal_strength >= 0 && signal_strength <= 100);
 
+  if (tether_technology_state_ != TECHNOLOGY_ENABLED) {
+    NET_LOG(ERROR) << "AddTetherNetworkState() called when Tether networks "
+                   << "are not enabled. Cannot add NetworkState.";
+    return;
+  }
+
   // If the network already exists, do nothing.
   if (GetNetworkStateFromGuid(guid)) {
     NET_LOG(ERROR) << "AddTetherNetworkState: " << name
@@ -463,6 +536,12 @@
     const std::string& carrier,
     int battery_percentage,
     int signal_strength) {
+  if (tether_technology_state_ != TECHNOLOGY_ENABLED) {
+    NET_LOG(ERROR) << "UpdateTetherNetworkProperties() called when Tether "
+                   << "networks are not enabled. Cannot update.";
+    return false;
+  }
+
   NetworkState* tether_network_state = GetModifiableNetworkStateFromGuid(guid);
   if (!tether_network_state)
     return false;
@@ -494,6 +573,13 @@
 bool NetworkStateHandler::AssociateTetherNetworkStateWithWifiNetwork(
     const std::string& tether_network_guid,
     const std::string& wifi_network_guid) {
+  if (tether_technology_state_ != TECHNOLOGY_ENABLED) {
+    NET_LOG(ERROR) << "AssociateTetherNetworkStateWithWifiNetwork() called "
+                   << "when Tether networks are not enabled. Cannot "
+                   << "associate.";
+    return false;
+  }
+
   NetworkState* tether_network =
       GetModifiableNetworkStateFromGuid(tether_network_guid);
   if (!tether_network) {
@@ -525,14 +611,14 @@
 
 void NetworkStateHandler::SetTetherNetworkStateDisconnected(
     const std::string& guid) {
-  // TODO(khorimoto): Remove the tether network as the default network, and
+  // TODO(khorimoto): Remove the Tether network as the default network, and
   // send a connection status change.
   SetTetherNetworkStateConnectionState(guid, shill::kStateDisconnect);
 }
 
 void NetworkStateHandler::SetTetherNetworkStateConnecting(
     const std::string& guid) {
-  // TODO(khorimoto): Set the tether network as the default network, and send
+  // TODO(khorimoto): Set the Tether network as the default network, and send
   // a connection status change.
   SetTetherNetworkStateConnectionState(guid, shill::kStateConfiguration);
 }
@@ -564,6 +650,41 @@
   NotifyNetworkListChanged();
 }
 
+void NetworkStateHandler::EnsureTetherDeviceState() {
+  bool should_be_present =
+      tether_technology_state_ != TechnologyState::TECHNOLOGY_UNAVAILABLE;
+
+  for (auto it = device_list_.begin(); it < device_list_.end(); ++it) {
+    std::string path = (*it)->path();
+    if (path == kTetherDevicePath) {
+      // If the Tether DeviceState is in the list and it should not be, remove
+      // it and return. If it is in the list and it should be, the list is
+      // already valid, so return without removing it.
+      if (!should_be_present)
+        device_list_.erase(it);
+      return;
+    }
+  }
+
+  if (!should_be_present) {
+    // If the Tether DeviceState was not in the list and it should not be, the
+    // list is already valid, so return.
+    return;
+  }
+
+  // The Tether DeviceState is not present in the list, but it should be. Since
+  // Tether networks are not recognized by Shill, they will never receive an
+  // update, so set properties on the state here.
+  std::unique_ptr<ManagedState> tether_device_state = ManagedState::Create(
+      ManagedState::ManagedType::MANAGED_TYPE_DEVICE, kTetherDevicePath);
+  tether_device_state->set_update_received();
+  tether_device_state->set_update_requested(false);
+  tether_device_state->set_name(kTetherDeviceName);
+  tether_device_state->set_type(kTypeTether);
+
+  device_list_.push_back(std::move(tether_device_state));
+}
+
 void NetworkStateHandler::GetDeviceList(DeviceStateList* list) const {
   GetDeviceListByType(NetworkTypePattern::Default(), list);
 }
@@ -572,6 +693,7 @@
                                               DeviceStateList* list) const {
   DCHECK(list);
   list->clear();
+
   for (auto iter = device_list_.begin(); iter != device_list_.end(); ++iter) {
     const DeviceState* device = (*iter)->AsDeviceState();
     DCHECK(device);
@@ -726,6 +848,17 @@
     list_entries.insert(path);
   }
 
+  if (type == ManagedState::ManagedType::MANAGED_TYPE_DEVICE) {
+    // Also move the Tether DeviceState if it exists. This will not happen as
+    // part of the loop above since |entries| will never contain the Tether
+    // path.
+    auto iter = managed_map.find(kTetherDevicePath);
+    if (iter != managed_map.end()) {
+      managed_list->push_back(std::move(iter->second));
+      managed_map.erase(iter);
+    }
+  }
+
   if (type != ManagedState::ManagedType::MANAGED_TYPE_NETWORK)
     return;
 
@@ -971,7 +1104,7 @@
   }
 }
 
-// TODO(khorimoto): Add sorting for the tether network list as well.
+// TODO(khorimoto): Add sorting for the Tether network list as well.
 void NetworkStateHandler::SortNetworkList() {
   // Note: usually active networks will precede inactive networks, however
   // this may briefly be untrue during state transitions (e.g. a network may
@@ -1275,6 +1408,8 @@
     technologies.emplace_back(shill::kTypeBluetooth);
   if (type.MatchesType(shill::kTypeVPN))
     technologies.emplace_back(shill::kTypeVPN);
+  if (type.MatchesType(kTypeTether))
+    technologies.emplace_back(kTypeTether);
 
   CHECK_GT(technologies.size(), 0ul);
   return technologies;
diff --git a/chromeos/network/network_state_handler.h b/chromeos/network/network_state_handler.h
index 3265b00..b35887b 100644
--- a/chromeos/network/network_state_handler.h
+++ b/chromeos/network/network_state_handler.h
@@ -112,6 +112,17 @@
       bool enabled,
       const network_handler::ErrorCallback& error_callback);
 
+  // Sets the tether technology state. Because Tether networks do not represent
+  // real Shill networks, this value must be set by the tether component rather
+  // than being generated by Shill. See TetherDeviceStateManager for more
+  // details.
+  void SetTetherTechnologyState(TechnologyState technology_state);
+
+  // Sets the scanning state of the tether technology. Since tether network
+  // scans are not actually performed as part of Shill, this value must be set
+  // by the tether component.
+  void SetTetherScanState(bool is_scanning);
+
   // Asynchronously sets the list of prohibited technologies. The accepted
   // values are the shill network technology identifiers. See also
   // chromeos::onc::Validator::ValidateGlobalNetworkConfiguration().
@@ -250,7 +261,9 @@
                            DeviceStateList* list) const;
 
   // Requests a network scan. This may trigger updates to the network
-  // list, which will trigger the appropriate observer calls.
+  // list, which will trigger the appropriate observer calls. Note that this
+  // function does not request a tether scan.
+  // TODO(khorimoto): Add ability to request a tether scan as well.
   void RequestScan() const;
 
   // Requests an update for an existing NetworkState, e.g. after configuring
@@ -259,7 +272,7 @@
   // acknowledged it (e.g. in the callback of a SetProperties).
   // When the properties are received, NetworkPropertiesUpdated will be
   // signaled for each member of |observers_|, regardless of whether any
-  // properties actually changed.
+  // properties actually changed. Note that this is a no-op for Tether networks.
   void RequestUpdateForNetwork(const std::string& service_path);
 
   // Informs NetworkStateHandler to notify observers that the properties for
@@ -452,6 +465,11 @@
       const std::string& guid,
       const std::string& connection_state);
 
+  // Ensures that the Tether DeviceState is present in |device_list_| if
+  // |tether_technology_state_| is not TECHNOLOGY_UNAVAILABLE and ensures that
+  // it is not present in |device_list_| if it is TECHNOLOGY_UNAVAILABLE.
+  void EnsureTetherDeviceState();
+
   // Shill property handler instance, owned by this class.
   std::unique_ptr<internal::ShillPropertyHandler> shill_property_handler_;
 
@@ -482,6 +500,11 @@
   // NetworkState that is not saved in a profile.
   SpecifierGuidMap specifier_guid_map_;
 
+  // The state corresponding to the tether device type. This value is managed by
+  // the tether component.
+  TechnologyState tether_technology_state_ =
+      TechnologyState::TECHNOLOGY_UNAVAILABLE;
+
   // Ensure that Shutdown() gets called exactly once.
   bool did_shutdown_ = false;
 
diff --git a/chromeos/network/network_state_handler_unittest.cc b/chromeos/network/network_state_handler_unittest.cc
index 0d1df22..0502606b 100644
--- a/chromeos/network/network_state_handler_unittest.cc
+++ b/chromeos/network/network_state_handler_unittest.cc
@@ -28,6 +28,7 @@
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
 #include "chromeos/network/network_state_handler_observer.h"
+#include "chromeos/network/tether_constants.h"
 #include "dbus/object_path.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
@@ -73,8 +74,8 @@
         device_count_(0),
         network_list_changed_count_(0),
         network_count_(0),
-        default_network_change_count_(0) {
-  }
+        default_network_change_count_(0),
+        scan_completed_count_(0) {}
 
   ~TestObserver() override {}
 
@@ -125,6 +126,11 @@
     device_property_updates_[device->path()]++;
   }
 
+  void ScanCompleted(const DeviceState* device) override {
+    DCHECK(device);
+    scan_completed_count_++;
+  }
+
   size_t device_list_changed_count() { return device_list_changed_count_; }
   size_t device_count() { return device_count_; }
   size_t network_list_changed_count() { return network_list_changed_count_; }
@@ -132,11 +138,13 @@
   size_t default_network_change_count() {
     return default_network_change_count_;
   }
+  size_t scan_completed_count() { return scan_completed_count_; }
   void reset_change_counts() {
     DVLOG(1) << "=== RESET CHANGE COUNTS ===";
     default_network_change_count_ = 0;
     device_list_changed_count_ = 0;
     network_list_changed_count_ = 0;
+    scan_completed_count_ = 0;
     connection_state_changes_.clear();
   }
   void reset_updates() {
@@ -172,6 +180,7 @@
   size_t network_list_changed_count_;
   size_t network_count_;
   size_t default_network_change_count_;
+  size_t scan_completed_count_;
   std::string default_network_;
   std::string default_network_connection_state_;
   std::map<std::string, int> property_updates_;
@@ -330,6 +339,9 @@
 }
 
 TEST_F(NetworkStateHandlerTest, GetNetworkList) {
+  network_state_handler_->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_ENABLED);
+
   // Ensure that the network list is the expected size.
   const size_t kNumShillManagerClientStubImplServices = 4;
   EXPECT_EQ(kNumShillManagerClientStubImplServices,
@@ -415,6 +427,9 @@
 }
 
 TEST_F(NetworkStateHandlerTest, GetTetherNetworkList) {
+  network_state_handler_->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_ENABLED);
+
   NetworkStateHandler::NetworkStateList tether_networks;
 
   GetTetherNetworkList(0 /* no limit */, &tether_networks);
@@ -568,13 +583,80 @@
   EXPECT_EQ(
       NetworkStateHandler::TECHNOLOGY_UNAVAILABLE,
       network_state_handler_->GetTechnologyState(NetworkTypePattern::Tether()));
+  EXPECT_FALSE(network_state_handler_->GetDeviceState(kTetherDevicePath));
+  EXPECT_FALSE(network_state_handler_->GetDeviceStateByType(
+      NetworkTypePattern::Tether()));
 
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      chromeos::switches::kEnableTether);
+  // Test SetTetherTechnologyState():
+  network_state_handler_->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_AVAILABLE);
+  EXPECT_EQ(1u, test_observer_->device_list_changed_count());
+  EXPECT_EQ(
+      NetworkStateHandler::TECHNOLOGY_AVAILABLE,
+      network_state_handler_->GetTechnologyState(NetworkTypePattern::Tether()));
+  const DeviceState* tether_device_state =
+      network_state_handler_->GetDeviceState(kTetherDevicePath);
+  EXPECT_TRUE(tether_device_state);
+  EXPECT_EQ(tether_device_state, network_state_handler_->GetDeviceStateByType(
+                                     NetworkTypePattern::Tether()));
 
+  // Test SetTechnologyEnabled() with a tether network:
+  network_state_handler_->SetTechnologyEnabled(
+      NetworkTypePattern::Tether(), true, network_handler::ErrorCallback());
+  EXPECT_EQ(2u, test_observer_->device_list_changed_count());
   EXPECT_EQ(
       NetworkStateHandler::TECHNOLOGY_ENABLED,
       network_state_handler_->GetTechnologyState(NetworkTypePattern::Tether()));
+  EXPECT_EQ(tether_device_state,
+            network_state_handler_->GetDeviceState(kTetherDevicePath));
+  EXPECT_EQ(tether_device_state, network_state_handler_->GetDeviceStateByType(
+                                     NetworkTypePattern::Tether()));
+
+  // Test SetProhibitedTechnologies() with a tether network:
+  network_state_handler_->SetProhibitedTechnologies(
+      std::vector<std::string>{kTypeTether}, network_handler::ErrorCallback());
+  EXPECT_EQ(3u, test_observer_->device_list_changed_count());
+  EXPECT_EQ(
+      NetworkStateHandler::TECHNOLOGY_PROHIBITED,
+      network_state_handler_->GetTechnologyState(NetworkTypePattern::Tether()));
+  EXPECT_EQ(tether_device_state,
+            network_state_handler_->GetDeviceState(kTetherDevicePath));
+  EXPECT_EQ(tether_device_state, network_state_handler_->GetDeviceStateByType(
+                                     NetworkTypePattern::Tether()));
+
+  // Set back to TECHNOLOGY_UNAVAILABLE; this should result in nullptr being
+  // returned by getters.
+  network_state_handler_->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_UNAVAILABLE);
+  EXPECT_FALSE(network_state_handler_->GetDeviceState(kTetherDevicePath));
+  EXPECT_FALSE(network_state_handler_->GetDeviceStateByType(
+      NetworkTypePattern::Tether()));
+}
+
+TEST_F(NetworkStateHandlerTest, TetherScanningState) {
+  network_state_handler_->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_ENABLED);
+
+  const DeviceState* tether_device_state =
+      network_state_handler_->GetDeviceStateByType(
+          NetworkTypePattern::Tether());
+  EXPECT_TRUE(tether_device_state);
+  EXPECT_FALSE(tether_device_state->scanning());
+  EXPECT_EQ(0u, test_observer_->scan_completed_count());
+
+  network_state_handler_->SetTetherScanState(true /* is_scanning */);
+  tether_device_state = network_state_handler_->GetDeviceStateByType(
+      NetworkTypePattern::Tether());
+  EXPECT_TRUE(tether_device_state);
+  EXPECT_TRUE(tether_device_state->scanning());
+  EXPECT_EQ(0u, test_observer_->scan_completed_count());
+
+  network_state_handler_->SetTetherScanState(false /* is_scanning */);
+  tether_device_state = network_state_handler_->GetDeviceStateByType(
+      NetworkTypePattern::Tether());
+  EXPECT_TRUE(tether_device_state);
+  EXPECT_FALSE(tether_device_state->scanning());
+  EXPECT_EQ(1u, test_observer_->scan_completed_count());
 }
 
 TEST_F(NetworkStateHandlerTest, ServicePropertyChanged) {
@@ -625,6 +707,9 @@
 }
 
 TEST_F(NetworkStateHandlerTest, TetherNetworkState) {
+  network_state_handler_->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_ENABLED);
+
   EXPECT_EQ(0u, test_observer_->network_list_changed_count());
 
   network_state_handler_->AddTetherNetworkState(
@@ -671,6 +756,9 @@
 }
 
 TEST_F(NetworkStateHandlerTest, TetherNetworkStateAssociation) {
+  network_state_handler_->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_ENABLED);
+
   EXPECT_EQ(0u, test_observer_->network_list_changed_count());
 
   const std::string profile = "/profile/profile1";
@@ -712,6 +800,9 @@
 }
 
 TEST_F(NetworkStateHandlerTest, TetherNetworkStateAssociationWifiRemoved) {
+  network_state_handler_->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_ENABLED);
+
   const std::string profile = "/profile/profile1";
   const std::string wifi_path = "/service/wifi_with_guid";
   AddService(wifi_path, kWifiGuid1, kWifiName1, shill::kTypeWifi,
@@ -744,6 +835,9 @@
 }
 
 TEST_F(NetworkStateHandlerTest, TetherNetworkStateAssociation_NoWifiNetwork) {
+  network_state_handler_->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_ENABLED);
+
   network_state_handler_->AddTetherNetworkState(
       kTetherGuid1, kTetherName1, kTetherCarrier1, kTetherBatteryPercentage1,
       kTetherSignalStrength1);
@@ -754,6 +848,9 @@
 }
 
 TEST_F(NetworkStateHandlerTest, TetherNetworkStateAssociation_NoTetherNetwork) {
+  network_state_handler_->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_ENABLED);
+
   const std::string profile = "/profile/profile1";
   const std::string wifi_path = "/service/wifi_with_guid";
   AddService(wifi_path, kWifiGuid1, kWifiName1, shill::kTypeWifi,
@@ -768,6 +865,9 @@
 }
 
 TEST_F(NetworkStateHandlerTest, SetTetherNetworkStateConnectionState) {
+  network_state_handler_->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_ENABLED);
+
   network_state_handler_->AddTetherNetworkState(
       kTetherGuid1, kTetherName1, kTetherCarrier1, kTetherBatteryPercentage1,
       kTetherSignalStrength1);
diff --git a/chromeos/network/tether_constants.cc b/chromeos/network/tether_constants.cc
index 70867b5a1..72fd96b 100644
--- a/chromeos/network/tether_constants.cc
+++ b/chromeos/network/tether_constants.cc
@@ -10,5 +10,7 @@
 const char kTetherBatteryPercentage[] = "Tether.BatteryPercentage";
 const char kTetherCarrier[] = "Tether.Carrier";
 const char kTetherSignalStrength[] = "Tether.SignalStrength";
+const char kTetherDevicePath[] = "tether-device-path";
+const char kTetherDeviceName[] = "tether-name";
 
 }  // namespace chromeos
diff --git a/chromeos/network/tether_constants.h b/chromeos/network/tether_constants.h
index 26b4f21d..4d73d1d 100644
--- a/chromeos/network/tether_constants.h
+++ b/chromeos/network/tether_constants.h
@@ -22,6 +22,12 @@
 CHROMEOS_EXPORT extern const char kTetherCarrier[];
 CHROMEOS_EXPORT extern const char kTetherSignalStrength[];
 
+// The device path used for the tether DeviceState.
+CHROMEOS_EXPORT extern const char kTetherDevicePath[];
+
+// The name used for the tether DeviceState.
+CHROMEOS_EXPORT extern const char kTetherDeviceName[];
+
 }  // namespace chromeos
 
 #endif  // CHROMEOS_NETWORK_TETHER_CONSTANTS_H_
diff --git a/components/arc/common/voice_interaction_framework.mojom b/components/arc/common/voice_interaction_framework.mojom
index adf25f4..38fb2ec 100644
--- a/components/arc/common/voice_interaction_framework.mojom
+++ b/components/arc/common/voice_interaction_framework.mojom
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Next MinVersion: 2
+// Next MinVersion: 3
 
 module arc.mojom;
 
 import "screen_rect.mojom";
 
 // Handles voice interaction queries from Android.
-// Next method ID: 2
+// Next method ID: 3
 interface VoiceInteractionFrameworkHost {
   // Returns a screenshot of currently focused window or empty array if
   // no window is focused.
@@ -17,10 +17,13 @@
 
   // Returns a fullscreen screenshot of the primary display.
   [MinVersion=1]CaptureFullscreen@1() => (array<uint8> png_data);
+
+  // Notifies the host that the metalayer has closed or could not open.
+  [MinVersion=2]OnMetalayerClosed@2();
 };
 
 // Connects with Android system server.
-// Next method ID:4
+// Next method ID: 4
 interface VoiceInteractionFrameworkInstance {
   Init@0(VoiceInteractionFrameworkHost host_ptr);
 
@@ -31,6 +34,6 @@
   // selected.
   [MinVersion=1] StartVoiceInteractionSessionForRegion@2(ScreenRect region);
 
-  // Toggles the metalayer.
-  [MinVersion=1] ToggleMetalayer@3();
+  // Shows/hides the metalayer in the container.
+  [MinVersion=1] SetMetalayerVisibility@3([MinVersion=2] bool visible);
 };
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
index 6e09db8..fd4f3f6 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
@@ -7,8 +7,7 @@
 namespace data_reduction_proxy {
 namespace features {
 
-// Enables the Data Reduction Proxy menu item in the main menu rather than under
-// Settings on Android.
+// Enables the Data Reduction Proxy footer in the main menu on Android.
 const base::Feature kDataReductionMainMenu{"DataReductionProxyMainMenu",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/components/storage_monitor/media_storage_util.cc b/components/storage_monitor/media_storage_util.cc
index 5dbfdcc..7841e4e29 100644
--- a/components/storage_monitor/media_storage_util.cc
+++ b/components/storage_monitor/media_storage_util.cc
@@ -9,7 +9,6 @@
 #include "base/callback.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
@@ -23,19 +22,6 @@
 
 namespace {
 
-// MediaDeviceNotification.DeviceInfo histogram values.
-enum DeviceInfoHistogramBuckets {
-  MASS_STORAGE_DEVICE_NAME_AND_UUID_AVAILABLE,
-  MASS_STORAGE_DEVICE_UUID_MISSING,
-  MASS_STORAGE_DEVICE_NAME_MISSING,
-  MASS_STORAGE_DEVICE_NAME_AND_UUID_MISSING,
-  MTP_STORAGE_DEVICE_NAME_AND_UUID_AVAILABLE,
-  MTP_STORAGE_DEVICE_UUID_MISSING,
-  MTP_STORAGE_DEVICE_NAME_MISSING,
-  MTP_STORAGE_DEVICE_NAME_AND_UUID_MISSING,
-  DEVICE_INFO_BUCKET_BOUNDARY
-};
-
 #if !defined(OS_WIN)
 const char kRootPath[] = "/";
 #endif
@@ -213,30 +199,6 @@
 }
 
 // static
-void MediaStorageUtil::RecordDeviceInfoHistogram(
-    bool mass_storage,
-    const std::string& device_uuid,
-    const base::string16& device_label) {
-  unsigned int event_number = 0;
-  if (!mass_storage)
-    event_number = 4;
-
-  if (device_label.empty())
-    event_number += 2;
-
-  if (device_uuid.empty())
-    event_number += 1;
-  enum DeviceInfoHistogramBuckets event =
-      static_cast<enum DeviceInfoHistogramBuckets>(event_number);
-  if (event >= DEVICE_INFO_BUCKET_BOUNDARY) {
-    NOTREACHED();
-    return;
-  }
-  UMA_HISTOGRAM_ENUMERATION("MediaDeviceNotifications.DeviceInfo", event,
-                            DEVICE_INFO_BUCKET_BOUNDARY);
-}
-
-// static
 bool MediaStorageUtil::IsRemovableStorageAttached(const std::string& id) {
   StorageMonitor* monitor = StorageMonitor::GetInstance();
   if (!monitor)
diff --git a/components/storage_monitor/media_storage_util.h b/components/storage_monitor/media_storage_util.h
index 99c14d6..6b0bb74 100644
--- a/components/storage_monitor/media_storage_util.h
+++ b/components/storage_monitor/media_storage_util.h
@@ -50,13 +50,6 @@
   // the device is connected.
   static base::FilePath FindDevicePathById(const std::string& device_id);
 
-  // Record device information histogram for the given |device_uuid| and
-  // |device_label|. |mass_storage| indicates whether the current device is a
-  // mass storage device, as defined by IsMassStorageDevice().
-  static void RecordDeviceInfoHistogram(bool mass_storage,
-                                        const std::string& device_uuid,
-                                        const base::string16& device_label);
-
   // Returns true if the |id| is both a removable device and also
   // currently attached.
   static bool IsRemovableStorageAttached(const std::string& id);
diff --git a/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc b/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc
index 0616199..3a67e27 100644
--- a/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc
+++ b/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc
@@ -11,7 +11,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
-#include "components/storage_monitor/media_storage_util.h"
 #include "components/storage_monitor/removable_device_constants.h"
 #include "device/media_transfer_protocol/mtp_storage_info.pb.h"
 
@@ -202,10 +201,6 @@
                            &storage_label, &location, &vendor_name,
                            &product_name);
 
-    // Keep track of device id and device name to see how often we receive
-    // empty values.
-    MediaStorageUtil::RecordDeviceInfoHistogram(false, device_id,
-                                                storage_label);
     if (device_id.empty() || storage_label.empty())
       return;
 
diff --git a/components/storage_monitor/portable_device_watcher_win.cc b/components/storage_monitor/portable_device_watcher_win.cc
index 44d2885..368c4cf2 100644
--- a/components/storage_monitor/portable_device_watcher_win.cc
+++ b/components/storage_monitor/portable_device_watcher_win.cc
@@ -20,7 +20,6 @@
 #include "base/win/scoped_co_mem.h"
 #include "base/win/scoped_comptr.h"
 #include "base/win/scoped_propvariant.h"
-#include "components/storage_monitor/media_storage_util.h"
 #include "components/storage_monitor/removable_device_constants.h"
 #include "components/storage_monitor/storage_info.h"
 #include "content/public/browser/browser_thread.h"
@@ -632,9 +631,6 @@
     const std::string& storage_id = storage_iter->object_persistent_id;
     DCHECK(!base::ContainsKey(storage_map_, storage_id));
 
-    // Keep track of storage id and storage name to see how often we receive
-    // empty values.
-    MediaStorageUtil::RecordDeviceInfoHistogram(false, storage_id, name);
     if (storage_id.empty() || name.empty())
       return;
 
diff --git a/components/storage_monitor/storage_monitor_chromeos.cc b/components/storage_monitor/storage_monitor_chromeos.cc
index 228cc440..edce2a5 100644
--- a/components/storage_monitor/storage_monitor_chromeos.cc
+++ b/components/storage_monitor/storage_monitor_chromeos.cc
@@ -57,10 +57,6 @@
     return false;
 
   std::string unique_id = MakeDeviceUniqueId(*disk);
-  // Keep track of device uuid and label, to see how often we receive empty
-  // values.
-  base::string16 device_label = base::UTF8ToUTF16(disk->device_label());
-  MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, device_label);
   if (unique_id.empty())
     return false;
 
@@ -68,12 +64,11 @@
       StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM :
       StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM;
 
-  *info = StorageInfo(StorageInfo::MakeDeviceId(type, unique_id),
-                      mount_info.mount_path,
-                      device_label,
-                      base::UTF8ToUTF16(disk->vendor_name()),
-                      base::UTF8ToUTF16(disk->product_name()),
-                      disk->total_size_in_bytes());
+  *info = StorageInfo(
+      StorageInfo::MakeDeviceId(type, unique_id), mount_info.mount_path,
+      base::UTF8ToUTF16(disk->device_label()),
+      base::UTF8ToUTF16(disk->vendor_name()),
+      base::UTF8ToUTF16(disk->product_name()), disk->total_size_in_bytes());
   return true;
 }
 
diff --git a/components/storage_monitor/storage_monitor_linux.cc b/components/storage_monitor/storage_monitor_linux.cc
index 1bbffa9..f0f53d7 100644
--- a/components/storage_monitor/storage_monitor_linux.cc
+++ b/components/storage_monitor/storage_monitor_linux.cc
@@ -15,6 +15,7 @@
 
 #include "base/bind.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/process/kill.h"
 #include "base/process/launch.h"
@@ -54,11 +55,6 @@
 // Construct a device id using label or manufacturer (vendor and model) details.
 std::string MakeDeviceUniqueId(struct udev_device* device) {
   std::string uuid = device::UdevDeviceGetPropertyValue(device, kFsUUID);
-  // Keep track of device uuid, to see how often we receive empty uuid values.
-  UMA_HISTOGRAM_BOOLEAN(
-      "RemovableDeviceNotificationsLinux.device_file_system_uuid_available",
-      !uuid.empty());
-
   if (!uuid.empty())
     return kFSUniqueIdPrefix + uuid;
 
@@ -104,12 +100,6 @@
   const std::string partition_size =
       device::UdevDeviceGetSysattrValue(device, kSizeSysAttr);
 
-  // Keep track of device size, to see how often this information is
-  // unavailable.
-  UMA_HISTOGRAM_BOOLEAN(
-      "RemovableDeviceNotificationsLinux.device_partition_size_available",
-      !partition_size.empty());
-
   uint64_t total_size_in_bytes = 0;
   if (!base::StringToUint64(partition_size, &total_size_in_bytes))
     return 0;
@@ -158,10 +148,6 @@
       device::UdevDeviceGetPropertyValue(device.get(), kModel));
 
   std::string unique_id = MakeDeviceUniqueId(device.get());
-
-  // Keep track of device info details to see how often we get invalid values.
-  MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, volume_label);
-
   const char* value =
       device::udev_device_get_sysattr_value(device.get(), kRemovableSysAttr);
   if (!value) {
@@ -179,21 +165,17 @@
 
   StorageInfo::Type type = StorageInfo::FIXED_MASS_STORAGE;
   if (is_removable) {
-    if (MediaStorageUtil::HasDcim(mount_point))
-      type = StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM;
-    else
-      type = StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM;
+    type = MediaStorageUtil::HasDcim(mount_point)
+               ? StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM
+               : StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM;
   }
 
   results_recorder.set_result(true);
 
-  storage_info.reset(new StorageInfo(
-      StorageInfo::MakeDeviceId(type, unique_id),
-      mount_point.value(),
-      volume_label,
-      vendor_name,
-      model_name,
-      GetDeviceStorageSize(device_path, device.get())));
+  storage_info = base::MakeUnique<StorageInfo>(
+      StorageInfo::MakeDeviceId(type, unique_id), mount_point.value(),
+      volume_label, vendor_name, model_name,
+      GetDeviceStorageSize(device_path, device.get()));
   return storage_info;
 }
 
diff --git a/components/storage_monitor/storage_monitor_mac.mm b/components/storage_monitor/storage_monitor_mac.mm
index 47d9135..a48b024 100644
--- a/components/storage_monitor/storage_monitor_mac.mm
+++ b/components/storage_monitor/storage_monitor_mac.mm
@@ -238,8 +238,6 @@
       disk_info_map_.erase(it);
   } else {
     disk_info_map_[bsd_name] = info;
-    MediaStorageUtil::RecordDeviceInfoHistogram(true, info.device_id(),
-                                                info.storage_label());
     if (ShouldPostNotificationForDisk(info))
       receiver()->ProcessAttach(info);
   }
diff --git a/components/storage_monitor/volume_mount_watcher_win.cc b/components/storage_monitor/volume_mount_watcher_win.cc
index 5ac0b11..17e7a630 100644
--- a/components/storage_monitor/volume_mount_watcher_win.cc
+++ b/components/storage_monitor/volume_mount_watcher_win.cc
@@ -16,7 +16,6 @@
 #include <algorithm>
 
 #include "base/bind_helpers.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -47,15 +46,6 @@
   FIXED,
 };
 
-// Histogram values for recording frequencies of eject attempts and
-// outcomes.
-enum EjectWinLockOutcomes {
-  LOCK_ATTEMPT,
-  LOCK_TIMEOUT,
-  LOCK_TIMEOUT2,
-  NUM_LOCK_OUTCOMES,
-};
-
 // We are trying to figure out whether the drive is a fixed volume,
 // a removable storage, or a floppy. A "floppy" here means "a volume we
 // want to basically ignore because it won't fit media and will spin
@@ -262,12 +252,7 @@
   // handle is closed, and this is done by the ScopedHandle above.
   BOOL locked = DeviceIoControl(volume_handle.Get(), FSCTL_LOCK_VOLUME,
                                 NULL, 0, NULL, 0, &bytes_returned, NULL);
-  UMA_HISTOGRAM_ENUMERATION("StorageMonitor.EjectWinLock",
-                            LOCK_ATTEMPT, NUM_LOCK_OUTCOMES);
   if (!locked) {
-    UMA_HISTOGRAM_ENUMERATION("StorageMonitor.EjectWinLock",
-                              iteration == 0 ? LOCK_TIMEOUT : LOCK_TIMEOUT2,
-                              NUM_LOCK_OUTCOMES);
     const int kNumLockRetries = 1;
     const base::TimeDelta kLockRetryInterval =
         base::TimeDelta::FromMilliseconds(500);
diff --git a/components/sync/protocol/session_specifics.proto b/components/sync/protocol/session_specifics.proto
index 04df7d31..622309b 100644
--- a/components/sync/protocol/session_specifics.proto
+++ b/components/sync/protocol/session_specifics.proto
@@ -155,6 +155,18 @@
   }
   // Whether the Password Manager saw a password field on the page.
   optional PasswordState password_state = 26;
+
+  // The id for the task associated with this navigation, which is globally
+  // unique with high probability.
+  // Similar with global_id, but used to identify a navigation in Chrome Tasks,
+  // so navigations of a page have the same task_id if one is the first visit of
+  // the page, and others are its back/forward visits.
+  optional int64 task_id = 27;
+  // Task ids of all ancestor navigations, which can be from other tabs, from
+  // root to parent. We define navigation A is parent of navigation B if page of
+  // B is got by clicking a link on page of A. This relationship is used to
+  // define a Chrome Task as a tree rooted by a navigation.
+  repeated int64 ancestor_task_id = 28;
 }
 
 // Navigation information for a single redirection within a single navigation.
diff --git a/components/sync_sessions/BUILD.gn b/components/sync_sessions/BUILD.gn
index 8d912876..7212996 100644
--- a/components/sync_sessions/BUILD.gn
+++ b/components/sync_sessions/BUILD.gn
@@ -48,6 +48,8 @@
     "synced_window_delegates_getter.h",
     "tab_node_pool.cc",
     "tab_node_pool.h",
+    "task_tracker.cc",
+    "task_tracker.h",
   ]
 
   public_deps = [
@@ -104,6 +106,7 @@
     "sync_sessions_metrics_unittest.cc",
     "synced_session_tracker_unittest.cc",
     "tab_node_pool_unittest.cc",
+    "task_tracker_unittest.cc",
   ]
 
   deps = [
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc
index f37c1b3..f985b3db 100644
--- a/components/sync_sessions/sessions_sync_manager.cc
+++ b/components/sync_sessions/sessions_sync_manager.cc
@@ -156,7 +156,8 @@
       local_event_router_(std::move(router)),
       page_revisit_broadcaster_(this, sessions_client),
       sessions_updated_callback_(sessions_updated_callback),
-      datatype_refresh_callback_(datatype_refresh_callback) {}
+      datatype_refresh_callback_(datatype_refresh_callback),
+      task_tracker_(base::MakeUnique<TaskTracker>()) {}
 
 SessionsSyncManager::~SessionsSyncManager() {}
 
@@ -422,8 +423,9 @@
   DCHECK(!tab_delegate->IsPlaceholderTab());
 
   if (tab_delegate->IsBeingDestroyed()) {
-    // Do nothing. By not proactively adding the tab to the session, it will be
-    // removed if necessary during subsequent cleanup.
+    task_tracker_->CleanTabTasks(tab_delegate->GetSessionId());
+    // Do nothing else. By not proactively adding the tab to the session, it
+    // will be removed if necessary during subsequent cleanup.
     return;
   }
 
@@ -464,6 +466,9 @@
   sync_pb::EntitySpecifics specifics;
   specifics.mutable_session()->CopyFrom(
       SessionTabToSpecifics(*session_tab, current_machine_tag(), tab_node_id));
+  // Intercept the sync model here to update task tracker and fill navigations
+  // with their ancestor navigations.
+  TrackTasks(tab_delegate, specifics.mutable_session());
   syncer::SyncData data = syncer::SyncData::CreateLocalData(
       TabNodeIdToTag(current_machine_tag(), tab_node_id), current_session_name_,
       specifics);
@@ -483,6 +488,54 @@
   }
 }
 
+void SessionsSyncManager::TrackTasks(
+    SyncedTabDelegate* const tab_delegate,
+    sync_pb::SessionSpecifics* session_specifics) {
+  sync_pb::SessionTab* tab_specifics = session_specifics->mutable_tab();
+  // Index in the whole navigations of the tab.
+  int current_navigation_index = tab_delegate->GetCurrentEntryIndex();
+  // Index in the tab_specifics, where the navigations is a -6/+6 window
+  int current_index_in_tab_specifics =
+      tab_specifics->current_navigation_index();
+  int64_t current_navigation_global_id =
+      tab_specifics->navigation(current_index_in_tab_specifics).global_id();
+
+  TabTasks* tab_tasks =
+      task_tracker_->GetTabTasks(tab_delegate->GetSessionId());
+  tab_tasks->UpdateWithNavigation(
+      current_navigation_index,
+      tab_delegate->GetTransitionAtIndex(current_navigation_index),
+      current_navigation_global_id);
+
+  for (int i = 0; i < tab_specifics->navigation_size(); i++) {
+    // Excluding blocked navigations, which are appended at tail.
+    if (tab_specifics->navigation(i).blocked_state() ==
+        sync_pb::TabNavigation::STATE_BLOCKED) {
+      break;
+    }
+
+    int navigation_index =
+        current_navigation_index - current_index_in_tab_specifics + i;
+    // Skipping navigations not been tracked by task_tracker.
+    if (navigation_index < 0 ||
+        navigation_index >= tab_tasks->GetNavigationsCount()) {
+      continue;
+    }
+    std::vector<int64_t> task_ids =
+        tab_tasks->GetTaskIdsForNavigation(navigation_index);
+    if (task_ids.empty())
+      continue;
+
+    tab_specifics->mutable_navigation(i)->set_task_id(task_ids.back());
+    // Pop the task id of navigation self.
+    task_ids.pop_back();
+    for (auto ancestor_task_id : task_ids) {
+      tab_specifics->mutable_navigation(i)->add_ancestor_task_id(
+          ancestor_task_id);
+    }
+  }
+}
+
 bool SessionsSyncManager::RebuildAssociations() {
   syncer::SyncDataList data(sync_processor_->GetAllSyncData(syncer::SESSIONS));
   std::unique_ptr<syncer::SyncErrorFactory> error_handler(
diff --git a/components/sync_sessions/sessions_sync_manager.h b/components/sync_sessions/sessions_sync_manager.h
index 80706d86..3c5e5fe 100644
--- a/components/sync_sessions/sessions_sync_manager.h
+++ b/components/sync_sessions/sessions_sync_manager.h
@@ -30,6 +30,7 @@
 #include "components/sync_sessions/revisit/page_revisit_broadcaster.h"
 #include "components/sync_sessions/synced_session.h"
 #include "components/sync_sessions/synced_session_tracker.h"
+#include "components/sync_sessions/task_tracker.h"
 
 namespace syncer {
 class LocalDeviceInfoProvider;
@@ -235,6 +236,11 @@
   void LocalTabDelegateToSpecifics(const SyncedTabDelegate& tab_delegate,
                                    sync_pb::SessionSpecifics* specifics);
 
+  // Updates task tracker with current navigation of |tab_delegate|, and fills
+  // TabNavigation's task id related fields in |specifics|.
+  void TrackTasks(SyncedTabDelegate* const tab_delegate,
+                  sync_pb::SessionSpecifics* specifics);
+
   // It's possible that when we associate windows, tabs aren't all loaded
   // into memory yet (e.g on android) and we don't have a WebContents. In this
   // case we can't do a full association, but we still want to update tab IDs
@@ -326,6 +332,10 @@
   // Callback to inform sync that a sync data refresh is requested.
   base::Closure datatype_refresh_callback_;
 
+  // Tracks Chrome Tasks, which associates navigations, with tab and navigation
+  // changes of current session.
+  std::unique_ptr<TaskTracker> task_tracker_;
+
   DISALLOW_COPY_AND_ASSIGN(SessionsSyncManager);
 };
 
diff --git a/components/sync_sessions/sessions_sync_manager_unittest.cc b/components/sync_sessions/sessions_sync_manager_unittest.cc
index bc22ca115..41c3eada 100644
--- a/components/sync_sessions/sessions_sync_manager_unittest.cc
+++ b/components/sync_sessions/sessions_sync_manager_unittest.cc
@@ -707,21 +707,34 @@
   }
   TestSyncedTabDelegate* AddTab(SessionID::id_type window_id,
                                 const std::string& url) {
-    return AddTab(window_id, url, base::Time());
+    return AddTab(window_id, url, base::Time::Now());
   }
 
   void NavigateTab(TestSyncedTabDelegate* delegate,
                    const std::string& url,
-                   base::Time time) {
+                   base::Time time,
+                   ui::PageTransition transition) {
     auto entry = base::MakeUnique<sessions::SerializedNavigationEntry>(
         SerializedNavigationEntryTestHelper::CreateNavigation(url, kTitle));
     SerializedNavigationEntryTestHelper::SetTimestamp(time, entry.get());
+    SerializedNavigationEntryTestHelper::SetTransitionType(transition,
+                                                           entry.get());
     delegate->AppendEntry(std::move(entry));
     delegate->set_current_entry_index(delegate->GetCurrentEntryIndex() + 1);
     router_->NotifyNav(delegate);
   }
+  void NavigateTab(TestSyncedTabDelegate* delegate,
+                   const std::string& url,
+                   base::Time time) {
+    NavigateTab(delegate, url, time, ui::PAGE_TRANSITION_TYPED);
+  }
   void NavigateTab(TestSyncedTabDelegate* delegate, const std::string& url) {
-    NavigateTab(delegate, url, base::Time());
+    NavigateTab(delegate, url, base::Time::Now());
+  }
+  void NavigateTab(TestSyncedTabDelegate* delegate,
+                   const std::string& url,
+                   ui::PageTransition transition) {
+    NavigateTab(delegate, url, base::Time::Now(), transition);
   }
 
   void ResetWindows() {
@@ -2532,4 +2545,53 @@
             out[1].sync_data().GetSpecifics().session().tab().window_id());
 }
 
+// Tests that task ids are generated for navigations on local tabs.
+TEST_F(SessionsSyncManagerTest, TrackTasksOnLocalTabModified) {
+  SyncChangeList changes;
+  TestSyncedWindowDelegate* window = AddWindow();
+  InitWithSyncDataTakeOutput(SyncDataList(), &changes);
+  SessionID::id_type window_id = window->GetSessionId();
+  ASSERT_FALSE(manager()->current_machine_tag().empty());
+  changes.clear();
+
+  // Tab 1
+  NavigateTab(AddTab(window_id, kFoo1), kFoo2, ui::PAGE_TRANSITION_TYPED);
+  // Tab 2
+  NavigateTab(AddTab(window_id, kBar1), kBar2, ui::PAGE_TRANSITION_LINK);
+
+  // We only test changes for tab add and tab update, and ignore header updates.
+  FilterOutLocalHeaderChanges(&changes);
+  // Sync data of adding Tab 1 change
+  sync_pb::SessionTab tab =
+      SyncDataLocal(changes[0].sync_data()).GetSpecifics().session().tab();
+  EXPECT_EQ(tab.navigation_size(), 1);
+  EXPECT_EQ(tab.navigation(0).global_id(), tab.navigation(0).task_id());
+  EXPECT_TRUE(tab.navigation(0).ancestor_task_id().empty());
+
+  // Sync data of updating Tab 1 change
+  tab = SyncDataLocal(changes[1].sync_data()).GetSpecifics().session().tab();
+  EXPECT_EQ(tab.navigation_size(), 2);
+  // navigation(0) and navigation(1) are two seperated tasks.
+  EXPECT_EQ(tab.navigation(0).global_id(), tab.navigation(0).task_id());
+  EXPECT_TRUE(tab.navigation(0).ancestor_task_id().empty());
+  EXPECT_EQ(tab.navigation(1).global_id(), tab.navigation(1).task_id());
+  EXPECT_TRUE(tab.navigation(1).ancestor_task_id().empty());
+
+  // Sync data of adding Tab 2 change
+  tab = SyncDataLocal(changes[2].sync_data()).GetSpecifics().session().tab();
+  EXPECT_EQ(tab.navigation_size(), 1);
+  EXPECT_EQ(tab.navigation(0).global_id(), tab.navigation(0).task_id());
+  EXPECT_TRUE(tab.navigation(0).ancestor_task_id().empty());
+
+  // Sync data of updating Tab 2 change
+  tab = SyncDataLocal(changes[3].sync_data()).GetSpecifics().session().tab();
+  EXPECT_EQ(tab.navigation_size(), 2);
+  EXPECT_EQ(tab.navigation(0).global_id(), tab.navigation(0).task_id());
+  EXPECT_TRUE(tab.navigation(0).ancestor_task_id().empty());
+  EXPECT_EQ(tab.navigation(1).global_id(), tab.navigation(1).task_id());
+  // navigation(1) is a subtask of navigation(0).
+  EXPECT_EQ(tab.navigation(1).ancestor_task_id_size(), 1);
+  EXPECT_EQ(tab.navigation(1).ancestor_task_id(0), tab.navigation(0).task_id());
+}
+
 }  // namespace sync_sessions
diff --git a/components/sync_sessions/task_tracker.cc b/components/sync_sessions/task_tracker.cc
new file mode 100644
index 0000000..0f8902e2
--- /dev/null
+++ b/components/sync_sessions/task_tracker.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 "components/sync_sessions/task_tracker.h"
+
+#include <utility>
+
+#include "base/numerics/safe_conversions.h"
+
+namespace sync_sessions {
+
+namespace {
+// The maximum number of tasks we track in a tab.
+int kMaxNumTasksPerTab = 100;
+}
+
+TabTasks::TabTasks() {}
+
+TabTasks::~TabTasks() {}
+
+std::vector<int64_t> TabTasks::GetTaskIdsForNavigation(
+    int navigation_index) const {
+  CHECK_LE(0, navigation_index);
+  CHECK_LT(navigation_index, GetNavigationsCount());
+
+  std::vector<int64_t> root_to_self_task_ids;
+  // Position of the navigation in task_ids_ vector.
+  int navigation_position = navigation_index - excluded_navigation_num_;
+
+  // If navigation_index is an excluded ancestor task, returns empty.
+  if (navigation_position < 0)
+    return root_to_self_task_ids;
+
+  TaskIdAndRoot task_id_and_root = task_ids_[navigation_position];
+
+  // If navigation_index is an invalid task, returns empty.
+  if (task_id_and_root.root_navigation_index < 0)
+    return root_to_self_task_ids;
+
+  // The root task can be excluded. If so, consider the oldest ancestor
+  // available as root.
+  int root_navigation_index =
+      task_id_and_root.root_navigation_index > excluded_navigation_num_
+          ? task_id_and_root.root_navigation_index - excluded_navigation_num_
+          : 0;
+  for (int i = root_navigation_index; i <= navigation_position; i++) {
+    // Fills the vector with valid tasks.
+    if (task_ids_[i].root_navigation_index >= 0)
+      root_to_self_task_ids.push_back(task_ids_[i].task_id);
+  }
+  return root_to_self_task_ids;
+}
+
+int TabTasks::GetNavigationsCount() const {
+  return excluded_navigation_num_ + task_ids_.size();
+}
+
+void TabTasks::UpdateWithNavigation(int navigation_index,
+                                    ui::PageTransition transition,
+                                    int64_t navigation_id) {
+  // Triggered by some notifications on the current page, do nothing.
+  if (navigation_index == current_navigation_index_) {
+    DVLOG(1) << "Doing nothing for navigation_index: " << navigation_index
+             << " of transition: " << transition;
+    return;
+  }
+
+  // Going back/forward to some previous navigation.
+  if (navigation_index < current_navigation_index_ ||
+      (navigation_index > current_navigation_index_ &&
+       transition & ui::PAGE_TRANSITION_FORWARD_BACK &&
+       base::checked_cast<size_t>(navigation_index) < task_ids_.size())) {
+    DVLOG(1) << "Just updating task position with navigation_index: "
+             << navigation_index << " of transition: " << transition;
+    current_navigation_index_ = navigation_index;
+    return;
+  }
+
+  // A new task for the new navigation.
+  int root_navigation_index = navigation_index;
+  if (current_navigation_index_ != -1 &&
+      (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_LINK) ||
+       ui::PageTransitionCoreTypeIs(transition,
+                                    ui::PAGE_TRANSITION_AUTO_SUBFRAME) ||
+       ui::PageTransitionCoreTypeIs(transition,
+                                    ui::PAGE_TRANSITION_MANUAL_SUBFRAME) ||
+       ui::PageTransitionCoreTypeIs(transition,
+                                    ui::PAGE_TRANSITION_FORM_SUBMIT) ||
+       transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK)) {
+    // Creating a sub-task with navigation at current_navigation_index as
+    // parent.
+    DVLOG(1) << "Creating a sub-task with navigation_index: "
+             << navigation_index << " of transition: " << transition
+             << " under navigation_index: " << current_navigation_index_;
+    // Position in task_id_.
+    int current_navigation_position =
+        current_navigation_index_ - excluded_navigation_num_;
+    // If current/parent task is excluded, consider the new task as a root task.
+    if (current_navigation_position >= 0) {
+      CHECK_LT(current_navigation_position,
+               base::checked_cast<int>(task_ids_.size()));
+      root_navigation_index =
+          task_ids_[current_navigation_position].root_navigation_index;
+    } else {
+      DVLOG(1) << "Becaue parent task is excluded, consider the sub-task as a "
+                  "root task.";
+    }
+  } else {
+    // Creating a root task.
+    // For now, we don't consider tasks cross tabs, so first navigation of the
+    // tab always creates a root task.
+    DVLOG(1) << "Creating a root task with navigation_index: "
+             << navigation_index << " of transition: " << transition;
+  }
+
+  // In most cases navigation_index == excluded_navigation_num_ +
+  // task_ids_.size() if the previous navigation is end of chain, or
+  // navigation_index < excluded_navigation_num_ + task_ids_.size() otherwise.
+  // In few case navigation_index > excluded_navigation_num_ + task_ids_.size(),
+  // we fill task_ids_ with invalid contents. A known case is the first
+  // navigation after newtab.
+  for (int i = task_ids_.size() + excluded_navigation_num_;
+       i < navigation_index; i++) {
+    task_ids_.push_back({-1, -1});
+  }
+
+  // Erase all task ids associated with an outdated forward navigation stack.
+  if (navigation_index > excluded_navigation_num_) {
+    int new_task_id_position = navigation_index - excluded_navigation_num_;
+    task_ids_.erase(task_ids_.begin() + new_task_id_position, task_ids_.end());
+  } else {
+    excluded_navigation_num_ = navigation_index;
+    // new task id position is 0
+    task_ids_.clear();
+  }
+
+  // Exclude oldest ancestors if task number reaches the limit.
+  int more_tasks_number = task_ids_.size() + 1 - kMaxNumTasksPerTab;
+  if (more_tasks_number > 0) {
+    task_ids_.erase(task_ids_.begin(), task_ids_.begin() + more_tasks_number);
+    DVLOG(1) << "Excluding " << more_tasks_number
+             << " oldest ancestor(s) from navigation index "
+             << excluded_navigation_num_;
+    excluded_navigation_num_ += more_tasks_number;
+  }
+
+  TaskIdAndRoot new_task = {root_navigation_index, navigation_id};
+  // Add the current task at navigation_index.
+  task_ids_.push_back(new_task);
+  current_navigation_index_ = navigation_index;
+  return;
+}
+
+TaskTracker::TaskTracker() {}
+
+TaskTracker::~TaskTracker() {}
+
+TabTasks* TaskTracker::GetTabTasks(SessionID::id_type tab_id) {
+  if (local_tab_tasks_map_.find(tab_id) == local_tab_tasks_map_.end()) {
+    local_tab_tasks_map_[tab_id] = base::MakeUnique<TabTasks>();
+  }
+  return local_tab_tasks_map_[tab_id].get();
+}
+
+void TaskTracker::CleanTabTasks(SessionID::id_type tab_id) {
+  auto iter = local_tab_tasks_map_.find(tab_id);
+  if (iter != local_tab_tasks_map_.end()) {
+    local_tab_tasks_map_.erase(iter);
+  }
+}
+
+}  // namespace sync_sessions
diff --git a/components/sync_sessions/task_tracker.h b/components/sync_sessions/task_tracker.h
new file mode 100644
index 0000000..44ee3636
--- /dev/null
+++ b/components/sync_sessions/task_tracker.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 COMPONENTS_SYNC_SESSIONS_TASK_TRACKER_H_
+#define COMPONENTS_SYNC_SESSIONS_TASK_TRACKER_H_
+
+#include <stddef.h>
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/time/clock.h"
+#include "base/time/default_clock.h"
+#include "base/time/time.h"
+#include "components/sessions/core/session_id.h"
+#include "components/sessions/core/session_types.h"
+#include "components/sync_sessions/synced_tab_delegate.h"
+#include "ui/base/page_transition_types.h"
+
+namespace sync_sessions {
+
+// Class to generate and manage task ids for navigations of a tab. For each
+// current navigation of a tab, UpdateWithNavigation(int navigation_index,
+//            ui::PageTransition transition)
+// needs to be called to update the object.
+//
+// TODO(shenchao): If the tab is restored, then the input navigation is not
+// necessarily the first navigation in this case. Need to fix it by initalizing
+// the object with restored data.
+// TODO(shenchao): Support to track tasks cross tabs.
+class TabTasks {
+ public:
+  TabTasks();
+  virtual ~TabTasks();
+
+  // Gets top-down task id list of ancestors and itself for
+  // |navigation_index|-th navigation of the tab.
+  std::vector<int64_t> GetTaskIdsForNavigation(int navigation_index) const;
+
+  int GetNavigationsCount() const;
+
+  // Updates the current task of the tab, given current navigation index of the
+  // tab as |navigation_index|, and its |transition|.
+  // If the navigation is from going back/forward of the tab, we set its first
+  // visit as current task; if the navigation is new, we create a subtask of the
+  // previous navigation if it's linked from the previous one or a root task
+  // otherwise, and use |navigation_id| as new task id.
+  void UpdateWithNavigation(int navigation_index,
+                            ui::PageTransition transition,
+                            int64_t navigation_id);
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(TaskTrackerTest, LimitMaxNumberOfTasksPerTab);
+
+  FRIEND_TEST_ALL_PREFIXES(TaskTrackerTest,
+                           CreateSubTaskFromExcludedAncestorTask);
+
+  struct TaskIdAndRoot {
+    // Root task index in task_ids_. Negative value means it's an invalid task
+    // just for filling the task_ids_.
+    int root_navigation_index;
+    int64_t task_id;
+  };
+
+  // Task ids (with root task) for the navigations of the tab. The vector is
+  // corresponding to the sequence of navigations of the tab.
+  std::vector<TaskIdAndRoot> task_ids_;
+  // Index of current navigation in task_ids_.
+  int current_navigation_index_ = -1;
+  // Number of oldest ancestors which have been excluded from being tracked in
+  // task_ids_;
+  int excluded_navigation_num_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(TabTasks);
+};
+
+// Tracks tasks of current session.
+class TaskTracker {
+ public:
+  // Constructs with a clock to get timestamp as new task ids.
+  TaskTracker();
+  virtual ~TaskTracker();
+
+  // Returns a TabTasks pointer, which is owned by this object, for the tab of
+  // given |tab_id|.
+  TabTasks* GetTabTasks(SessionID::id_type tab_id);
+
+  // Cleans tracked task ids of navigations in the tab of |tab_id|.
+  void CleanTabTasks(SessionID::id_type tab_id);
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(TaskTrackerTest, CleanTabTasks);
+  std::map<SessionID::id_type, std::unique_ptr<TabTasks>> local_tab_tasks_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(TaskTracker);
+};
+
+}  // namespace sync_sessions
+
+#endif  // COMPONENTS_SYNC_SESSIONS_TASK_TRACKER_H_
diff --git a/components/sync_sessions/task_tracker_unittest.cc b/components/sync_sessions/task_tracker_unittest.cc
new file mode 100644
index 0000000..40fd0424
--- /dev/null
+++ b/components/sync_sessions/task_tracker_unittest.cc
@@ -0,0 +1,198 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync_sessions/task_tracker.h"
+
+#include <utility>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::ElementsAre;
+using testing::SizeIs;
+
+namespace sync_sessions {
+
+namespace {
+const int kTab1 = 15;
+const int kTab2 = 25;
+}  // namespace
+
+TEST(TaskTrackerTest, GetTabTasks) {
+  TaskTracker task_tracker;
+  TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1);
+  ASSERT_NE(tab_tasks, nullptr);
+  EXPECT_EQ(task_tracker.GetTabTasks(kTab1), tab_tasks);
+  EXPECT_NE(task_tracker.GetTabTasks(kTab2), tab_tasks);
+}
+
+TEST(TaskTrackerTest, CleanTabTasks) {
+  TaskTracker task_tracker;
+  TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1);
+  ASSERT_NE(tab_tasks, nullptr);
+  ASSERT_FALSE(task_tracker.local_tab_tasks_map_.empty());
+
+  task_tracker.CleanTabTasks(kTab1);
+  EXPECT_TRUE(task_tracker.local_tab_tasks_map_.empty());
+}
+
+TEST(TaskTrackerTest, UpdateTasksWithMultipleClicks) {
+  TaskTracker task_tracker;
+  TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1);
+
+  tab_tasks->UpdateWithNavigation(1, ui::PageTransition::PAGE_TRANSITION_TYPED,
+                                  100);
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100));
+
+  tab_tasks->UpdateWithNavigation(2, ui::PageTransition::PAGE_TRANSITION_LINK,
+                                  200);
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(2), ElementsAre(100, 200));
+
+  tab_tasks->UpdateWithNavigation(3, ui::PageTransition::PAGE_TRANSITION_LINK,
+                                  300);
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(2), ElementsAre(100, 200));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(3),
+              ElementsAre(100, 200, 300));
+}
+
+TEST(TaskTrackerTest, UpdateTasksWithMultipleClicksAndTypes) {
+  TaskTracker task_tracker;
+  TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1);
+
+  tab_tasks->UpdateWithNavigation(1, ui::PAGE_TRANSITION_LINK, 100);
+  tab_tasks->UpdateWithNavigation(2, ui::PAGE_TRANSITION_LINK, 200);
+  tab_tasks->UpdateWithNavigation(3, ui::PAGE_TRANSITION_LINK, 300);
+  tab_tasks->UpdateWithNavigation(4, ui::PAGE_TRANSITION_TYPED, 400);
+  tab_tasks->UpdateWithNavigation(5, ui::PAGE_TRANSITION_LINK, 500);
+  tab_tasks->UpdateWithNavigation(6, ui::PAGE_TRANSITION_TYPED, 600);
+  tab_tasks->UpdateWithNavigation(7, ui::PAGE_TRANSITION_LINK, 700);
+
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(2), ElementsAre(100, 200));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(3),
+              ElementsAre(100, 200, 300));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(4), ElementsAre(400));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(5), ElementsAre(400, 500));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(6), ElementsAre(600));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(7), ElementsAre(600, 700));
+}
+
+TEST(TaskTrackerTest, UpdateTasksWithBackforwards) {
+  TaskTracker task_tracker;
+  TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1);
+
+  tab_tasks->UpdateWithNavigation(1, ui::PAGE_TRANSITION_TYPED, 100);
+  tab_tasks->UpdateWithNavigation(2, ui::PAGE_TRANSITION_LINK, 200);
+  tab_tasks->UpdateWithNavigation(3, ui::PAGE_TRANSITION_LINK, 300);
+
+  tab_tasks->UpdateWithNavigation(
+      1,
+      ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+                                ui::PAGE_TRANSITION_FORWARD_BACK),
+      400);
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(2), ElementsAre(100, 200));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(3),
+              ElementsAre(100, 200, 300));
+
+  tab_tasks->UpdateWithNavigation(
+      3,
+      ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+                                ui::PAGE_TRANSITION_FORWARD_BACK),
+      500);
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(2), ElementsAre(100, 200));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(3),
+              ElementsAre(100, 200, 300));
+}
+
+TEST(TaskTrackerTest, UpdateWithNavigationsWithBackAndForkedNavigation) {
+  TaskTracker task_tracker;
+  TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1);
+  tab_tasks->UpdateWithNavigation(1, ui::PAGE_TRANSITION_LINK, 100);
+  tab_tasks->UpdateWithNavigation(2, ui::PAGE_TRANSITION_LINK, 200);
+  tab_tasks->UpdateWithNavigation(3, ui::PAGE_TRANSITION_LINK, 300);
+  tab_tasks->UpdateWithNavigation(
+      1,
+      ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+                                ui::PAGE_TRANSITION_FORWARD_BACK),
+      400);
+  tab_tasks->UpdateWithNavigation(2, ui::PAGE_TRANSITION_LINK, 500);
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(2), ElementsAre(100, 500));
+  // We don't track navigation at index 3 any more, and it's out of scope now.
+  EXPECT_THAT(tab_tasks->GetNavigationsCount(), 3);
+}
+
+TEST(TaskTrackerTest, LimitMaxNumberOfTasksPerTab) {
+  int kMaxNumTasksPerTab = 100;
+  TaskTracker task_tracker;
+  TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1);
+
+  // Reaching max number of tasks for a tab.
+  for (int i = 0; i < kMaxNumTasksPerTab; i++) {
+    tab_tasks->UpdateWithNavigation(i, ui::PAGE_TRANSITION_LINK, i * 100);
+  }
+
+  tab_tasks->UpdateWithNavigation(kMaxNumTasksPerTab, ui::PAGE_TRANSITION_LINK,
+                                  kMaxNumTasksPerTab * 100);
+
+  ASSERT_THAT(tab_tasks->task_ids_, SizeIs(kMaxNumTasksPerTab));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(0), ElementsAre());
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre(100));
+  std::vector<int64_t> task_ids =
+      tab_tasks->GetTaskIdsForNavigation(kMaxNumTasksPerTab);
+  EXPECT_THAT(task_ids, SizeIs(kMaxNumTasksPerTab));
+  EXPECT_EQ(task_ids[0], 100);
+  EXPECT_EQ(task_ids[kMaxNumTasksPerTab - 1], kMaxNumTasksPerTab * 100);
+
+  tab_tasks->UpdateWithNavigation(kMaxNumTasksPerTab + 1,
+                                  ui::PAGE_TRANSITION_LINK,
+                                  (kMaxNumTasksPerTab + 1) * 100);
+
+  ASSERT_THAT(tab_tasks->task_ids_, SizeIs(kMaxNumTasksPerTab));
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(0), ElementsAre());
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1), ElementsAre());
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(2), ElementsAre(200));
+  task_ids = tab_tasks->GetTaskIdsForNavigation(kMaxNumTasksPerTab + 1);
+  EXPECT_THAT(task_ids, SizeIs(kMaxNumTasksPerTab));
+  EXPECT_EQ(task_ids[0], 200);
+  EXPECT_EQ(task_ids[kMaxNumTasksPerTab - 1], (kMaxNumTasksPerTab + 1) * 100);
+}
+
+TEST(TaskTrackerTest, CreateSubTaskFromExcludedAncestorTask) {
+  int kMaxNumTasksPerTab = 100;
+  TaskTracker task_tracker;
+  TabTasks* tab_tasks = task_tracker.GetTabTasks(kTab1);
+
+  // Reaching max number of tasks for a tab.
+  for (int i = 0; i < kMaxNumTasksPerTab; i++) {
+    tab_tasks->UpdateWithNavigation(i, ui::PAGE_TRANSITION_LINK, i * 100);
+  }
+
+  tab_tasks->UpdateWithNavigation(kMaxNumTasksPerTab, ui::PAGE_TRANSITION_LINK,
+                                  kMaxNumTasksPerTab * 100);
+  ASSERT_EQ(tab_tasks->excluded_navigation_num_, 1);
+  ASSERT_EQ(tab_tasks->current_navigation_index_, kMaxNumTasksPerTab);
+
+  tab_tasks->UpdateWithNavigation(
+      0,
+      ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+                                ui::PAGE_TRANSITION_FORWARD_BACK),
+      (kMaxNumTasksPerTab + 1) * 100);
+  ASSERT_EQ(tab_tasks->excluded_navigation_num_, 1);
+  ASSERT_EQ(tab_tasks->current_navigation_index_, 0);
+
+  tab_tasks->UpdateWithNavigation(1, ui::PAGE_TRANSITION_LINK,
+                                  (kMaxNumTasksPerTab + 2) * 100);
+  ASSERT_THAT(tab_tasks->task_ids_, SizeIs(1));
+  ASSERT_EQ(tab_tasks->GetNavigationsCount(), 2);
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(0), ElementsAre());
+  EXPECT_THAT(tab_tasks->GetTaskIdsForNavigation(1),
+              ElementsAre((kMaxNumTasksPerTab + 2) * 100));
+}
+
+}  // namespace sync_sessions
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
index ee8613adf..f585d90e1 100644
--- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
+++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -64,8 +64,8 @@
   }
 
   // ContentBrowserTest
-  void SetUpInProcessBrowserTestFixture() override;
-  void TearDownInProcessBrowserTestFixture() override;
+  void SetUpOnMainThread() override;
+  void TearDownOnMainThread() override;
 
  protected:
   std::string GetAttr(const ui::AXNode* node,
@@ -83,15 +83,14 @@
   DISALLOW_COPY_AND_ASSIGN(CrossPlatformAccessibilityBrowserTest);
 };
 
-void CrossPlatformAccessibilityBrowserTest::SetUpInProcessBrowserTestFixture() {
+void CrossPlatformAccessibilityBrowserTest::SetUpOnMainThread() {
 #if defined(OS_WIN)
   ui::win::CreateATLModuleIfNeeded();
   com_initializer_.reset(new base::win::ScopedCOMInitializer());
 #endif
 }
 
-void
-CrossPlatformAccessibilityBrowserTest::TearDownInProcessBrowserTestFixture() {
+void CrossPlatformAccessibilityBrowserTest::TearDownOnMainThread() {
 #if defined(OS_WIN)
   com_initializer_.reset();
 #endif
diff --git a/content/browser/blob_storage/chrome_blob_storage_context.cc b/content/browser/blob_storage/chrome_blob_storage_context.cc
index 3192cd0d..8e3a3d8 100644
--- a/content/browser/blob_storage/chrome_blob_storage_context.cc
+++ b/content/browser/blob_storage/chrome_blob_storage_context.cc
@@ -15,6 +15,8 @@
 #include "base/single_thread_task_runner.h"
 #include "base/task_runner.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "content/browser/resource_context_impl.h"
+#include "content/common/resource_request_body_impl.h"
 #include "content/public/browser/blob_handle.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
@@ -186,4 +188,33 @@
   delete this;
 }
 
+storage::BlobStorageContext* GetBlobStorageContext(
+    ChromeBlobStorageContext* blob_storage_context) {
+  if (!blob_storage_context)
+    return NULL;
+  return blob_storage_context->context();
+}
+
+void AttachRequestBodyBlobDataHandles(ResourceRequestBodyImpl* body,
+                                      ResourceContext* resource_context) {
+  storage::BlobStorageContext* blob_context = GetBlobStorageContext(
+      GetChromeBlobStorageContextForResourceContext(resource_context));
+
+  DCHECK(blob_context);
+  for (size_t i = 0; i < body->elements()->size(); ++i) {
+    const ResourceRequestBodyImpl::Element& element = (*body->elements())[i];
+    if (element.type() != ResourceRequestBodyImpl::Element::TYPE_BLOB)
+      continue;
+    std::unique_ptr<storage::BlobDataHandle> handle =
+        blob_context->GetBlobDataFromUUID(element.blob_uuid());
+    DCHECK(handle);
+    if (!handle)
+      continue;
+    // Ensure the blob and any attached shareable files survive until
+    // upload completion. The |body| takes ownership of |handle|.
+    const void* key = handle.get();
+    body->SetUserData(key, handle.release());
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/blob_storage/chrome_blob_storage_context.h b/content/browser/blob_storage/chrome_blob_storage_context.h
index 4c7cfac..ad4a2a2 100644
--- a/content/browser/blob_storage/chrome_blob_storage_context.h
+++ b/content/browser/blob_storage/chrome_blob_storage_context.h
@@ -29,6 +29,8 @@
 class BlobHandle;
 class BrowserContext;
 struct ChromeBlobStorageContextDeleter;
+class ResourceRequestBodyImpl;
+class ResourceContext;
 
 // A context class that keeps track of BlobStorageController used by the chrome.
 // There is an instance associated with each BrowserContext. There could be
@@ -82,6 +84,16 @@
   }
 };
 
+// Returns the BlobStorageContext associated with the
+// ChromeBlobStorageContext instance passed in.
+storage::BlobStorageContext* GetBlobStorageContext(
+    ChromeBlobStorageContext* blob_storage_context);
+
+// Attaches blob data handles to the ResourceRequestBodyImpl body passed in.
+// This is used for POST and PUT requests.
+void AttachRequestBodyBlobDataHandles(ResourceRequestBodyImpl* body,
+                                      ResourceContext* resource_context);
+
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_FILEAPI_CHROME_BLOB_STORAGE_CONTEXT_H_
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 0dc52fca..5021cd5 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -217,14 +217,17 @@
 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
 void SetupSandbox(const base::CommandLine& parsed_command_line) {
   TRACE_EVENT0("startup", "SetupSandbox");
+  // RenderSandboxHostLinux needs to be initialized even if the sandbox and
+  // zygote are both disabled. It initializes the renderer socket.
+  RenderSandboxHostLinux::GetInstance()->Init();
+
   if (parsed_command_line.HasSwitch(switches::kNoZygote)) {
     CHECK(parsed_command_line.HasSwitch(switches::kNoSandbox))
         << "--no-sandbox should be used together with --no--zygote";
     return;
   }
 
-  // Tickle the sandbox host and zygote host so they fork now.
-  RenderSandboxHostLinux::GetInstance()->Init();
+  // Tickle the zygote host so it forks now.
   ZygoteHostImpl::GetInstance()->Init(parsed_command_line);
   *GetGenericZygote() = CreateZygote();
   RenderProcessHostImpl::EarlyZygoteLaunch();
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 525d09e..1d409a8d 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -18,9 +18,13 @@
 #include "base/format_macros.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/mock_entropy_provider.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_restrictions.h"
@@ -32,6 +36,7 @@
 #include "content/browser/download/download_item_impl.h"
 #include "content/browser/download/download_manager_impl.h"
 #include "content/browser/download/download_resource_handler.h"
+#include "content/browser/download/parallel_download_utils.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/download_danger_type.h"
@@ -82,6 +87,9 @@
 
 namespace {
 
+// Default request count for parallel download tests.
+constexpr int kTestRequestCount = 3;
+
 class MockDownloadItemObserver : public DownloadItem::Observer {
  public:
   MockDownloadItemObserver() {}
@@ -589,8 +597,8 @@
             make_scoped_refptr(content::BrowserThread::GetBlockingPool())));
   }
 
-  void SetUpCommandLine(base::CommandLine* commnad_line) override {
-    IsolateAllSitesForTesting(commnad_line);
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    IsolateAllSitesForTesting(command_line);
   }
 
   TestShellDownloadManagerDelegate* GetDownloadManagerDelegate() {
@@ -747,6 +755,45 @@
   std::unique_ptr<TestShellDownloadManagerDelegate> test_delegate_;
 };
 
+// Test fixture for parallel downloading.
+class ParallelDownloadTest : public DownloadContentTest {
+ protected:
+  void SetUp() override {
+    field_trial_list_ = base::MakeUnique<base::FieldTrialList>(
+        base::MakeUnique<base::MockEntropyProvider>());
+    SetupConfig();
+    DownloadContentTest::SetUp();
+  }
+
+ private:
+  // TODO(xingliu): Use this technique in parallel download unit tests to load
+  // the finch configuration.
+  void SetupConfig() {
+    const std::string kTrialName = "trial_name";
+    const std::string kGroupName = "group_name";
+
+    std::map<std::string, std::string> params;
+    params[content::kMinSliceSizeFinchKey] = "1";
+    params[content::kParallelRequestCountFinchKey] =
+        base::IntToString(kTestRequestCount);
+    params[content::kParallelRequestDelayFinchKey] = "0";
+    params[content::kParallelRequestRemainingTimeFinchKey] = "0";
+
+    scoped_refptr<base::FieldTrial> trial =
+        base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
+    base::AssociateFieldTrialParams(kTrialName, kGroupName, params);
+    std::unique_ptr<base::FeatureList> feature_list =
+        base::MakeUnique<base::FeatureList>();
+    feature_list->RegisterFieldTrialOverride(
+        features::kParallelDownloading.name,
+        base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
+    scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
+  }
+
+  std::unique_ptr<base::FieldTrialList> field_trial_list_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
 }  // namespace
 
 IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadCancelled) {
@@ -2655,4 +2702,30 @@
                download->GetTargetFilePath().BaseName().value().c_str());
 }
 
+IN_PROC_BROWSER_TEST_F(ParallelDownloadTest, ParallelDownloadComplete) {
+  EXPECT_TRUE(base::FeatureList::IsEnabled(features::kParallelDownloading));
+
+  TestDownloadRequestHandler request_handler;
+  TestDownloadRequestHandler::Parameters parameters;
+  parameters.etag = "ABC";
+  parameters.size = 5097152;
+  // Only parallel download needs to specify the connection type to http 1.1,
+  // other tests will automatically fall back to non-parallel download even if
+  // the ParallelDownloading feature is enabled based on
+  // fieldtrial_testing_config.json.
+  parameters.connection_type = net::HttpResponseInfo::CONNECTION_INFO_HTTP1_1;
+  request_handler.StartServing(parameters);
+
+  DownloadItem* download =
+      StartDownloadAndReturnItem(shell(), request_handler.url());
+  WaitForCompletion(download);
+
+  TestDownloadRequestHandler::CompletedRequests completed_requests;
+  request_handler.GetCompletedRequestInfo(&completed_requests);
+  EXPECT_EQ(kTestRequestCount, static_cast<int>(completed_requests.size()));
+
+  ReadAndVerifyFileContents(parameters.pattern_generator_seed, parameters.size,
+                            download->GetTargetFilePath());
+}
+
 }  // namespace content
diff --git a/content/browser/download/download_job_factory.cc b/content/browser/download/download_job_factory.cc
index a6ac607a..f170470 100644
--- a/content/browser/download/download_job_factory.cc
+++ b/content/browser/download/download_job_factory.cc
@@ -78,6 +78,7 @@
 
 }  // namespace
 
+// static
 std::unique_ptr<DownloadJob> DownloadJobFactory::CreateJob(
     DownloadItemImpl* download_item,
     std::unique_ptr<DownloadRequestHandleInterface> req_handle,
diff --git a/content/browser/download/parallel_download_utils.cc b/content/browser/download/parallel_download_utils.cc
index 1e3d900b..49fc009 100644
--- a/content/browser/download/parallel_download_utils.cc
+++ b/content/browser/download/parallel_download_utils.cc
@@ -14,30 +14,13 @@
 
 namespace {
 
-// Finch parameter key value for minimum slice size in bytes to use parallel
-// download.
-const char kMinSliceSizeFinchKey[] = "min_slice_size";
-
 // Default value for |kMinSliceSizeFinchKey|, when no parameter is specified.
 const int64_t kMinSliceSizeParallelDownload = 2097152;
 
-// Finch parameter key value for number of parallel requests in a parallel
-// download, including the original request.
-const char kParallelRequestCountFinchKey[] = "request_count";
-
 // Default value for |kParallelRequestCountFinchKey|, when no parameter is
 // specified.
 const int kParallelRequestCount = 2;
 
-// Finch parameter key value for the delay time in milliseconds to send
-// parallel requests after response of the original request is handled.
-const char kParallelRequestDelayFinchKey[] = "parallel_request_delay";
-
-// Finch parameter key value for the remaining time in seconds that is required
-// to send parallel requests.
-const char kParallelRequestRemainingTimeFinchKey[] =
-    "parallel_request_remaining_time";
-
 // The default remaining download time in seconds required for parallel request
 // creation.
 const int kDefaultRemainingTimeInSeconds = 10;
diff --git a/content/browser/download/parallel_download_utils.h b/content/browser/download/parallel_download_utils.h
index c6031f5..fcf7f39b 100644
--- a/content/browser/download/parallel_download_utils.h
+++ b/content/browser/download/parallel_download_utils.h
@@ -13,6 +13,23 @@
 
 namespace content {
 
+// Finch parameter key value for minimum slice size in bytes to use parallel
+// download.
+constexpr char kMinSliceSizeFinchKey[] = "min_slice_size";
+
+// Finch parameter key value for number of parallel requests in a parallel
+// download, including the original request.
+constexpr char kParallelRequestCountFinchKey[] = "request_count";
+
+// Finch parameter key value for the delay time in milliseconds to send
+// parallel requests after response of the original request is handled.
+constexpr char kParallelRequestDelayFinchKey[] = "parallel_request_delay";
+
+// Finch parameter key value for the remaining time in seconds that is required
+// to send parallel requests.
+constexpr char kParallelRequestRemainingTimeFinchKey[] =
+    "parallel_request_remaining_time";
+
 // Chunks the content that starts from |current_offset|, into at most
 // std::max(|request_count|, 1) smaller slices.
 // Each slice contains at least |min_slice_size| bytes unless |total_length|
diff --git a/content/browser/frame_host/navigator.h b/content/browser/frame_host/navigator.h
index 5a1f906..9982cea4 100644
--- a/content/browser/frame_host/navigator.h
+++ b/content/browser/frame_host/navigator.h
@@ -121,6 +121,7 @@
       const std::string& extra_headers,
       const Referrer& referrer,
       WindowOpenDisposition disposition,
+      bool force_new_process_for_new_contents,
       bool should_replace_current_entry,
       bool user_gesture) {}
 
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index 6dd1df2..e1a5cc6 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -732,6 +732,7 @@
     const std::string& extra_headers,
     const Referrer& referrer,
     WindowOpenDisposition disposition,
+    bool force_new_process_for_new_contents,
     bool should_replace_current_entry,
     bool user_gesture) {
   // Note: This can be called for subframes (even when OOPIFs are not possible)
@@ -774,6 +775,8 @@
   OpenURLParams params(dest_url, referrer, frame_tree_node_id, disposition,
                        ui::PAGE_TRANSITION_LINK,
                        true /* is_renderer_initiated */);
+  params.force_new_process_for_new_contents =
+      force_new_process_for_new_contents;
   params.uses_post = uses_post;
   params.post_data = body;
   params.extra_headers = extra_headers;
diff --git a/content/browser/frame_host/navigator_impl.h b/content/browser/frame_host/navigator_impl.h
index e59fa4e..997ddcbf 100644
--- a/content/browser/frame_host/navigator_impl.h
+++ b/content/browser/frame_host/navigator_impl.h
@@ -71,6 +71,7 @@
                       const std::string& extra_headers,
                       const Referrer& referrer,
                       WindowOpenDisposition disposition,
+                      bool force_new_process_for_new_contents,
                       bool should_replace_current_entry,
                       bool user_gesture) override;
   void RequestTransferURL(RenderFrameHostImpl* render_frame_host,
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index a64bf5be6..b730c3c 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1172,10 +1172,22 @@
   TRACE_EVENT1("navigation", "RenderFrameHostImpl::OpenURL", "url",
                validated_url.possibly_invalid_spec());
 
+  // When |params.disposition| asks OpenURL to create new contents, it always
+  // happens because of an explicit user request for new content creation (i.e.
+  // opening a link using ctrl-click or middle click).  In such cases, the new
+  // content should be created in a new renderer to break opener relationship
+  // (see https://crbug.com/658386) and to conserve memory per renderer (see
+  // https://crbug.com/23815).  Note that new content creation that wasn't
+  // explicitly requested by the user (i.e. left-clicking a link with
+  // target=_blank) goes through a different code path (through
+  // WebViewClient::CreateView).
+  bool kForceNewProcessForNewContents = true;
+
   frame_tree_node_->navigator()->RequestOpenURL(
       this, validated_url, params.uses_post, params.resource_request_body,
       params.extra_headers, params.referrer, params.disposition,
-      params.should_replace_current_entry, params.user_gesture);
+      kForceNewProcessForNewContents, params.should_replace_current_entry,
+      params.user_gesture);
 }
 
 void RenderFrameHostImpl::OnCancelInitialHistoryLoad() {
diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc
index 5e16a9328..5ff9458 100644
--- a/content/browser/loader/navigation_url_loader_network_service.cc
+++ b/content/browser/loader/navigation_url_loader_network_service.cc
@@ -4,7 +4,10 @@
 
 #include "content/browser/loader/navigation_url_loader_network_service.h"
 
+#include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/memory/ptr_util.h"
+#include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/frame_host/navigation_request_info.h"
 #include "content/browser/loader/navigation_resource_handler.h"
 #include "content/browser/loader/navigation_resource_throttle.h"
@@ -15,13 +18,32 @@
 #include "content/public/browser/navigation_ui_data.h"
 #include "content/public/browser/ssl_status.h"
 #include "content/public/browser/stream_handle.h"
+#include "content/public/common/referrer.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
+#include "net/base/load_flags.h"
 #include "net/url_request/url_request_context.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 namespace content {
 
+// This function is called on the IO thread for POST/PUT requests for
+// attaching blob information to the request body.
+void HandleRequestsWithBody(
+    std::unique_ptr<ResourceRequest> request,
+    ResourceContext* resource_context,
+    base::WeakPtr<NavigationURLLoaderNetworkService> url_loader) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(request->request_body.get());
+
+  AttachRequestBodyBlobDataHandles(request->request_body.get(),
+                                    resource_context);
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&NavigationURLLoaderNetworkService::StartURLRequest,
+                  url_loader, base::Passed(&request)));
+}
+
 NavigationURLLoaderNetworkService::NavigationURLLoaderNetworkService(
     ResourceContext* resource_context,
     StoragePartition* storage_partition,
@@ -30,8 +52,9 @@
     ServiceWorkerNavigationHandle* service_worker_handle,
     AppCacheNavigationHandle* appcache_handle,
     NavigationURLLoaderDelegate* delegate)
-    : delegate_(delegate), binding_(this) {
+    : delegate_(delegate), binding_(this), weak_factory_(this) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
   // TODO(scottmg): Maybe some of this setup should be done only once, instead
   // of every time.
   ServiceManagerConnection::GetForProcess()->GetConnector()->BindInterface(
@@ -39,18 +62,46 @@
 
   // TODO(scottmg): Port over stuff from RDHI::BeginNavigationRequest() here.
   auto new_request = base::MakeUnique<ResourceRequest>();
-  new_request->method = "GET";
+
+  new_request->method = request_info->common_params.method;
   new_request->url = request_info->common_params.url;
   new_request->first_party_for_cookies = request_info->first_party_for_cookies;
   new_request->priority = net::HIGHEST;
 
-  mojom::URLLoaderClientPtr url_loader_client_ptr_to_pass;
-  binding_.Bind(&url_loader_client_ptr_to_pass);
+  // The code below to set fields like request_initiator, referrer, etc has
+  // been copied from ResourceDispatcherHostImpl. We did not refactor the
+  // common code into a function, because RDHI uses accessor functions on the
+  // URLRequest class to set these fields. whereas we use ResourceRequest here.
+  new_request->request_initiator = request_info->begin_params.initiator_origin;
+  new_request->referrer = request_info->common_params.referrer.url;
+  new_request->referrer_policy = request_info->common_params.referrer.policy;
+  new_request->headers = request_info->begin_params.headers;
 
-  url_loader_factory_->CreateLoaderAndStart(
-      mojo::MakeRequest(&url_loader_associated_ptr_), 0 /* routing_id? */,
-      0 /* request_id? */, mojom::kURLLoadOptionSendSSLInfo, *new_request,
-      std::move(url_loader_client_ptr_to_pass));
+  int load_flags = request_info->begin_params.load_flags;
+  load_flags |= net::LOAD_VERIFY_EV_CERT;
+  if (request_info->is_main_frame)
+    load_flags |= net::LOAD_MAIN_FRAME_DEPRECATED;
+
+  // Sync loads should have maximum priority and should be the only
+  // requests that have the ignore limits flag set.
+  DCHECK(!(load_flags & net::LOAD_IGNORE_LIMITS));
+
+  new_request->load_flags = load_flags;
+
+  new_request->request_body = request_info->common_params.post_data.get();
+  if (new_request->request_body.get()) {
+    // The request body may need blob handles to be added to it. This
+    // functionality has to be invoked on the IO thread.
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(&HandleRequestsWithBody,
+                   base::Passed(&new_request),
+                   resource_context,
+                   weak_factory_.GetWeakPtr()));
+    return;
+  }
+
+  StartURLRequest(std::move(new_request));
 }
 
 NavigationURLLoaderNetworkService::~NavigationURLLoaderNetworkService() {}
@@ -118,4 +169,17 @@
   }
 }
 
+void NavigationURLLoaderNetworkService::StartURLRequest(
+    std::unique_ptr<ResourceRequest> request) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  mojom::URLLoaderClientPtr url_loader_client_ptr_to_pass;
+  binding_.Bind(&url_loader_client_ptr_to_pass);
+
+  url_loader_factory_->CreateLoaderAndStart(
+      mojo::MakeRequest(&url_loader_associated_ptr_), 0 /* routing_id? */,
+      0 /* request_id? */, mojom::kURLLoadOptionSendSSLInfo, *request,
+      std::move(url_loader_client_ptr_to_pass));
+}
+
 }  // namespace content
diff --git a/content/browser/loader/navigation_url_loader_network_service.h b/content/browser/loader/navigation_url_loader_network_service.h
index bb574b1..a60b276 100644
--- a/content/browser/loader/navigation_url_loader_network_service.h
+++ b/content/browser/loader/navigation_url_loader_network_service.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_NETWORK_SERVICE_H_
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "content/browser/loader/navigation_url_loader.h"
 #include "content/common/url_loader.mojom.h"
 #include "content/common/url_loader_factory.mojom.h"
@@ -20,6 +21,7 @@
 namespace content {
 
 class ResourceContext;
+class NavigationPostDataHandler;
 
 // This is an implementation of NavigationURLLoader used when
 // --enable-network-service is used.
@@ -58,6 +60,9 @@
   void OnComplete(
       const ResourceRequestCompletionStatus& completion_status) override;
 
+  // Initiates the request.
+  void StartURLRequest(std::unique_ptr<ResourceRequest> request);
+
  private:
   void ConnectURLLoaderFactory(
       std::unique_ptr<service_manager::Connector> connector);
@@ -70,6 +75,8 @@
   scoped_refptr<ResourceResponse> response_;
   SSLStatus ssl_status_;
 
+  base::WeakPtrFactory<NavigationURLLoaderNetworkService> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(NavigationURLLoaderNetworkService);
 };
 
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index a9c9157..7271a3a 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -137,7 +137,7 @@
 const int kUpdateLoadStatesIntervalMsec = 250;
 
 // Maximum byte "cost" of all the outstanding requests for a renderer.
-// See delcaration of |max_outstanding_requests_cost_per_process_| for details.
+// See declaration of |max_outstanding_requests_cost_per_process_| for details.
 // This bound is 25MB, which allows for around 6000 outstanding requests.
 const int kMaxOutstandingRequestsCostPerProcess = 26214400;
 
@@ -265,33 +265,6 @@
   return sct_status.status == net::ct::SCT_STATUS_OK;
 }
 
-storage::BlobStorageContext* GetBlobStorageContext(
-    ChromeBlobStorageContext* blob_storage_context) {
-  if (!blob_storage_context)
-    return NULL;
-  return blob_storage_context->context();
-}
-
-void AttachRequestBodyBlobDataHandles(
-    ResourceRequestBodyImpl* body,
-    storage::BlobStorageContext* blob_context) {
-  DCHECK(blob_context);
-  for (size_t i = 0; i < body->elements()->size(); ++i) {
-    const ResourceRequestBodyImpl::Element& element = (*body->elements())[i];
-    if (element.type() != ResourceRequestBodyImpl::Element::TYPE_BLOB)
-      continue;
-    std::unique_ptr<storage::BlobDataHandle> handle =
-        blob_context->GetBlobDataFromUUID(element.blob_uuid());
-    DCHECK(handle);
-    if (!handle)
-      continue;
-    // Ensure the blob and any attached shareable files survive until
-    // upload completion. The |body| takes ownership of |handle|.
-    const void* key = handle.get();
-    body->SetUserData(key, handle.release());
-  }
-}
-
 // Returns the PreviewsState after requesting it from the delegate. The
 // PreviewsState is a bitmask of potentially several Previews optimizations.
 PreviewsState GetPreviewsState(PreviewsState previews_state,
@@ -350,6 +323,8 @@
           max_num_in_flight_requests_ * kMaxRequestsPerProcessRatio)),
       max_outstanding_requests_cost_per_process_(
           kMaxOutstandingRequestsCostPerProcess),
+      largest_outstanding_request_count_seen_(0),
+      largest_outstanding_request_per_process_count_seen_(0),
       delegate_(nullptr),
       loader_delegate_(nullptr),
       allow_cross_origin_auth_prompt_(false),
@@ -1298,9 +1273,8 @@
       // Attaches the BlobDataHandles to request_body not to free the blobs and
       // any attached shareable files until upload completion. These data will
       // be used in UploadDataStream and ServiceWorkerURLRequestJob.
-      AttachRequestBodyBlobDataHandles(
-          request_data.request_body.get(),
-          blob_context);
+      AttachRequestBodyBlobDataHandles(request_data.request_body.get(),
+                                       resource_context);
     }
     new_request->set_upload(UploadDataStreamBuilder::Build(
         request_data.request_body.get(), blob_context,
@@ -1904,6 +1878,20 @@
   DCHECK_GE(stats.num_requests, 0);
   UpdateOutstandingRequestsStats(*info, stats);
 
+  if (num_in_flight_requests_ > largest_outstanding_request_count_seen_) {
+    largest_outstanding_request_count_seen_ = num_in_flight_requests_;
+    UMA_HISTOGRAM_COUNTS_1M(
+        "Net.ResourceDispatcherHost.OutstandingRequests.Total",
+        largest_outstanding_request_count_seen_);
+  }
+
+  if (stats.num_requests > largest_outstanding_request_count_seen_) {
+    largest_outstanding_request_per_process_count_seen_ = stats.num_requests;
+    UMA_HISTOGRAM_COUNTS_1M(
+        "Net.ResourceDispatcherHost.OutstandingRequests.PerProcess",
+        largest_outstanding_request_per_process_count_seen_);
+  }
+
   return stats;
 }
 
@@ -2009,7 +1997,7 @@
   // Resolve elements from request_body and prepare upload data.
   ResourceRequestBodyImpl* body = info.common_params.post_data.get();
   if (body) {
-    AttachRequestBodyBlobDataHandles(body, blob_context);
+    AttachRequestBodyBlobDataHandles(body, resource_context);
     // TODO(davidben): The FileSystemContext is null here. In the case where
     // another renderer requested this navigation, this should be the same
     // FileSystemContext passed into ShouldServiceRequest.
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h
index 4821073e..3667199 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -742,6 +742,12 @@
   //       kAvgBytesPerOutstandingRequest)
   int max_outstanding_requests_cost_per_process_;
 
+  // Largest number of outstanding requests seen so far across all processes.
+  int largest_outstanding_request_count_seen_;
+
+  // Largest number of outstanding requests seen so far in any single process.
+  int largest_outstanding_request_per_process_count_seen_;
+
   // Time of the last user gesture. Stored so that we can add a load
   // flag to requests occurring soon after a gesture to indicate they
   // may be because of explicit user action.
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index 6ae8ed6..7eed4ac 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -92,7 +92,7 @@
   wc->GetFrameTree()->root()->navigator()->RequestOpenURL(
       wc->GetFrameTree()->root()->current_frame_host(), extension_url, false,
       nullptr, std::string(), Referrer(), WindowOpenDisposition::CURRENT_TAB,
-      false, true);
+      false, false, true);
 
   // Since the navigation above requires a cross-process swap, there will be a
   // speculative/pending RenderFrameHost. Ensure it exists and is in a different
diff --git a/content/browser/speech/speech_recognition_browsertest.cc b/content/browser/speech/speech_recognition_browsertest.cc
index d51fea6..73c4cc0 100644
--- a/content/browser/speech/speech_recognition_browsertest.cc
+++ b/content/browser/speech/speech_recognition_browsertest.cc
@@ -111,15 +111,13 @@
 
  protected:
   // ContentBrowserTest methods.
-  void SetUpInProcessBrowserTestFixture() override {
+  void SetUpOnMainThread() override {
     test_audio_input_controller_factory_.set_delegate(this);
     media::AudioInputController::set_factory_for_testing(
         &test_audio_input_controller_factory_);
     mock_streaming_server_.reset(new MockGoogleStreamingServer(this));
     streaming_server_state_ = kIdle;
-  }
 
-  void SetUpOnMainThread() override {
     ASSERT_TRUE(SpeechRecognitionManagerImpl::GetInstance());
     media::AudioManager::StartHangMonitorIfNeeded(
         BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
@@ -138,9 +136,7 @@
     // Deleting AudioManager on audio thread,
     audio_system_.reset();
     audio_manager_.reset();
-  }
 
-  void TearDownInProcessBrowserTestFixture() override {
     test_audio_input_controller_factory_.set_delegate(nullptr);
     mock_streaming_server_.reset();
   }
diff --git a/content/public/browser/page_navigator.cc b/content/public/browser/page_navigator.cc
index cb7da03..de8d88e 100644
--- a/content/public/browser/page_navigator.cc
+++ b/content/public/browser/page_navigator.cc
@@ -16,6 +16,7 @@
       uses_post(false),
       frame_tree_node_id(-1),
       disposition(disposition),
+      force_new_process_for_new_contents(false),
       transition(transition),
       is_renderer_initiated(is_renderer_initiated),
       should_replace_current_entry(false),
@@ -33,6 +34,7 @@
       uses_post(false),
       frame_tree_node_id(-1),
       disposition(disposition),
+      force_new_process_for_new_contents(false),
       transition(transition),
       is_renderer_initiated(is_renderer_initiated),
       should_replace_current_entry(false),
@@ -50,6 +52,7 @@
       uses_post(false),
       frame_tree_node_id(frame_tree_node_id),
       disposition(disposition),
+      force_new_process_for_new_contents(false),
       transition(transition),
       is_renderer_initiated(is_renderer_initiated),
       should_replace_current_entry(false),
@@ -60,6 +63,7 @@
     : uses_post(false),
       frame_tree_node_id(-1),
       disposition(WindowOpenDisposition::UNKNOWN),
+      force_new_process_for_new_contents(false),
       transition(ui::PAGE_TRANSITION_LINK),
       is_renderer_initiated(false),
       should_replace_current_entry(false),
diff --git a/content/public/browser/page_navigator.h b/content/public/browser/page_navigator.h
index eb9e6a83..166a0d51 100644
--- a/content/public/browser/page_navigator.h
+++ b/content/public/browser/page_navigator.h
@@ -82,6 +82,12 @@
   // The disposition requested by the navigation source.
   WindowOpenDisposition disposition;
 
+  // Controls creation of new web contents (in case |disposition| asks for a new
+  // tab or window).  If |force_new_process_for_new_contents| is true, then we
+  // try to put the new contents in a new renderer, even if they are same-site
+  // as |source_site_instance| (this is subject to renderer process limits).
+  bool force_new_process_for_new_contents;
+
   // The transition type of navigation.
   ui::PageTransition transition;
 
diff --git a/content/public/test/test_download_request_handler.cc b/content/public/test/test_download_request_handler.cc
index 180f37f..d7d05a85 100644
--- a/content/public/test/test_download_request_handler.cc
+++ b/content/public/test/test_download_request_handler.cc
@@ -412,6 +412,7 @@
       HeadersFromString(base::StringPrintf("HTTP/1.1 200 Success\r\n"
                                            "Content-Length: %" PRId64 "\r\n",
                                            parameters_->size));
+  response_info_.connection_info = parameters_->connection_type;
   AddCommonEntityHeaders();
   NotifyHeadersCompleteAndPrepareToRead();
   return;
@@ -454,6 +455,7 @@
           "Content-Length: %" PRId64 "\r\n",
           requested_range_begin_, requested_range_end_, parameters_->size,
           (requested_range_end_ - requested_range_begin_) + 1));
+  response_info_.connection_info = parameters_->connection_type;
   AddCommonEntityHeaders();
   NotifyHeadersCompleteAndPrepareToRead();
   return true;
@@ -585,7 +587,9 @@
       content_type("application/octet-stream"),
       size(102400),
       pattern_generator_seed(1),
-      support_byte_ranges(true) {}
+      support_byte_ranges(true),
+      connection_type(
+          net::HttpResponseInfo::ConnectionInfo::CONNECTION_INFO_UNKNOWN) {}
 
 // Copy and move constructors / assignment operators are all defaults.
 TestDownloadRequestHandler::Parameters::Parameters(const Parameters&) = default;
@@ -599,6 +603,7 @@
       size(that.size),
       pattern_generator_seed(that.pattern_generator_seed),
       support_byte_ranges(that.support_byte_ranges),
+      connection_type(that.connection_type),
       on_start_handler(that.on_start_handler),
       injected_errors(std::move(that.injected_errors)) {}
 
diff --git a/content/public/test/test_download_request_handler.h b/content/public/test/test_download_request_handler.h
index 4daff5c4..629d8d61 100644
--- a/content/public/test/test_download_request_handler.h
+++ b/content/public/test/test_download_request_handler.h
@@ -147,6 +147,9 @@
     // If true, the response contains a 'Accept-Ranges: bytes' header.
     bool support_byte_ranges;
 
+    // The connection type in the response.
+    net::HttpResponseInfo::ConnectionInfo connection_type;
+
     // If on_start_handler is valid, it will be invoked when a new request is
     // received. See details about the OnStartHandler above.
     OnStartHandler on_start_handler;
diff --git a/content/renderer/media_recorder/media_recorder_handler.cc b/content/renderer/media_recorder/media_recorder_handler.cc
index 13986893..16b0bb1 100644
--- a/content/renderer/media_recorder/media_recorder_handler.cc
+++ b/content/renderer/media_recorder/media_recorder_handler.cc
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/strings/string_tokenizer.h"
 #include "base/strings/string_util.h"
+#include "content/child/scoped_web_callbacks.h"
 #include "content/renderer/media/media_stream_audio_track.h"
 #include "content/renderer/media/media_stream_track.h"
 #include "content/renderer/media/webrtc_uma_histograms.h"
@@ -25,6 +26,7 @@
 #include "third_party/WebKit/public/platform/WebMediaRecorderHandlerClient.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
 #include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/modules/media_capabilities/WebMediaConfiguration.h"
 
 using base::TimeDelta;
 using base::TimeTicks;
@@ -32,6 +34,8 @@
 
 namespace content {
 
+using blink::WebMediaCapabilitiesQueryCallbacks;
+
 namespace {
 
 media::VideoCodec CodecIdToMediaVideoCodec(VideoTrackRecorder::CodecId id) {
@@ -51,6 +55,11 @@
   return media::kUnknownVideoCodec;
 }
 
+void OnEncodingInfoError(
+    std::unique_ptr<WebMediaCapabilitiesQueryCallbacks> callbacks) {
+  callbacks->OnError();
+}
+
 }  // anonymous namespace
 
 MediaRecorderHandler::MediaRecorderHandler()
@@ -267,6 +276,54 @@
   webm_muxer_->Resume();
 }
 
+void MediaRecorderHandler::EncodingInfo(
+    const blink::WebMediaConfiguration& configuration,
+    std::unique_ptr<blink::WebMediaCapabilitiesQueryCallbacks> callbacks) {
+  DCHECK(main_render_thread_checker_.CalledOnValidThread());
+  DCHECK(configuration.video_configuration ||
+         configuration.audio_configuration);
+
+  ScopedWebCallbacks<WebMediaCapabilitiesQueryCallbacks> scoped_callbacks =
+      make_scoped_web_callbacks(callbacks.release(),
+                                base::Bind(&OnEncodingInfoError));
+
+  std::unique_ptr<blink::WebMediaCapabilitiesInfo> info(
+      new blink::WebMediaCapabilitiesInfo());
+
+  // TODO(mcasas): Support the case when both video and audio configurations are
+  // specified: https://crbug.com/709181.
+  std::string content_type;
+  if (configuration.video_configuration)
+    content_type = configuration.video_configuration->content_type.Ascii();
+  else
+    content_type = configuration.audio_configuration->content_type.Ascii();
+
+  // |content_type| should be of the form "bla;codecs=foo", where "bla" is the
+  // type and "codecs=foo" is the parameter ("foo" is the parameter value), see
+  // RFC 2231 [1]. CanSupportMimeType() operates on type and parameter value.
+  // [1] https://tools.ietf.org/html/rfc2231
+  base::StringTokenizer mime_tokenizer(content_type, ";");
+  blink::WebString web_type;
+  blink::WebString web_codecs;
+  if (mime_tokenizer.GetNext())
+    web_type = blink::WebString::FromASCII(mime_tokenizer.token());
+  if (mime_tokenizer.GetNext()) {
+    const std::string parameters = mime_tokenizer.token();
+    base::StringTokenizer parameter_tokenizer(parameters, "=");
+    if (parameter_tokenizer.GetNext() &&
+        base::ToLowerASCII(parameter_tokenizer.token()) == "codecs" &&
+        parameter_tokenizer.GetNext()) {
+      web_codecs = blink::WebString::FromASCII(parameter_tokenizer.token());
+    }
+  }
+
+  info->supported = CanSupportMimeType(web_type, web_codecs);
+  DVLOG(1) << "type: " << web_type.Ascii() << ", params:" << web_codecs.Ascii()
+           << " is" << (info->supported ? " supported" : " NOT supported");
+
+  scoped_callbacks.PassCallbacks()->OnSuccess(std::move(info));
+}
+
 void MediaRecorderHandler::OnEncodedVideo(
     const media::WebmMuxer::VideoParameters& params,
     std::unique_ptr<std::string> encoded_data,
diff --git a/content/renderer/media_recorder/media_recorder_handler.h b/content/renderer/media_recorder/media_recorder_handler.h
index f7d7f64..d9affd90e 100644
--- a/content/renderer/media_recorder/media_recorder_handler.h
+++ b/content/renderer/media_recorder/media_recorder_handler.h
@@ -61,6 +61,9 @@
   void Stop() override;
   void Pause() override;
   void Resume() override;
+  void EncodingInfo(
+      const blink::WebMediaConfiguration& configuration,
+      std::unique_ptr<blink::WebMediaCapabilitiesQueryCallbacks> cb) override;
 
  private:
   friend class MediaRecorderHandlerTest;
diff --git a/content/zygote/zygote_browsertest.cc b/content/zygote/zygote_browsertest.cc
index 4122bb79..5376445f 100644
--- a/content/zygote/zygote_browsertest.cc
+++ b/content/zygote/zygote_browsertest.cc
@@ -5,7 +5,9 @@
 #include <string>
 #include <vector>
 
+#include "base/command_line.h"
 #include "base/strings/string_split.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
@@ -38,4 +40,29 @@
   EXPECT_TRUE(parts[2].empty());
 }
 
+class LinuxZygoteDisabledBrowserTest : public ContentBrowserTest {
+ public:
+  LinuxZygoteDisabledBrowserTest() {}
+  ~LinuxZygoteDisabledBrowserTest() override {}
+
+ protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    ContentBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kNoZygote);
+    command_line->AppendSwitch(switches::kNoSandbox);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LinuxZygoteDisabledBrowserTest);
+};
+
+// https://crbug.com/712779
+#if !defined(THREAD_SANITIZER)
+// Test that the renderer doesn't crash during launch if zygote is disabled.
+IN_PROC_BROWSER_TEST_F(LinuxZygoteDisabledBrowserTest,
+                       NoCrashWhenZygoteDisabled) {
+  NavigateToURL(shell(), GURL("data:text/html,start page"));
+}
+#endif
+
 }  // namespace content
diff --git a/extensions/browser/api/serial/serial_apitest.cc b/extensions/browser/api/serial/serial_apitest.cc
index eef6645..37567658e 100644
--- a/extensions/browser/api/serial/serial_apitest.cc
+++ b/extensions/browser/api/serial/serial_apitest.cc
@@ -14,6 +14,7 @@
 #include "extensions/browser/api/serial/serial_api.h"
 #include "extensions/browser/api/serial/serial_connection.h"
 #include "extensions/browser/extension_function.h"
+#include "extensions/browser/extension_function_registry.h"
 #include "extensions/common/api/serial.h"
 #include "extensions/common/switches.h"
 #include "extensions/test/result_catcher.h"
@@ -122,6 +123,12 @@
   return new FakeSerialConnectFunction();
 }
 
+bool OverrideFunction(const std::string& name,
+                      ExtensionFunctionFactory factory) {
+  return ExtensionFunctionRegistry::GetInstance()->OverrideFunctionForTesting(
+      name, factory);
+}
+
 }  // namespace
 
 // Disable SIMULATE_SERIAL_PORTS only if all the following are true:
@@ -149,10 +156,10 @@
   catcher.RestrictToBrowserContext(browser()->profile());
 
 #if SIMULATE_SERIAL_PORTS
-  ASSERT_TRUE(ExtensionFunctionDispatcher::OverrideFunction(
-      "serial.getDevices", FakeSerialGetDevicesFunctionFactory));
-  ASSERT_TRUE(ExtensionFunctionDispatcher::OverrideFunction(
-      "serial.connect", FakeSerialConnectFunctionFactory));
+  ASSERT_TRUE(OverrideFunction("serial.getDevices",
+                               FakeSerialGetDevicesFunctionFactory));
+  ASSERT_TRUE(
+      OverrideFunction("serial.connect", FakeSerialConnectFunctionFactory));
 #endif
 
   ASSERT_TRUE(RunExtensionTest("serial/api")) << message_;
diff --git a/extensions/browser/extension_function_dispatcher.cc b/extensions/browser/extension_function_dispatcher.cc
index 97befcd8..a2ec0ef04 100644
--- a/extensions/browser/extension_function_dispatcher.cc
+++ b/extensions/browser/extension_function_dispatcher.cc
@@ -272,12 +272,6 @@
   return GetAssociatedWebContents();
 }
 
-bool ExtensionFunctionDispatcher::OverrideFunction(
-    const std::string& name, ExtensionFunctionFactory factory) {
-  return ExtensionFunctionRegistry::GetInstance()->OverrideFunction(name,
-                                                                    factory);
-}
-
 // static
 void ExtensionFunctionDispatcher::DispatchOnIOThread(
     InfoMap* extension_info_map,
diff --git a/extensions/browser/extension_function_dispatcher.h b/extensions/browser/extension_function_dispatcher.h
index 9aa833f4..073ca0e 100644
--- a/extensions/browser/extension_function_dispatcher.h
+++ b/extensions/browser/extension_function_dispatcher.h
@@ -70,11 +70,6 @@
     virtual ~Delegate() {}
   };
 
-  // Override a previously registered function. Returns true if successful,
-  // false if no such function was registered.
-  static bool OverrideFunction(const std::string& name,
-                               ExtensionFunctionFactory factory);
-
   // Dispatches an IO-thread extension function. Only used for specific
   // functions that must be handled on the IO-thread.
   static void DispatchOnIOThread(
diff --git a/extensions/browser/extension_function_registry.cc b/extensions/browser/extension_function_registry.cc
index 75114e4..714739d 100644
--- a/extensions/browser/extension_function_registry.cc
+++ b/extensions/browser/extension_function_registry.cc
@@ -23,7 +23,7 @@
 
 ExtensionFunctionRegistry::~ExtensionFunctionRegistry() {}
 
-bool ExtensionFunctionRegistry::OverrideFunction(
+bool ExtensionFunctionRegistry::OverrideFunctionForTesting(
     const std::string& name,
     ExtensionFunctionFactory factory) {
   FactoryMap::iterator iter = factories_.find(name);
diff --git a/extensions/browser/extension_function_registry.h b/extensions/browser/extension_function_registry.h
index 128f5d0..4904036 100644
--- a/extensions/browser/extension_function_registry.h
+++ b/extensions/browser/extension_function_registry.h
@@ -46,10 +46,10 @@
   explicit ExtensionFunctionRegistry();
   virtual ~ExtensionFunctionRegistry();
 
-  // Allows overriding of specific functions (e.g. for testing).  Functions
-  // must be previously registered.  Returns true if successful.
-  bool OverrideFunction(const std::string& name,
-                        ExtensionFunctionFactory factory);
+  // Allows overriding of specific functions for testing.  Functions must be
+  // previously registered.  Returns true if successful.
+  bool OverrideFunctionForTesting(const std::string& name,
+                                  ExtensionFunctionFactory factory);
 
   // Factory method for the ExtensionFunction registered as 'name'.
   ExtensionFunction* NewFunction(const std::string& name);
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index d9b33a7..ad8b044e 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -5042,19 +5042,19 @@
     [self registerLoadRequest:navigationURL
                      referrer:self.currentNavItemReferrer
                    transition:self.currentTransition];
+    WKNavigation* navigation = nil;
     if (navigationURL == net::GURLWithNSURL([_webView URL])) {
-      [_navigationStates setState:web::WKNavigationState::REQUESTED
-                    forNavigation:[_webView reload]];
+      navigation = [_webView reload];
     } else {
       // |didCommitNavigation:| may not be called for fast navigation, so update
       // the navigation type now as it is already known.
       holder->set_navigation_type(WKNavigationTypeBackForward);
-      WKNavigation* navigation =
+      navigation =
           [_webView goToBackForwardListItem:holder->back_forward_list_item()];
-      [_navigationStates setState:web::WKNavigationState::REQUESTED
-                    forNavigation:navigation];
       [self reportBackForwardNavigationTypeForFastNavigation:YES];
     }
+    [_navigationStates setState:web::WKNavigationState::REQUESTED
+                  forNavigation:navigation];
   };
 
   // If the request is not a form submission or resubmission, or the user
diff --git a/media/gpu/dxva_video_decode_accelerator_win.cc b/media/gpu/dxva_video_decode_accelerator_win.cc
index 135d4e3..d7a3865 100644
--- a/media/gpu/dxva_video_decode_accelerator_win.cc
+++ b/media/gpu/dxva_video_decode_accelerator_win.cc
@@ -798,7 +798,7 @@
 
 bool DXVAVideoDecodeAccelerator::CreateDX11DevManager() {
   // The device may exist if the last state was a config change.
-  if (d3d11_device_.Get())
+  if (D3D11Device())
     return true;
   HRESULT hr = create_dxgi_device_manager_(&dx11_dev_manager_reset_token_,
                                            d3d11_device_manager_.Receive());
@@ -811,8 +811,9 @@
     RETURN_ON_FAILURE(angle_device_.Get(), "Failed to get d3d11 device", false);
 
     using_angle_device_ = true;
-    d3d11_device_ = angle_device_;
-  } else {
+  }
+
+  if (use_fp16_ || !share_nv12_textures_) {
     // This array defines the set of DirectX hardware feature levels we support.
     // The ordering MUST be preserved. All applications are assumed to support
     // 9.1 unless otherwise stated by the application.
@@ -855,7 +856,7 @@
   }
 
   D3D11_FEATURE_DATA_D3D11_OPTIONS options;
-  hr = d3d11_device_->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options,
+  hr = D3D11Device()->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options,
                                           sizeof(options));
   RETURN_ON_HR_FAILURE(hr, "Failed to retrieve D3D11 options", false);
 
@@ -866,14 +867,14 @@
 
   UINT nv12_format_support = 0;
   hr =
-      d3d11_device_->CheckFormatSupport(DXGI_FORMAT_NV12, &nv12_format_support);
+      D3D11Device()->CheckFormatSupport(DXGI_FORMAT_NV12, &nv12_format_support);
   RETURN_ON_HR_FAILURE(hr, "Failed to check NV12 format support", false);
 
   if (!(nv12_format_support & D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT))
     copy_nv12_textures_ = false;
 
   UINT fp16_format_support = 0;
-  hr = d3d11_device_->CheckFormatSupport(DXGI_FORMAT_R16G16B16A16_FLOAT,
+  hr = D3D11Device()->CheckFormatSupport(DXGI_FORMAT_R16G16B16A16_FLOAT,
                                          &fp16_format_support);
   if (FAILED(hr) ||
       !(fp16_format_support & D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT))
@@ -883,18 +884,18 @@
   // context are synchronized across threads. We have multiple threads
   // accessing the context, the media foundation decoder threads and the
   // decoder thread via the video format conversion transform.
-  hr = multi_threaded_.QueryFrom(d3d11_device_.Get());
+  hr = multi_threaded_.QueryFrom(D3D11Device());
   RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D10Multithread", false);
   multi_threaded_->SetMultithreadProtected(TRUE);
 
-  hr = d3d11_device_manager_->ResetDevice(d3d11_device_.Get(),
+  hr = d3d11_device_manager_->ResetDevice(D3D11Device(),
                                           dx11_dev_manager_reset_token_);
   RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false);
 
   D3D11_QUERY_DESC query_desc;
   query_desc.Query = D3D11_QUERY_EVENT;
   query_desc.MiscFlags = 0;
-  hr = d3d11_device_->CreateQuery(&query_desc, d3d11_query_.Receive());
+  hr = D3D11Device()->CreateQuery(&query_desc, d3d11_query_.Receive());
   RETURN_ON_HR_FAILURE(hr, "Failed to create DX11 device query", false);
 
   return true;
@@ -1759,8 +1760,8 @@
       (state == kNormal || state == kFlushing || state == kStopped),
       "DoDecode: not in normal/flushing/stopped state", ILLEGAL_STATE, );
 
-  if (d3d11_device_)
-    g_last_device_removed_reason = d3d11_device_->GetDeviceRemovedReason();
+  if (D3D11Device())
+    g_last_device_removed_reason = D3D11Device()->GetDeviceRemovedReason();
 
   MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0};
   DWORD status = 0;
@@ -2992,4 +2993,8 @@
   return provide_nv12_textures ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
 }
 
+ID3D11Device* DXVAVideoDecodeAccelerator::D3D11Device() const {
+  return share_nv12_textures_ ? angle_device_.Get() : d3d11_device_.Get();
+}
+
 }  // namespace media
diff --git a/media/gpu/dxva_video_decode_accelerator_win.h b/media/gpu/dxva_video_decode_accelerator_win.h
index 6f45519..1e46411 100644
--- a/media/gpu/dxva_video_decode_accelerator_win.h
+++ b/media/gpu/dxva_video_decode_accelerator_win.h
@@ -374,6 +374,8 @@
 
   uint32_t GetTextureTarget() const;
 
+  ID3D11Device* D3D11Device() const;
+
   // To expose client callbacks from VideoDecodeAccelerator.
   VideoDecodeAccelerator::Client* client_;
 
diff --git a/net/ftp/ftp_network_transaction_unittest.cc b/net/ftp/ftp_network_transaction_unittest.cc
index 33ae123..bf7b29e9 100644
--- a/net/ftp/ftp_network_transaction_unittest.cc
+++ b/net/ftp/ftp_network_transaction_unittest.cc
@@ -4,10 +4,10 @@
 
 #include "net/ftp/ftp_network_transaction.h"
 
-#include "build/build_config.h"
+#include <deque>
 
-#include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -65,6 +65,7 @@
         data_type_('I') {
     Init();
   }
+  ~FtpSocketDataProvider() override {}
 
   // SocketDataProvider implementation.
   MockRead OnRead() override {
@@ -244,8 +245,8 @@
 
 class FtpSocketDataProviderDirectoryListing : public FtpSocketDataProvider {
  public:
-  FtpSocketDataProviderDirectoryListing() {
-  }
+  FtpSocketDataProviderDirectoryListing() {}
+  ~FtpSocketDataProviderDirectoryListing() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -271,8 +272,8 @@
 class FtpSocketDataProviderDirectoryListingWithPasvFallback
     : public FtpSocketDataProviderDirectoryListing {
  public:
-  FtpSocketDataProviderDirectoryListingWithPasvFallback() {
-  }
+  FtpSocketDataProviderDirectoryListingWithPasvFallback() {}
+  ~FtpSocketDataProviderDirectoryListingWithPasvFallback() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -294,31 +295,10 @@
       FtpSocketDataProviderDirectoryListingWithPasvFallback);
 };
 
-class FtpSocketDataProviderDirectoryListingZeroSize
-    : public FtpSocketDataProviderDirectoryListing {
- public:
-  FtpSocketDataProviderDirectoryListingZeroSize() {
-  }
-
-  MockWriteResult OnWrite(const std::string& data) override {
-    if (InjectFault())
-      return MockWriteResult(ASYNC, data.length());
-    switch (state()) {
-      case PRE_SIZE:
-        return Verify("SIZE /\r\n", data, PRE_CWD, "213 0\r\n");
-      default:
-        return FtpSocketDataProviderDirectoryListing::OnWrite(data);
-    }
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderDirectoryListingZeroSize);
-};
-
 class FtpSocketDataProviderVMSDirectoryListing : public FtpSocketDataProvider {
  public:
-  FtpSocketDataProviderVMSDirectoryListing() {
-  }
+  FtpSocketDataProviderVMSDirectoryListing() {}
+  ~FtpSocketDataProviderVMSDirectoryListing() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -352,8 +332,8 @@
 class FtpSocketDataProviderVMSDirectoryListingRootDirectory
     : public FtpSocketDataProvider {
  public:
-  FtpSocketDataProviderVMSDirectoryListingRootDirectory() {
-  }
+  FtpSocketDataProviderVMSDirectoryListingRootDirectory() {}
+  ~FtpSocketDataProviderVMSDirectoryListingRootDirectory() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -388,8 +368,8 @@
 class FtpSocketDataProviderFileDownloadWithFileTypecode
     : public FtpSocketDataProvider {
  public:
-  FtpSocketDataProviderFileDownloadWithFileTypecode() {
-  }
+  FtpSocketDataProviderFileDownloadWithFileTypecode() {}
+  ~FtpSocketDataProviderFileDownloadWithFileTypecode() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -411,8 +391,8 @@
 
 class FtpSocketDataProviderFileDownload : public FtpSocketDataProvider {
  public:
-  FtpSocketDataProviderFileDownload() {
-  }
+  FtpSocketDataProviderFileDownload() {}
+  ~FtpSocketDataProviderFileDownload() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -439,6 +419,7 @@
     : public FtpSocketDataProvider {
  public:
   FtpSocketDataProviderPathSeparatorsNotUnescaped() {}
+  ~FtpSocketDataProviderPathSeparatorsNotUnescaped() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -465,8 +446,8 @@
 
 class FtpSocketDataProviderFileNotFound : public FtpSocketDataProvider {
  public:
-  FtpSocketDataProviderFileNotFound() {
-  }
+  FtpSocketDataProviderFileNotFound() {}
+  ~FtpSocketDataProviderFileNotFound() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -494,8 +475,8 @@
 class FtpSocketDataProviderFileDownloadWithPasvFallback
     : public FtpSocketDataProviderFileDownload {
  public:
-  FtpSocketDataProviderFileDownloadWithPasvFallback() {
-  }
+  FtpSocketDataProviderFileDownloadWithPasvFallback() {}
+  ~FtpSocketDataProviderFileDownloadWithPasvFallback() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -519,8 +500,8 @@
 class FtpSocketDataProviderFileDownloadZeroSize
     : public FtpSocketDataProviderFileDownload {
  public:
-  FtpSocketDataProviderFileDownloadZeroSize() {
-  }
+  FtpSocketDataProviderFileDownloadZeroSize() {}
+  ~FtpSocketDataProviderFileDownloadZeroSize() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -545,8 +526,8 @@
 class FtpSocketDataProviderFileDownloadCWD451
     : public FtpSocketDataProviderFileDownload {
  public:
-  FtpSocketDataProviderFileDownloadCWD451() {
-  }
+  FtpSocketDataProviderFileDownloadCWD451() {}
+  ~FtpSocketDataProviderFileDownloadCWD451() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -567,8 +548,8 @@
 
 class FtpSocketDataProviderVMSFileDownload : public FtpSocketDataProvider {
  public:
-  FtpSocketDataProviderVMSFileDownload() {
-  }
+  FtpSocketDataProviderVMSFileDownload() {}
+  ~FtpSocketDataProviderVMSFileDownload() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -603,8 +584,8 @@
 
 class FtpSocketDataProviderEscaping : public FtpSocketDataProviderFileDownload {
  public:
-  FtpSocketDataProviderEscaping() {
-  }
+  FtpSocketDataProviderEscaping() {}
+  ~FtpSocketDataProviderEscaping() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -629,60 +610,11 @@
   DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderEscaping);
 };
 
-class FtpSocketDataProviderFileDownloadTransferStarting
-    : public FtpSocketDataProviderFileDownload {
- public:
-  FtpSocketDataProviderFileDownloadTransferStarting() {
-  }
-
-  MockWriteResult OnWrite(const std::string& data) override {
-    if (InjectFault())
-      return MockWriteResult(ASYNC, data.length());
-    switch (state()) {
-      case PRE_RETR:
-        return Verify("RETR /file\r\n", data, PRE_QUIT,
-                      "125-Data connection already open.\r\n"
-                      "125  Transfer starting.\r\n"
-                      "226 Transfer complete.\r\n");
-      default:
-        return FtpSocketDataProviderFileDownload::OnWrite(data);
-    }
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderFileDownloadTransferStarting);
-};
-
-class FtpSocketDataProviderDirectoryListingTransferStarting
-    : public FtpSocketDataProviderDirectoryListing {
- public:
-  FtpSocketDataProviderDirectoryListingTransferStarting() {
-  }
-
-  MockWriteResult OnWrite(const std::string& data) override {
-    if (InjectFault())
-      return MockWriteResult(ASYNC, data.length());
-    switch (state()) {
-      case PRE_LIST:
-        return Verify("LIST -l\r\n", data, PRE_QUIT,
-                      "125-Data connection already open.\r\n"
-                      "125  Transfer starting.\r\n"
-                      "226 Transfer complete.\r\n");
-      default:
-        return FtpSocketDataProviderDirectoryListing::OnWrite(data);
-    }
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(
-      FtpSocketDataProviderDirectoryListingTransferStarting);
-};
-
 class FtpSocketDataProviderFileDownloadInvalidResponse
     : public FtpSocketDataProviderFileDownload {
  public:
-  FtpSocketDataProviderFileDownloadInvalidResponse() {
-  }
+  FtpSocketDataProviderFileDownloadInvalidResponse() {}
+  ~FtpSocketDataProviderFileDownloadInvalidResponse() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -718,6 +650,8 @@
         epsv_response_length_(epsv_response_length),
         expected_state_(expected_state) {}
 
+  ~FtpSocketDataProviderEvilEpsv() override {}
+
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
       return MockWriteResult(ASYNC, data.length());
@@ -731,7 +665,7 @@
   }
 
  private:
-  const char* epsv_response_;
+  const char* const epsv_response_;
   const size_t epsv_response_length_;
   const State expected_state_;
 
@@ -745,6 +679,7 @@
       : pasv_response_(pasv_response),
         expected_state_(expected_state) {
   }
+  ~FtpSocketDataProviderEvilPasv() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -758,7 +693,7 @@
   }
 
  private:
-  const char* pasv_response_;
+  const char* const pasv_response_;
   const State expected_state_;
 
   DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderEvilPasv);
@@ -770,6 +705,7 @@
       : size_response_(size_response),
         expected_state_(expected_state) {
   }
+  ~FtpSocketDataProviderEvilSize() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -783,7 +719,7 @@
   }
 
  private:
-  const char* size_response_;
+  const char* const size_response_;
   const State expected_state_;
 
   DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderEvilSize);
@@ -797,6 +733,7 @@
       : expected_user_(expected_user),
         expected_password_(expected_password) {
   }
+  ~FtpSocketDataProviderEvilLogin() override {}
 
   MockWriteResult OnWrite(const std::string& data) override {
     if (InjectFault())
@@ -814,51 +751,12 @@
   }
 
  private:
-  const char* expected_user_;
-  const char* expected_password_;
+  const char* const expected_user_;
+  const char* const expected_password_;
 
   DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderEvilLogin);
 };
 
-class FtpSocketDataProviderCloseConnection : public FtpSocketDataProvider {
- public:
-  FtpSocketDataProviderCloseConnection() {
-  }
-
-  MockWriteResult OnWrite(const std::string& data) override {
-    if (InjectFault())
-      return MockWriteResult(ASYNC, data.length());
-    switch (state()) {
-      case PRE_USER:
-        return Verify("USER anonymous\r\n", data,
-                      PRE_QUIT, "");
-      default:
-        return FtpSocketDataProvider::OnWrite(data);
-    }
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderCloseConnection);
-};
-
-class BorkedFtpSocketDataProvider : public FtpSocketDataProvider {
- public:
-  BorkedFtpSocketDataProvider() {}
-  ~BorkedFtpSocketDataProvider() override {}
-
-  MockWriteResult OnWrite(const std::string& data) override {
-    switch (state()) {
-      case PRE_USER:
-        return Verify("USER anonymous\r\n", data, PRE_PASSWD, "957 Spam\r\n");
-      default:
-        return FtpSocketDataProvider::OnWrite(data);
-    }
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BorkedFtpSocketDataProvider);
-};
-
 class FtpNetworkTransactionTest
     : public PlatformTest,
       public ::testing::WithParamInterface<int> {
@@ -877,14 +775,15 @@
     }
     host_resolver_->set_rules(rules.get());
   }
+  ~FtpNetworkTransactionTest() override {}
 
   // Sets up an FtpNetworkTransaction and MocketClientSocketFactory, replacing
   // the default one. Only needs to be called if a test runs multiple
   // transactions.
   void SetUpTransaction() {
-    mock_socket_factory_.reset(new MockClientSocketFactory());
-    transaction_.reset(new FtpNetworkTransaction(host_resolver_.get(),
-                                                 mock_socket_factory_.get()));
+    mock_socket_factory_ = base::MakeUnique<MockClientSocketFactory>();
+    transaction_ = base::MakeUnique<FtpNetworkTransaction>(
+        host_resolver_.get(), mock_socket_factory_.get());
   }
 
  protected:
@@ -916,9 +815,9 @@
       MockRead(mock_data.c_str()),
     };
 
-    std::unique_ptr<StaticSocketDataProvider> data_socket(
-        new StaticSocketDataProvider(data_reads, arraysize(data_reads), NULL,
-                                     0));
+    std::unique_ptr<StaticSocketDataProvider> data_socket =
+        base::MakeUnique<StaticSocketDataProvider>(
+            data_reads, arraysize(data_reads), nullptr, 0);
     mock_socket_factory_->AddSocketDataProvider(data_socket.get());
     FtpRequestInfo request_info = GetRequestInfo(request);
     EXPECT_EQ(LOAD_STATE_IDLE, transaction_->GetLoadState());
@@ -968,7 +867,7 @@
 TEST_P(FtpNetworkTransactionTest, FailedLookup) {
   FtpRequestInfo request_info = GetRequestInfo("ftp://badhost");
   scoped_refptr<RuleBasedHostResolverProc> rules(
-      new RuleBasedHostResolverProc(NULL));
+      new RuleBasedHostResolverProc(nullptr));
   rules->AddSimulatedFailure("badhost");
   host_resolver_->set_rules(rules.get());
 
@@ -1056,7 +955,9 @@
 
 // Regression test for http://crbug.com/60555.
 TEST_P(FtpNetworkTransactionTest, DirectoryTransactionZeroSize) {
-  FtpSocketDataProviderDirectoryListingZeroSize ctrl_socket;
+  FtpSocketDataProviderDirectoryListing ctrl_socket;
+  ctrl_socket.InjectFailure(FtpSocketDataProvider::PRE_SIZE,
+                            FtpSocketDataProvider::PRE_CWD, "213 0\r\n");
   ExecuteTransaction(&ctrl_socket, "ftp://host", OK);
 }
 
@@ -1071,7 +972,12 @@
 }
 
 TEST_P(FtpNetworkTransactionTest, DirectoryTransactionTransferStarting) {
-  FtpSocketDataProviderDirectoryListingTransferStarting ctrl_socket;
+  FtpSocketDataProviderDirectoryListing ctrl_socket;
+  ctrl_socket.InjectFailure(FtpSocketDataProvider::PRE_LIST,
+                            FtpSocketDataProvider::PRE_QUIT,
+                            "125-Data connection already open.\r\n"
+                            "125  Transfer starting.\r\n"
+                            "226 Transfer complete.\r\n");
   ExecuteTransaction(&ctrl_socket, "ftp://host", OK);
 }
 
@@ -1145,7 +1051,12 @@
 }
 
 TEST_P(FtpNetworkTransactionTest, DownloadTransactionTransferStarting) {
-  FtpSocketDataProviderFileDownloadTransferStarting ctrl_socket;
+  FtpSocketDataProviderFileDownload ctrl_socket;
+  ctrl_socket.InjectFailure(FtpSocketDataProvider::PRE_RETR,
+                            FtpSocketDataProvider::PRE_QUIT,
+                            "125-Data connection already open.\r\n"
+                            "125  Transfer starting.\r\n"
+                            "226 Transfer complete.\r\n");
   ExecuteTransaction(&ctrl_socket, "ftp://host/file", OK);
 }
 
@@ -1225,7 +1136,7 @@
   };
   StaticSocketDataProvider data_socket1;
   StaticSocketDataProvider data_socket2(data_reads, arraysize(data_reads),
-                                        NULL, 0);
+                                        nullptr, 0);
   mock_socket_factory_->AddSocketDataProvider(&ctrl_socket);
   mock_socket_factory_->AddSocketDataProvider(&data_socket1);
   mock_socket_factory_->AddSocketDataProvider(&data_socket2);
@@ -1514,7 +1425,9 @@
 
 // Regression test for http://crbug.com/25023.
 TEST_P(FtpNetworkTransactionTest, CloseConnection) {
-  FtpSocketDataProviderCloseConnection ctrl_socket;
+  FtpSocketDataProvider ctrl_socket;
+  ctrl_socket.InjectFailure(FtpSocketDataProvider::PRE_USER,
+                            FtpSocketDataProvider::PRE_QUIT, "");
   ExecuteTransaction(&ctrl_socket, "ftp://host", ERR_EMPTY_RESPONSE);
 }
 
@@ -1808,7 +1721,7 @@
       "257 \"foo\nbar\" is your current location\r\n", ERR_INVALID_RESPONSE);
 }
 
-INSTANTIATE_TEST_CASE_P(FTP,
+INSTANTIATE_TEST_CASE_P(Ftp,
                         FtpNetworkTransactionTest,
                         ::testing::Values(AF_INET, AF_INET6));
 
diff --git a/net/http/http_stream_factory_impl_job_controller.cc b/net/http/http_stream_factory_impl_job_controller.cc
index b4a6bd46..6b052ad 100644
--- a/net/http/http_stream_factory_impl_job_controller.cc
+++ b/net/http/http_stream_factory_impl_job_controller.cc
@@ -636,16 +636,16 @@
 
 void HttpStreamFactoryImpl::JobController::
     RemoveRequestFromSpdySessionRequestMap() {
-  const SpdySessionKey* spdy_session_key = request_->spdy_session_key();
-  if (spdy_session_key) {
+  if (request_->HasSpdySessionKey()) {
+    const SpdySessionKey& spdy_session_key = request_->GetSpdySessionKey();
     SpdySessionRequestMap& spdy_session_request_map =
         factory_->spdy_session_request_map_;
-    DCHECK(base::ContainsKey(spdy_session_request_map, *spdy_session_key));
-    RequestSet& request_set = spdy_session_request_map[*spdy_session_key];
+    DCHECK(base::ContainsKey(spdy_session_request_map, spdy_session_key));
+    RequestSet& request_set = spdy_session_request_map[spdy_session_key];
     DCHECK(base::ContainsKey(request_set, request_));
     request_set.erase(request_);
     if (request_set.empty())
-      spdy_session_request_map.erase(*spdy_session_key);
+      spdy_session_request_map.erase(spdy_session_key);
     request_->ResetSpdySessionKey();
   }
 }
diff --git a/net/http/http_stream_factory_impl_request.cc b/net/http/http_stream_factory_impl_request.cc
index 76abed6..8cefe1d4 100644
--- a/net/http/http_stream_factory_impl_request.cc
+++ b/net/http/http_stream_factory_impl_request.cc
@@ -44,11 +44,6 @@
   helper_->OnRequestComplete();
 }
 
-void HttpStreamFactoryImpl::Request::SetSpdySessionKey(
-    const SpdySessionKey& spdy_session_key) {
-  spdy_session_key_.reset(new SpdySessionKey(spdy_session_key));
-}
-
 void HttpStreamFactoryImpl::Request::Complete(bool was_alpn_negotiated,
                                               NextProto negotiated_protocol,
                                               bool using_spdy) {
@@ -154,16 +149,6 @@
   return connection_attempts_;
 }
 
-void HttpStreamFactoryImpl::Request::ResetSpdySessionKey() {
-  if (spdy_session_key_.get()) {
-    spdy_session_key_.reset();
-  }
-}
-
-bool HttpStreamFactoryImpl::Request::HasSpdySessionKey() const {
-  return spdy_session_key_.get() != NULL;
-}
-
 void HttpStreamFactoryImpl::Request::AddConnectionAttempts(
     const ConnectionAttempts& attempts) {
   for (const auto& attempt : attempts)
diff --git a/net/http/http_stream_factory_impl_request.h b/net/http/http_stream_factory_impl_request.h
index 703dedd..266dd44 100644
--- a/net/http/http_stream_factory_impl_request.h
+++ b/net/http/http_stream_factory_impl_request.h
@@ -9,6 +9,7 @@
 #include <set>
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "net/base/net_export.h"
 #include "net/http/http_stream_factory_impl.h"
 #include "net/log/net_log_with_source.h"
@@ -63,16 +64,23 @@
   // for the Request. Note that this does not mean that SPDY is necessarily
   // supported for this SpdySessionKey, since we may need to wait for NPN to
   // complete before knowing if SPDY is available.
-  void SetSpdySessionKey(const SpdySessionKey& spdy_session_key);
-  bool HasSpdySessionKey() const;
+  void SetSpdySessionKey(const SpdySessionKey& spdy_session_key) {
+    spdy_session_key_ = spdy_session_key;
+  }
+  bool HasSpdySessionKey() const { return spdy_session_key_.has_value(); }
+  const SpdySessionKey& GetSpdySessionKey() const {
+    DCHECK(HasSpdySessionKey());
+    return spdy_session_key_.value();
+  }
+  void ResetSpdySessionKey() { spdy_session_key_.reset(); }
+
+  HttpStreamRequest::StreamType stream_type() const { return stream_type_; }
 
   // Marks completion of the request. Must be called before OnStreamReady().
   void Complete(bool was_alpn_negotiated,
                 NextProto negotiated_protocol,
                 bool using_spdy);
 
-  void ResetSpdySessionKey();
-
   // Called by |helper_| to record connection attempts made by the socket
   // layer in an attached Job for this stream request.
   void AddConnectionAttempts(const ConnectionAttempts& attempts);
@@ -84,7 +92,6 @@
 
   // HttpStreamRequest::Delegate methods which we implement. Note we don't
   // actually subclass HttpStreamRequest::Delegate.
-
   void OnStreamReady(const SSLConfig& used_ssl_config,
                      const ProxyInfo& used_proxy_info,
                      HttpStream* stream);
@@ -112,7 +119,6 @@
       HttpStream* stream);
 
   // HttpStreamRequest methods.
-
   int RestartTunnelWithProxyAuth() override;
   void SetPriority(RequestPriority priority) override;
   LoadState GetLoadState() const override;
@@ -120,10 +126,6 @@
   NextProto negotiated_protocol() const override;
   bool using_spdy() const override;
   const ConnectionAttempts& connection_attempts() const override;
-  HttpStreamRequest::StreamType stream_type() const { return stream_type_; }
-  const SpdySessionKey* spdy_session_key() const {
-    return spdy_session_key_.get();
-  }
 
  private:
   const GURL url_;
@@ -136,7 +138,7 @@
   HttpStreamRequest::Delegate* const delegate_;
   const NetLogWithSource net_log_;
 
-  std::unique_ptr<const SpdySessionKey> spdy_session_key_;
+  base::Optional<SpdySessionKey> spdy_session_key_;
 
   bool completed_;
   bool was_alpn_negotiated_;
diff --git a/net/quic/core/congestion_control/bbr_sender.cc b/net/quic/core/congestion_control/bbr_sender.cc
index 666a9d7..cd7e59c3 100644
--- a/net/quic/core/congestion_control/bbr_sender.cc
+++ b/net/quic/core/congestion_control/bbr_sender.cc
@@ -46,6 +46,12 @@
 // will exit the STARTUP mode.
 const float kStartupGrowthTarget = 1.25;
 const QuicRoundTripCount kRoundTripsWithoutGrowthBeforeExitingStartup = 3;
+
+// Maintain ack history for this fraction of the smoothed RTT.
+const float kRecentlyAckedRttFraction = 0.5f;
+// Minimum period over which ack history will be maintained.
+const QuicTime::Delta kMinAckHistory = QuicTime::Delta::FromMilliseconds(5);
+
 }  // namespace
 
 BbrSender::DebugState::DebugState(const BbrSender& sender)
@@ -93,10 +99,14 @@
       pacing_gain_(1),
       congestion_window_gain_(1),
       congestion_window_gain_constant_(
-          static_cast<float>(GetQuicFlag(FLAGS_quic_bbr_cwnd_gain))),
+          static_cast<float>(FLAGS_quic_bbr_cwnd_gain)),
       rtt_variance_weight_(
-          static_cast<float>(GetQuicFlag(FLAGS_quic_bbr_rtt_variation_weight))),
+          static_cast<float>(FLAGS_quic_bbr_rtt_variation_weight)),
       num_startup_rtts_(kRoundTripsWithoutGrowthBeforeExitingStartup),
+      congestion_window_gain_for_slow_delivery_(
+          static_cast<float>(FLAGS_quic_bbr_slow_delivery_cwnd_gain)),
+      threshold_multiplier_for_slow_delivery_(static_cast<float>(
+          FLAGS_quic_bbr_slow_delivery_threshold_multiplier)),
       cycle_current_offset_(0),
       last_cycle_start_(QuicTime::Zero()),
       is_at_full_bandwidth_(false),
@@ -108,7 +118,8 @@
       last_sample_is_app_limited_(false),
       recovery_state_(NOT_IN_RECOVERY),
       end_recovery_at_(0),
-      recovery_window_(max_congestion_window_) {
+      recovery_window_(max_congestion_window_),
+      bytes_recently_acked_(0) {
   EnterStartupMode();
 }
 
@@ -134,11 +145,45 @@
   return is_retransmittable == HAS_RETRANSMITTABLE_DATA;
 }
 
-QuicTime::Delta BbrSender::TimeUntilSend(QuicTime /* now */,
-                                         QuicByteCount bytes_in_flight) const {
+bool BbrSender::SlowDeliveryAllowsSending(QuicTime now,
+                                          QuicByteCount bytes_in_flight) {
+  if (mode_ != BbrSender::PROBE_BW) {
+    return false;
+  }
+  UpdateRecentlyAcked(now, 0u);
+  // Set a (large) limit to how much we send into a blackhole.
+  if (bytes_in_flight >=
+      congestion_window_gain_for_slow_delivery_ * GetCongestionWindow()) {
+    return false;
+  }
+  // If no acks were recorded in the recent past, continue sending.
+  if (recently_acked_.empty()) {
+    return true;
+  }
+  // Compute the time period over which acks should have been recorded.
+  QuicTime::Delta ack_period =
+      std::max(now - recently_acked_.front().ack_time,
+               std::max(kMinAckHistory, kRecentlyAckedRttFraction *
+                                            rtt_stats_->smoothed_rtt()));
+  // If delivery rate is less than BW by a factor of threshold_multiplier_,
+  // ack rate has suddenly decreased substantially. Continue sending.
+  if (BandwidthEstimate() * ack_period >
+      threshold_multiplier_for_slow_delivery_ * bytes_recently_acked_) {
+    return true;
+  }
+  return false;
+}
+
+QuicTime::Delta BbrSender::TimeUntilSend(QuicTime now,
+                                         QuicByteCount bytes_in_flight) {
   if (bytes_in_flight < GetCongestionWindow()) {
     return QuicTime::Delta::Zero();
   }
+  if (FLAGS_quic_reloadable_flag_quic_bbr_slow_recent_delivery &&
+      SlowDeliveryAllowsSending(now, bytes_in_flight)) {
+    QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_slow_recent_delivery, 2, 2);
+    return QuicTime::Delta::Zero();
+  }
   return QuicTime::Delta::Infinite();
 }
 
@@ -247,6 +292,14 @@
     min_rtt_expired = UpdateBandwidthAndMinRtt(event_time, acked_packets);
     UpdateRecoveryState(last_acked_packet, !lost_packets.empty(),
                         is_round_start);
+
+    if (FLAGS_quic_reloadable_flag_quic_bbr_slow_recent_delivery) {
+      QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_slow_recent_delivery, 1,
+                        2);
+      UpdateRecentlyAcked(
+          event_time, sampler_.total_bytes_acked() - total_bytes_acked_before);
+    }
+
     if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes) {
       QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_aggregation_bytes, 1,
                         2);
@@ -515,11 +568,51 @@
       // Exit recovery if appropriate.
       if (!has_losses && last_acked_packet > end_recovery_at_) {
         recovery_state_ = NOT_IN_RECOVERY;
+        return;
+      }
+
+      if (!FLAGS_quic_reloadable_flag_quic_bbr_extra_conservation) {
+        return;
+      }
+
+      // Use "single round in conservation" approach outside of PROBE_BW.
+      if (mode_ != PROBE_BW) {
+        return;
+      }
+
+      // Switch between conservation and growth depending on position in the
+      // gain cycle.
+      if (cycle_current_offset_ == 0 ||
+          cycle_current_offset_ == kGainCycleLength - 1) {
+        recovery_state_ = GROWTH;
+      } else {
+        recovery_state_ = CONSERVATION;
       }
       break;
   }
 }
 
+void BbrSender::UpdateRecentlyAcked(QuicTime new_ack_time,
+                                    QuicByteCount newly_acked_bytes) {
+  // Discard information stored for acks received too far in the past.
+  QuicTime::Delta recent_period = std::max(
+      kMinAckHistory, kRecentlyAckedRttFraction * rtt_stats_->smoothed_rtt());
+  while (!recently_acked_.empty() &&
+         (recently_acked_.front().ack_time + recent_period < new_ack_time)) {
+    DCHECK_GE(bytes_recently_acked_, recently_acked_.front().acked_bytes);
+    bytes_recently_acked_ -= recently_acked_.front().acked_bytes;
+    recently_acked_.pop_front();
+  }
+  // Nothing to add to recently_acked_ if no new ack.
+  if (newly_acked_bytes == 0)
+    return;
+  // Add information for new ack
+  DataDelivered new_ack = {new_ack_time, newly_acked_bytes};
+  recently_acked_.push_back(new_ack);
+  bytes_recently_acked_ += newly_acked_bytes;
+}
+
+// TODO(ianswett): Move this logic into BandwidthSampler.
 void BbrSender::UpdateAckAggregationBytes(QuicTime ack_time,
                                           QuicByteCount newly_acked_bytes) {
   // Compute how many bytes are expected to be delivered, assuming max bandwidth
diff --git a/net/quic/core/congestion_control/bbr_sender.h b/net/quic/core/congestion_control/bbr_sender.h
index 9a6cd7e3..cc76f76 100644
--- a/net/quic/core/congestion_control/bbr_sender.h
+++ b/net/quic/core/congestion_control/bbr_sender.h
@@ -119,7 +119,7 @@
   void OnRetransmissionTimeout(bool packets_retransmitted) override {}
   void OnConnectionMigration() override {}
   QuicTime::Delta TimeUntilSend(QuicTime now,
-                                QuicByteCount bytes_in_flight) const override;
+                                QuicByteCount bytes_in_flight) override;
   QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override;
   QuicBandwidth BandwidthEstimate() const override;
   QuicByteCount GetCongestionWindow() const override;
@@ -196,6 +196,16 @@
                            bool has_losses,
                            bool is_round_start);
 
+  // Returns true if recent ack rate has decreased substantially and if sender
+  // is allowed to continue sending when congestion window limited.
+  bool SlowDeliveryAllowsSending(QuicTime now, QuicByteCount bytes_in_flight);
+
+  // Updates history of recently received acks. Acks are considered recent
+  // if received within kRecentlyAckedRttFraction x smoothed RTT in the past.
+  // Adds new ack to recently_acked_ if |newly_acked_bytes| is non-zero.
+  void UpdateRecentlyAcked(QuicTime new_ack_time,
+                           QuicByteCount newly_acked_bytes);
+
   // Updates the ack aggregation max filter in bytes.
   void UpdateAckAggregationBytes(QuicTime ack_time,
                                  QuicByteCount newly_acked_bytes);
@@ -270,6 +280,13 @@
   // The number of RTTs to stay in STARTUP mode.  Defaults to 3.
   QuicRoundTripCount num_startup_rtts_;
 
+  // Gain to use when delivery rate is slow.
+  // TODO(jri): Make this a constant if we decide to use this code for BBR.
+  const float congestion_window_gain_for_slow_delivery_;
+  // Threshold multiplier below which delivery is considered slow.
+  // TODO(jri): Make this a constant if we decide to use this code for BBR.
+  const float threshold_multiplier_for_slow_delivery_;
+
   // Number of round-trips in PROBE_BW mode, used for determining the current
   // pacing gain cycle.
   int cycle_current_offset_;
@@ -305,6 +322,17 @@
   // A window used to limit the number of bytes in flight during loss recovery.
   QuicByteCount recovery_window_;
 
+  // Records information about a received ack
+  struct DataDelivered {
+    QuicTime ack_time;
+    QuicByteCount acked_bytes;
+  };
+
+  // Data structure to record recently received acks. Used for determining
+  // recently seen ack rate over a short period in the past.
+  std::deque<DataDelivered> recently_acked_;
+  QuicByteCount bytes_recently_acked_;
+
   DISALLOW_COPY_AND_ASSIGN(BbrSender);
 };
 
diff --git a/net/quic/core/congestion_control/bbr_sender_test.cc b/net/quic/core/congestion_control/bbr_sender_test.cc
index f89c8ad..872b863 100644
--- a/net/quic/core/congestion_control/bbr_sender_test.cc
+++ b/net/quic/core/congestion_control/bbr_sender_test.cc
@@ -92,6 +92,7 @@
                               {&receiver_, &competing_receiver_}) {
     // TODO(ianswett): Determine why tests become flaky with CWND based on SRTT.
     FLAGS_quic_reloadable_flag_quic_bbr_base_cwnd_on_srtt = false;
+    FLAGS_quic_reloadable_flag_quic_bbr_extra_conservation = true;
     rtt_stats_ = bbr_sender_.connection()->sent_packet_manager().GetRttStats();
     sender_ = SetupBbrSender(&bbr_sender_);
 
@@ -337,7 +338,8 @@
             sender_->ExportDebugState().max_bandwidth);
   // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures
   // bandwidth higher than the link rate.
-  EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited);
+  // TODO(vasilvv): figure out why the line below is occasionally flaky.
+  // EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited);
   // The margin here is high, because the aggregation greatly increases
   // smoothed rtt.
   EXPECT_GE(kTestRtt * 4.5, rtt_stats_->smoothed_rtt());
@@ -348,7 +350,7 @@
 TEST_F(BbrSenderTest, SimpleTransferAckDecimation) {
   FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes = true;
   // Decrease the CWND gain so extra CWND is required with stretch acks.
-  SetQuicFlag(&FLAGS_quic_bbr_cwnd_gain, 1.0);
+  FLAGS_quic_bbr_cwnd_gain = 1.0;
   sender_ = new BbrSender(
       rtt_stats_,
       QuicSentPacketManagerPeer::GetUnackedPacketMap(
@@ -385,7 +387,7 @@
   FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = true;
   FLAGS_quic_reloadable_flag_quic_bbr_keep_sending_at_recent_rate = true;
   // Decrease the CWND gain so extra CWND is required with stretch acks.
-  SetQuicFlag(&FLAGS_quic_bbr_cwnd_gain, 1.0);
+  FLAGS_quic_bbr_cwnd_gain = 1.0;
   sender_ = new BbrSender(
       rtt_stats_,
       QuicSentPacketManagerPeer::GetUnackedPacketMap(
@@ -417,6 +419,38 @@
   ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.1f);
 }
 
+// Test a simple long data transfer with 2 rtts of aggregation.
+TEST_F(BbrSenderTest,
+       SimpleTransfer2RTTAggregationBytesWithIncreasedInflightLimit) {
+  FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes = false;
+  FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd = false;
+  FLAGS_quic_reloadable_flag_quic_bbr_keep_sending_at_recent_rate = false;
+  FLAGS_quic_reloadable_flag_quic_bbr_slow_recent_delivery = true;
+  FLAGS_quic_bbr_slow_delivery_threshold_multiplier = 0.5;
+  FLAGS_quic_bbr_slow_delivery_cwnd_gain = 4.0;
+  CreateDefaultSetup();
+  // 2 RTTs of aggregation, with a max of 10kb.
+  EnableAggregation(10 * 1024, 2 * kTestRtt);
+
+  // Transfer 12MB.
+  DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
+  EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode);
+  // It's possible to read a bandwidth as much as 50% too high with aggregation.
+  EXPECT_LE(kTestLinkBandwidth * 0.99f,
+            sender_->ExportDebugState().max_bandwidth);
+  // TODO(ianswett): Tighten this bound once we understand why BBR is
+  // overestimating bandwidth with aggregation. b/36022633
+  EXPECT_GE(kTestLinkBandwidth * 1.5f,
+            sender_->ExportDebugState().max_bandwidth);
+  // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures
+  // bandwidth higher than the link rate.
+  EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited);
+  // The margin here is high, because the aggregation greatly increases
+  // smoothed rtt.
+  EXPECT_GE(kTestRtt * 4, rtt_stats_->smoothed_rtt());
+  ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.1f);
+}
+
 // Test the number of losses incurred by the startup phase in a situation when
 // the buffer is less than BDP.
 TEST_F(BbrSenderTest, PacketLossOnSmallBufferStartup) {
@@ -432,6 +466,12 @@
 // Ensures the code transitions loss recovery states correctly (NOT_IN_RECOVERY
 // -> CONSERVATION -> GROWTH -> NOT_IN_RECOVERY).
 TEST_F(BbrSenderTest, RecoveryStates) {
+  // Set seed to the position where the gain cycling causes the sender go
+  // into conservation upon entering PROBE_BW.
+  //
+  // TODO(vasilvv): there should be a better way to test this.
+  random_.set_seed(UINT64_C(14719894707049085006));
+
   const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10);
   bool simulator_result;
   CreateSmallBufferSetup();
@@ -464,9 +504,16 @@
         return sender_->ExportDebugState().recovery_state != BbrSender::GROWTH;
       },
       timeout);
+
+  ASSERT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode);
+  if (FLAGS_quic_reloadable_flag_quic_bbr_extra_conservation) {
+    ASSERT_EQ(BbrSender::CONSERVATION,
+              sender_->ExportDebugState().recovery_state);
+  } else {
+    ASSERT_EQ(BbrSender::NOT_IN_RECOVERY,
+              sender_->ExportDebugState().recovery_state);
+  }
   ASSERT_TRUE(simulator_result);
-  ASSERT_EQ(BbrSender::NOT_IN_RECOVERY,
-            sender_->ExportDebugState().recovery_state);
 }
 
 // Verify the behavior of the algorithm in the case when the connection sends
diff --git a/net/quic/core/congestion_control/send_algorithm_interface.h b/net/quic/core/congestion_control/send_algorithm_interface.h
index dacccba..5abb3e9 100644
--- a/net/quic/core/congestion_control/send_algorithm_interface.h
+++ b/net/quic/core/congestion_control/send_algorithm_interface.h
@@ -82,9 +82,8 @@
   virtual void OnConnectionMigration() = 0;
 
   // Calculate the time until we can send the next packet.
-  virtual QuicTime::Delta TimeUntilSend(
-      QuicTime now,
-      QuicByteCount bytes_in_flight) const = 0;
+  virtual QuicTime::Delta TimeUntilSend(QuicTime now,
+                                        QuicByteCount bytes_in_flight) = 0;
 
   // The pacing rate of the send algorithm.  May be zero if the rate is unknown.
   virtual QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const = 0;
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_base.cc b/net/quic/core/congestion_control/tcp_cubic_sender_base.cc
index 151cc3e..d56fbf8 100644
--- a/net/quic/core/congestion_control/tcp_cubic_sender_base.cc
+++ b/net/quic/core/congestion_control/tcp_cubic_sender_base.cc
@@ -188,7 +188,7 @@
 
 QuicTime::Delta TcpCubicSenderBase::TimeUntilSend(
     QuicTime /* now */,
-    QuicByteCount bytes_in_flight) const {
+    QuicByteCount bytes_in_flight) {
   if (!no_prr_ && InRecovery()) {
     // PRR is used when in recovery.
     return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight,
diff --git a/net/quic/core/congestion_control/tcp_cubic_sender_base.h b/net/quic/core/congestion_control/tcp_cubic_sender_base.h
index a4ac1e57..2488bf2 100644
--- a/net/quic/core/congestion_control/tcp_cubic_sender_base.h
+++ b/net/quic/core/congestion_control/tcp_cubic_sender_base.h
@@ -62,7 +62,7 @@
   void OnRetransmissionTimeout(bool packets_retransmitted) override;
   void OnConnectionMigration() override;
   QuicTime::Delta TimeUntilSend(QuicTime now,
-                                QuicByteCount bytes_in_flight) const override;
+                                QuicByteCount bytes_in_flight) override;
   QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override;
   QuicBandwidth BandwidthEstimate() const override;
   bool InSlowStart() const override;
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h
index e59f187..d1bc575e 100644
--- a/net/quic/core/quic_flags_list.h
+++ b/net/quic/core/quic_flags_list.h
@@ -204,3 +204,16 @@
 // If true, enable random padding of size [1, 256] when response body is
 // compressed for QUIC version >= 38.
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_random_padding, false)
+
+// Use conservation in PROBE_BW ouside of super-unity gain and immediately
+// preceeding cycle.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_extra_conservation, false)
+
+// Increase BBR's inflight limit if recent ack rate is low.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_slow_recent_delivery, false)
+
+// Congestion window gain for QUIC BBR during slow delivery.
+QUIC_FLAG(double, FLAGS_quic_bbr_slow_delivery_cwnd_gain, 4.0f)
+
+// Threshold multiplier below which delivery is considered slow.
+QUIC_FLAG(double, FLAGS_quic_bbr_slow_delivery_threshold_multiplier, 0.5f)
diff --git a/net/quic/core/quic_version_manager.cc b/net/quic/core/quic_version_manager.cc
index fb8bdf0..7652813 100644
--- a/net/quic/core/quic_version_manager.cc
+++ b/net/quic/core/quic_version_manager.cc
@@ -10,7 +10,7 @@
 namespace net {
 
 QuicVersionManager::QuicVersionManager(QuicVersionVector supported_versions)
-    : enable_version_39_(GetQuicFlag(FLAGS_quic_enable_version_39)),
+    : enable_version_39_(FLAGS_quic_enable_version_39),
       enable_version_38_(FLAGS_quic_reloadable_flag_quic_enable_version_38),
       allowed_supported_versions_(supported_versions),
       filtered_supported_versions_(
@@ -24,9 +24,9 @@
 }
 
 void QuicVersionManager::MaybeRefilterSupportedVersions() {
-  if (enable_version_39_ != GetQuicFlag(FLAGS_quic_enable_version_39) ||
+  if (enable_version_39_ != FLAGS_quic_enable_version_39 ||
       enable_version_38_ != FLAGS_quic_reloadable_flag_quic_enable_version_38) {
-    enable_version_39_ = GetQuicFlag(FLAGS_quic_enable_version_39);
+    enable_version_39_ = FLAGS_quic_enable_version_39;
     enable_version_38_ = FLAGS_quic_reloadable_flag_quic_enable_version_38;
     RefilterSupportedVersions();
   }
diff --git a/net/quic/core/quic_version_manager_test.cc b/net/quic/core/quic_version_manager_test.cc
index 05691b55..b2ddbf5 100644
--- a/net/quic/core/quic_version_manager_test.cc
+++ b/net/quic/core/quic_version_manager_test.cc
@@ -30,7 +30,7 @@
   EXPECT_EQ(QUIC_VERSION_36, manager.GetSupportedVersions()[2]);
   EXPECT_EQ(QUIC_VERSION_35, manager.GetSupportedVersions()[3]);
 
-  SetQuicFlag(&FLAGS_quic_enable_version_39, true);
+  FLAGS_quic_enable_version_39 = true;
   EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
             manager.GetSupportedVersions());
   ASSERT_EQ(5u, manager.GetSupportedVersions().size());
diff --git a/net/quic/core/quic_versions.cc b/net/quic/core/quic_versions.cc
index b94997d..4a9583b2 100644
--- a/net/quic/core/quic_versions.cc
+++ b/net/quic/core/quic_versions.cc
@@ -31,7 +31,7 @@
   filtered_versions.clear();  // Guaranteed by spec not to change capacity.
   for (QuicVersion version : versions) {
     if (version == QUIC_VERSION_39) {
-      if (GetQuicFlag(FLAGS_quic_enable_version_39) &&
+      if (FLAGS_quic_enable_version_39 &&
           FLAGS_quic_reloadable_flag_quic_enable_version_38) {
         filtered_versions.push_back(version);
       }
diff --git a/net/quic/core/quic_versions_test.cc b/net/quic/core/quic_versions_test.cc
index 0b392a9e..42493cf 100644
--- a/net/quic/core/quic_versions_test.cc
+++ b/net/quic/core/quic_versions_test.cc
@@ -147,7 +147,7 @@
                                     QUIC_VERSION_39};
 
   FLAGS_quic_reloadable_flag_quic_enable_version_38 = true;
-  SetQuicFlag(&FLAGS_quic_enable_version_39, false);
+  FLAGS_quic_enable_version_39 = false;
 
   QuicVersionVector filtered_versions = FilterSupportedVersions(all_versions);
   ASSERT_EQ(4u, filtered_versions.size());
@@ -164,7 +164,7 @@
                                     QUIC_VERSION_39};
 
   FLAGS_quic_reloadable_flag_quic_enable_version_38 = true;
-  SetQuicFlag(&FLAGS_quic_enable_version_39, true);
+  FLAGS_quic_enable_version_39 = true;
 
   QuicVersionVector filtered_versions = FilterSupportedVersions(all_versions);
   ASSERT_EQ(all_versions, filtered_versions);
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 1eb3868e..f30363d1 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -758,9 +758,8 @@
   MOCK_METHOD1(OnRetransmissionTimeout, void(bool));
   MOCK_METHOD0(OnConnectionMigration, void());
   MOCK_METHOD0(RevertRetransmissionTimeout, void());
-  MOCK_CONST_METHOD2(TimeUntilSend,
-                     QuicTime::Delta(QuicTime now,
-                                     QuicByteCount bytes_in_flight));
+  MOCK_METHOD2(TimeUntilSend,
+               QuicTime::Delta(QuicTime now, QuicByteCount bytes_in_flight));
   MOCK_CONST_METHOD1(PacingRate, QuicBandwidth(QuicByteCount));
   MOCK_CONST_METHOD0(BandwidthEstimate, QuicBandwidth(void));
   MOCK_CONST_METHOD0(HasReliableBandwidthEstimate, bool());
diff --git a/net/tools/quic/platform/impl/quic_socket_utils.cc b/net/tools/quic/platform/impl/quic_socket_utils.cc
index d602ac35..621767c 100644
--- a/net/tools/quic/platform/impl/quic_socket_utils.cc
+++ b/net/tools/quic/platform/impl/quic_socket_utils.cc
@@ -10,6 +10,7 @@
 #include <string.h>
 #include <sys/socket.h>
 #include <sys/uio.h>
+#include <unistd.h>
 #include <string>
 
 #include "net/quic/core/quic_packets.h"
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index 3f3f235..2b582dde 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -535,7 +535,7 @@
   static_assert(arraysize(kSupportedQuicVersions) == 5u,
                 "Supported versions out of sync");
   FLAGS_quic_reloadable_flag_quic_enable_version_38 = true;
-  SetQuicFlag(&FLAGS_quic_enable_version_39, true);
+  FLAGS_quic_enable_version_39 = true;
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
   QuicConnectionId connection_id = 1;
@@ -575,7 +575,7 @@
                 PACKET_6BYTE_PACKET_NUMBER, 1);
 
   // Turn off version 39.
-  SetQuicFlag(&FLAGS_quic_enable_version_39, false);
+  FLAGS_quic_enable_version_39 = false;
   ++connection_id;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
       .Times(0);
@@ -584,7 +584,7 @@
                 PACKET_6BYTE_PACKET_NUMBER, 1);
 
   // Turn on version 39.
-  SetQuicFlag(&FLAGS_quic_enable_version_39, true);
+  FLAGS_quic_enable_version_39 = true;
   ++connection_id;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
       .WillOnce(testing::Return(CreateSession(
diff --git a/services/ui/gpu/gpu_main.cc b/services/ui/gpu/gpu_main.cc
index ba01980..580e5b4fc 100644
--- a/services/ui/gpu/gpu_main.cc
+++ b/services/ui/gpu/gpu_main.cc
@@ -166,6 +166,7 @@
     cc::mojom::FrameSinkManagerRequest request,
     cc::mojom::FrameSinkManagerClientPtrInfo client_info) {
   DCHECK(!gpu_command_service_);
+  DCHECK(gpu_service_);
   gpu_command_service_ = new gpu::GpuInProcessThreadService(
       gpu_thread_task_runner_, gpu_service_->sync_point_manager(),
       gpu_service_->mailbox_manager(), gpu_service_->share_group());
diff --git a/styleguide/styleguide.md b/styleguide/styleguide.md
index 4af45ddd..1a24bb5e 100644
--- a/styleguide/styleguide.md
+++ b/styleguide/styleguide.md
@@ -43,6 +43,6 @@
 
 ## Web languages (JavaScript, HTML, CSS)
 
-When working on Web-based UI features, consult the [Web Development Style Guide](https://sites.google.com/a/chromium.org/dev/developers/web-development-style-guide) for the Chromium conventions used in JS/CSS/HTML files.
+When working on Web-based UI features, consult the [Web Development Style Guide](web/web.md) for the Chromium conventions used in JS/CSS/HTML files.
 
 Internal uses of web languages, notably "layout" tests, should preferably follow these style guides, but it is not enforced.
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index 584f799..8e9191c 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -1412,6 +1412,7 @@
 crbug.com/589265 virtual/threaded/animations/animated-filter-svg-element.html [ Failure Crash ]
 
 # Some work remains to fully support composited animation and scrolling.
+Bug(none) virtual/threaded/animations/css-animation-affects-use-elements.html [ Failure ]
 Bug(none) virtual/threaded/animations/composited-animation-style-update.html [ Failure ]
 crbug.com/702350 transitions/opacity-transform-transitions-inside-iframe.html [ Timeout ]
 crbug.com/702350 virtual/threaded/transitions/opacity-transform-transitions-inside-iframe.html [ Timeout ]
@@ -1420,7 +1421,7 @@
 crbug.com/702353 virtual/threaded/transitions/extra-transition.html [ Timeout ]
 crbug.com/702365 virtual/threaded/animations/composited-filter-webkit-filter.html [ Failure ]
 crbug.com/702370 virtual/threaded/animations/compositor-independent-transform-cancel.html [ Failure ]
-crbug.com/702379 virtual/threaded/animations/skew-notsequential-compositor.html [ Failure ]
+crbug.com/702379 virtual/threaded/animations/skew-notsequential-compositor.html [ Failure Crash ]
 crbug.com/692310 virtual/threaded/animations/3d/replace-filling-transform.html [ Crash ]
 crbug.com/692310 virtual/threaded/animations/change-transform-style-during-animation.html [ Crash ]
 crbug.com/692310 virtual/threaded/animations/fill-mode-transform.html [ Crash ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/media-capabilities/idlharness-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/media-capabilities/idlharness-expected.txt
index 44200e0..8a6f9d9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/media-capabilities/idlharness-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/media-capabilities/idlharness-expected.txt
@@ -20,6 +20,8 @@
 FAIL MediaCapabilities interface: operation decodingInfo(MediaDecodingConfiguration) assert_throws: calling operation with this = null didn't throw TypeError function "function () {
             fn.apply(obj, args);
         }" did not throw
-FAIL MediaCapabilities interface: operation encodingInfo(MediaEncodingConfiguration) assert_own_property: interface prototype object missing non-static operation expected property "encodingInfo" missing
+FAIL MediaCapabilities interface: operation encodingInfo(MediaEncodingConfiguration) assert_throws: calling operation with this = null didn't throw TypeError function "function () {
+            fn.apply(obj, args);
+        }" did not throw
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-expected.txt b/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-expected.txt
index 389da5ae..f4fb539 100644
--- a/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE WARNING: line 1: The rtcpMuxPolicy option is being considered for removal and may be removed no earlier than M60, around August 2017. If you depend on it, please see https://www.chromestatus.com/features/5654810086866944 for more details.
+CONSOLE WARNING: line 1: The rtcpMuxPolicy option is being considered for removal and may be removed no earlier than M62, around October 2017. If you depend on it, please see https://www.chromestatus.com/features/5654810086866944 for more details.
 CONSOLE WARNING: line 1: Unknown constraint named invalid rejected
 CONSOLE WARNING: line 1: Unknown constraint named valid_but_unsupported_1 rejected
 CONSOLE WARNING: line 1: Unknown constraint named valid_but_unsupported_1 rejected
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-constants.js b/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-constants.js
new file mode 100644
index 0000000..bc2e35d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-constants.js
@@ -0,0 +1,376 @@
+// Copyright 2017 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-wasm
+
+function bytes() {
+  var buffer = new ArrayBuffer(arguments.length);
+  var view = new Uint8Array(buffer);
+  for (var i = 0; i < arguments.length; i++) {
+    var val = arguments[i];
+    if ((typeof val) == "string") val = val.charCodeAt(0);
+    view[i] = val | 0;
+  }
+  return buffer;
+}
+
+// Header declaration constants
+var kWasmH0 = 0;
+var kWasmH1 = 0x61;
+var kWasmH2 = 0x73;
+var kWasmH3 = 0x6d;
+
+var kWasmV0 = 0x1;
+var kWasmV1 = 0;
+var kWasmV2 = 0;
+var kWasmV3 = 0;
+
+var kHeaderSize = 8;
+var kPageSize = 65536;
+
+function bytesWithHeader() {
+  var buffer = new ArrayBuffer(kHeaderSize + arguments.length);
+  var view = new Uint8Array(buffer);
+  view[0] = kWasmH0;
+  view[1] = kWasmH1;
+  view[2] = kWasmH2;
+  view[3] = kWasmH3;
+  view[4] = kWasmV0;
+  view[5] = kWasmV1;
+  view[6] = kWasmV2;
+  view[7] = kWasmV3;
+  for (var i = 0; i < arguments.length; i++) {
+    var val = arguments[i];
+    if ((typeof val) == "string") val = val.charCodeAt(0);
+    view[kHeaderSize + i] = val | 0;
+  }
+  return buffer;
+}
+
+let kDeclNoLocals = 0;
+
+// Section declaration constants
+let kUnknownSectionCode = 0;
+let kTypeSectionCode = 1;      // Function signature declarations
+let kImportSectionCode = 2;    // Import declarations
+let kFunctionSectionCode = 3;  // Function declarations
+let kTableSectionCode = 4;     // Indirect function table and other tables
+let kMemorySectionCode = 5;    // Memory attributes
+let kGlobalSectionCode = 6;    // Global declarations
+let kExportSectionCode = 7;    // Exports
+let kStartSectionCode = 8;     // Start function declaration
+let kElementSectionCode = 9;  // Elements section
+let kCodeSectionCode = 10;      // Function code
+let kDataSectionCode = 11;     // Data segments
+let kNameSectionCode = 12;     // Name section (encoded as string)
+
+let kWasmFunctionTypeForm = 0x60;
+let kWasmAnyFunctionTypeForm = 0x70;
+
+let kResizableMaximumFlag = 1;
+
+// Function declaration flags
+let kDeclFunctionName   = 0x01;
+let kDeclFunctionImport = 0x02;
+let kDeclFunctionLocals = 0x04;
+let kDeclFunctionExport = 0x08;
+
+// Local types
+let kWasmStmt = 0x40;
+let kWasmI32 = 0x7f;
+let kWasmI64 = 0x7e;
+let kWasmF32 = 0x7d;
+let kWasmF64 = 0x7c;
+let kWasmS128 = 0x7b;
+
+let kExternalFunction = 0;
+let kExternalTable = 1;
+let kExternalMemory = 2;
+let kExternalGlobal = 3;
+
+let kTableZero = 0;
+let kMemoryZero = 0;
+
+// Useful signatures
+let kSig_i_i = makeSig([kWasmI32], [kWasmI32]);
+let kSig_l_l = makeSig([kWasmI64], [kWasmI64]);
+let kSig_i_l = makeSig([kWasmI64], [kWasmI32]);
+let kSig_i_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32]);
+let kSig_i_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], [kWasmI32]);
+let kSig_d_dd = makeSig([kWasmF64, kWasmF64], [kWasmF64]);
+let kSig_l_ll = makeSig([kWasmI64, kWasmI64], [kWasmI64]);
+let kSig_i_dd = makeSig([kWasmF64, kWasmF64], [kWasmI32]);
+let kSig_v_v = makeSig([], []);
+let kSig_i_v = makeSig([], [kWasmI32]);
+let kSig_l_v = makeSig([], [kWasmI64]);
+let kSig_f_v = makeSig([], [kWasmF64]);
+let kSig_d_v = makeSig([], [kWasmF64]);
+let kSig_v_i = makeSig([kWasmI32], []);
+let kSig_v_ii = makeSig([kWasmI32, kWasmI32], []);
+let kSig_v_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], []);
+let kSig_v_l = makeSig([kWasmI64], []);
+let kSig_v_d = makeSig([kWasmF64], []);
+let kSig_v_dd = makeSig([kWasmF64, kWasmF64], []);
+let kSig_v_ddi = makeSig([kWasmF64, kWasmF64, kWasmI32], []);
+let kSig_s_v = makeSig([], [kWasmS128]);
+
+function makeSig(params, results) {
+  return {params: params, results: results};
+}
+
+function makeSig_v_x(x) {
+  return makeSig([x], []);
+}
+
+function makeSig_v_xx(x) {
+  return makeSig([x, x], []);
+}
+
+function makeSig_r_v(r) {
+  return makeSig([], [r]);
+}
+
+function makeSig_r_x(r, x) {
+  return makeSig([x], [r]);
+}
+
+function makeSig_r_xx(r, x) {
+  return makeSig([x, x], [r]);
+}
+
+// Opcodes
+let kExprUnreachable = 0x00;
+let kExprNop = 0x01;
+let kExprBlock = 0x02;
+let kExprLoop = 0x03;
+let kExprIf = 0x04;
+let kExprElse = 0x05;
+let kExprTry = 0x06;
+let kExprCatch = 0x07;
+let kExprThrow = 0x08;
+let kExprEnd = 0x0b;
+let kExprBr = 0x0c;
+let kExprBrIf = 0x0d;
+let kExprBrTable = 0x0e;
+let kExprReturn = 0x0f;
+let kExprCallFunction = 0x10;
+let kExprCallIndirect = 0x11;
+let kExprDrop = 0x1a;
+let kExprSelect = 0x1b;
+let kExprGetLocal = 0x20;
+let kExprSetLocal = 0x21;
+let kExprTeeLocal = 0x22;
+let kExprGetGlobal = 0x23;
+let kExprSetGlobal = 0x24;
+let kExprI32Const = 0x41;
+let kExprI64Const = 0x42;
+let kExprF32Const = 0x43;
+let kExprF64Const = 0x44;
+let kExprI32LoadMem = 0x28;
+let kExprI64LoadMem = 0x29;
+let kExprF32LoadMem = 0x2a;
+let kExprF64LoadMem = 0x2b;
+let kExprI32LoadMem8S = 0x2c;
+let kExprI32LoadMem8U = 0x2d;
+let kExprI32LoadMem16S = 0x2e;
+let kExprI32LoadMem16U = 0x2f;
+let kExprI64LoadMem8S = 0x30;
+let kExprI64LoadMem8U = 0x31;
+let kExprI64LoadMem16S = 0x32;
+let kExprI64LoadMem16U = 0x33;
+let kExprI64LoadMem32S = 0x34;
+let kExprI64LoadMem32U = 0x35;
+let kExprI32StoreMem = 0x36;
+let kExprI64StoreMem = 0x37;
+let kExprF32StoreMem = 0x38;
+let kExprF64StoreMem = 0x39;
+let kExprI32StoreMem8 = 0x3a;
+let kExprI32StoreMem16 = 0x3b;
+let kExprI64StoreMem8 = 0x3c;
+let kExprI64StoreMem16 = 0x3d;
+let kExprI64StoreMem32 = 0x3e;
+let kExprMemorySize = 0x3f;
+let kExprGrowMemory = 0x40;
+let kExprI32Eqz = 0x45;
+let kExprI32Eq = 0x46;
+let kExprI32Ne = 0x47;
+let kExprI32LtS = 0x48;
+let kExprI32LtU = 0x49;
+let kExprI32GtS = 0x4a;
+let kExprI32GtU = 0x4b;
+let kExprI32LeS = 0x4c;
+let kExprI32LeU = 0x4d;
+let kExprI32GeS = 0x4e;
+let kExprI32GeU = 0x4f;
+let kExprI64Eqz = 0x50;
+let kExprI64Eq = 0x51;
+let kExprI64Ne = 0x52;
+let kExprI64LtS = 0x53;
+let kExprI64LtU = 0x54;
+let kExprI64GtS = 0x55;
+let kExprI64GtU = 0x56;
+let kExprI64LeS = 0x57;
+let kExprI64LeU = 0x58;
+let kExprI64GeS = 0x59;
+let kExprI64GeU = 0x5a;
+let kExprF32Eq = 0x5b;
+let kExprF32Ne = 0x5c;
+let kExprF32Lt = 0x5d;
+let kExprF32Gt = 0x5e;
+let kExprF32Le = 0x5f;
+let kExprF32Ge = 0x60;
+let kExprF64Eq = 0x61;
+let kExprF64Ne = 0x62;
+let kExprF64Lt = 0x63;
+let kExprF64Gt = 0x64;
+let kExprF64Le = 0x65;
+let kExprF64Ge = 0x66;
+let kExprI32Clz = 0x67;
+let kExprI32Ctz = 0x68;
+let kExprI32Popcnt = 0x69;
+let kExprI32Add = 0x6a;
+let kExprI32Sub = 0x6b;
+let kExprI32Mul = 0x6c;
+let kExprI32DivS = 0x6d;
+let kExprI32DivU = 0x6e;
+let kExprI32RemS = 0x6f;
+let kExprI32RemU = 0x70;
+let kExprI32And = 0x71;
+let kExprI32Ior = 0x72;
+let kExprI32Xor = 0x73;
+let kExprI32Shl = 0x74;
+let kExprI32ShrS = 0x75;
+let kExprI32ShrU = 0x76;
+let kExprI32Rol = 0x77;
+let kExprI32Ror = 0x78;
+let kExprI64Clz = 0x79;
+let kExprI64Ctz = 0x7a;
+let kExprI64Popcnt = 0x7b;
+let kExprI64Add = 0x7c;
+let kExprI64Sub = 0x7d;
+let kExprI64Mul = 0x7e;
+let kExprI64DivS = 0x7f;
+let kExprI64DivU = 0x80;
+let kExprI64RemS = 0x81;
+let kExprI64RemU = 0x82;
+let kExprI64And = 0x83;
+let kExprI64Ior = 0x84;
+let kExprI64Xor = 0x85;
+let kExprI64Shl = 0x86;
+let kExprI64ShrS = 0x87;
+let kExprI64ShrU = 0x88;
+let kExprI64Rol = 0x89;
+let kExprI64Ror = 0x8a;
+let kExprF32Abs = 0x8b;
+let kExprF32Neg = 0x8c;
+let kExprF32Ceil = 0x8d;
+let kExprF32Floor = 0x8e;
+let kExprF32Trunc = 0x8f;
+let kExprF32NearestInt = 0x90;
+let kExprF32Sqrt = 0x91;
+let kExprF32Add = 0x92;
+let kExprF32Sub = 0x93;
+let kExprF32Mul = 0x94;
+let kExprF32Div = 0x95;
+let kExprF32Min = 0x96;
+let kExprF32Max = 0x97;
+let kExprF32CopySign = 0x98;
+let kExprF64Abs = 0x99;
+let kExprF64Neg = 0x9a;
+let kExprF64Ceil = 0x9b;
+let kExprF64Floor = 0x9c;
+let kExprF64Trunc = 0x9d;
+let kExprF64NearestInt = 0x9e;
+let kExprF64Sqrt = 0x9f;
+let kExprF64Add = 0xa0;
+let kExprF64Sub = 0xa1;
+let kExprF64Mul = 0xa2;
+let kExprF64Div = 0xa3;
+let kExprF64Min = 0xa4;
+let kExprF64Max = 0xa5;
+let kExprF64CopySign = 0xa6;
+let kExprI32ConvertI64 = 0xa7;
+let kExprI32SConvertF32 = 0xa8;
+let kExprI32UConvertF32 = 0xa9;
+let kExprI32SConvertF64 = 0xaa;
+let kExprI32UConvertF64 = 0xab;
+let kExprI64SConvertI32 = 0xac;
+let kExprI64UConvertI32 = 0xad;
+let kExprI64SConvertF32 = 0xae;
+let kExprI64UConvertF32 = 0xaf;
+let kExprI64SConvertF64 = 0xb0;
+let kExprI64UConvertF64 = 0xb1;
+let kExprF32SConvertI32 = 0xb2;
+let kExprF32UConvertI32 = 0xb3;
+let kExprF32SConvertI64 = 0xb4;
+let kExprF32UConvertI64 = 0xb5;
+let kExprF32ConvertF64 = 0xb6;
+let kExprF64SConvertI32 = 0xb7;
+let kExprF64UConvertI32 = 0xb8;
+let kExprF64SConvertI64 = 0xb9;
+let kExprF64UConvertI64 = 0xba;
+let kExprF64ConvertF32 = 0xbb;
+let kExprI32ReinterpretF32 = 0xbc;
+let kExprI64ReinterpretF64 = 0xbd;
+let kExprF32ReinterpretI32 = 0xbe;
+let kExprF64ReinterpretI64 = 0xbf;
+
+let kTrapUnreachable          = 0;
+let kTrapMemOutOfBounds       = 1;
+let kTrapDivByZero            = 2;
+let kTrapDivUnrepresentable   = 3;
+let kTrapRemByZero            = 4;
+let kTrapFloatUnrepresentable = 5;
+let kTrapFuncInvalid          = 6;
+let kTrapFuncSigMismatch      = 7;
+let kTrapInvalidIndex         = 8;
+
+let kTrapMsgs = [
+  "unreachable",
+  "memory access out of bounds",
+  "divide by zero",
+  "divide result unrepresentable",
+  "remainder by zero",
+  "integer result unrepresentable",
+  "invalid function",
+  "function signature mismatch",
+  "invalid index into function table"
+];
+
+function assertTraps(trap, code) {
+  var threwException = true;
+  try {
+    if (typeof code === 'function') {
+      code();
+    } else {
+      eval(code);
+    }
+    threwException = false;
+  } catch (e) {
+    assertEquals("object", typeof e);
+    assertEquals(kTrapMsgs[trap], e.message);
+    // Success.
+    return;
+  }
+  throw new MjsUnitAssertionError("Did not trap, expected: "
+                                  + kTrapMsgs[trap]);
+}
+
+function assertWasmThrows(value, code) {
+  assertEquals("number", typeof(value));
+  try {
+    if (typeof code === 'function') {
+      code();
+    } else {
+      eval(code);
+    }
+  } catch (e) {
+    assertEquals("number", typeof e);
+    assertEquals(value, e);
+    // Success.
+    return;
+  }
+  throw new MjsUnitAssertionError("Did not throw at all, expected: "
+                                  + value);
+}
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-module-builder.js b/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-module-builder.js
new file mode 100644
index 0000000..0d8c698
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/wasm/resources/wasm-module-builder.js
@@ -0,0 +1,581 @@
+// Copyright 2017 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Used for encoding f32 and double constants to bits.
+let __buffer = new ArrayBuffer(8);
+let byte_view = new Int8Array(__buffer);
+let f32_view = new Float32Array(__buffer);
+let f64_view = new Float64Array(__buffer);
+
+class Binary extends Array {
+  emit_u8(val) {
+    this.push(val);
+  }
+
+  emit_u16(val) {
+    this.push(val & 0xff);
+    this.push((val >> 8) & 0xff);
+  }
+
+  emit_u32(val) {
+    this.push(val & 0xff);
+    this.push((val >> 8) & 0xff);
+    this.push((val >> 16) & 0xff);
+    this.push((val >> 24) & 0xff);
+  }
+
+  emit_u32v(val) {
+    while (true) {
+      let v = val & 0xff;
+      val = val >>> 7;
+      if (val == 0) {
+        this.push(v);
+        break;
+      }
+      this.push(v | 0x80);
+    }
+  }
+
+  emit_bytes(data) {
+    for (let i = 0; i < data.length; i++) {
+      this.push(data[i] & 0xff);
+    }
+  }
+
+  emit_string(string) {
+    // When testing illegal names, we pass a byte array directly.
+    if (string instanceof Array) {
+      this.emit_u32v(string.length);
+      this.emit_bytes(string);
+      return;
+    }
+
+    // This is the hacky way to convert a JavaScript string to a UTF8 encoded
+    // string only containing single-byte characters.
+    let string_utf8 = unescape(encodeURIComponent(string));
+    this.emit_u32v(string_utf8.length);
+    for (let i = 0; i < string_utf8.length; i++) {
+      this.emit_u8(string_utf8.charCodeAt(i));
+    }
+  }
+
+  emit_header() {
+    this.push(kWasmH0, kWasmH1, kWasmH2, kWasmH3,
+              kWasmV0, kWasmV1, kWasmV2, kWasmV3);
+  }
+
+  emit_section(section_code, content_generator) {
+    // Emit section name.
+    this.emit_u8(section_code);
+    // Emit the section to a temporary buffer: its full length isn't know yet.
+    let section = new Binary;
+    content_generator(section);
+    // Emit section length.
+    this.emit_u32v(section.length);
+    // Copy the temporary buffer.
+    this.push(...section);
+  }
+}
+
+class WasmFunctionBuilder {
+  constructor(module, name, type_index) {
+    this.module = module;
+    this.name = name;
+    this.type_index = type_index;
+    this.body = [];
+  }
+
+  exportAs(name) {
+    this.module.addExport(name, this.index);
+    return this;
+  }
+
+  exportFunc() {
+    this.exportAs(this.name);
+    return this;
+  }
+
+  addBody(body) {
+    for (let b of body) {
+      if (typeof b != 'number') throw new Error("invalid body");
+    }
+    this.body = body;
+    // Automatically add the end for the function block to the body.
+    body.push(kExprEnd);
+    return this;
+  }
+
+  addBodyWithEnd(body) {
+    this.body = body;
+    return this;
+  }
+
+  addLocals(locals) {
+    this.locals = locals;
+    return this;
+  }
+
+  end() {
+    return this.module;
+  }
+}
+
+class WasmGlobalBuilder {
+  constructor(module, type, mutable) {
+    this.module = module;
+    this.type = type;
+    this.mutable = mutable;
+    this.init = 0;
+  }
+
+  exportAs(name) {
+    this.module.exports.push({name: name, kind: kExternalGlobal,
+                              index: this.index});
+    return this;
+  }
+}
+
+class WasmModuleBuilder {
+  constructor() {
+    this.types = [];
+    this.imports = [];
+    this.exports = [];
+    this.globals = [];
+    this.functions = [];
+    this.function_table = [];
+    this.function_table_length = 0;
+    this.function_table_inits = [];
+    this.segments = [];
+    this.explicit = [];
+    this.num_imported_funcs = 0;
+    this.num_imported_globals = 0;
+    return this;
+  }
+
+  addStart(start_index) {
+    this.start_index = start_index;
+    return this;
+  }
+
+  addMemory(min, max, exp) {
+    this.memory = {min: min, max: max, exp: exp};
+    return this;
+  }
+
+  addExplicitSection(bytes) {
+    this.explicit.push(bytes);
+    return this;
+  }
+
+  stringToBytes(name) {
+    var result = new Binary();
+    result.emit_u32v(name.length);
+    for (var i = 0; i < name.length; i++) {
+      result.emit_u8(name.charCodeAt(i));
+    }
+    return result;
+  }
+
+  addCustomSection(name, bytes) {
+    name = this.stringToBytes(name);
+    var length = new Binary();
+    length.emit_u32v(name.length + bytes.length);
+    this.explicit.push([0, ...length, ...name, ...bytes]);
+  }
+
+  addType(type) {
+    // TODO: canonicalize types?
+    this.types.push(type);
+    return this.types.length - 1;
+  }
+
+  addGlobal(local_type, mutable) {
+    let glob = new WasmGlobalBuilder(this, local_type, mutable);
+    glob.index = this.globals.length + this.num_imported_globals;
+    this.globals.push(glob);
+    return glob;
+  }
+
+  addFunction(name, type) {
+    let type_index = (typeof type) == "number" ? type : this.addType(type);
+    let func = new WasmFunctionBuilder(this, name, type_index);
+    func.index = this.functions.length + this.num_imported_funcs;
+    this.functions.push(func);
+    return func;
+  }
+
+  addImport(module = "", name, type) {
+    let type_index = (typeof type) == "number" ? type : this.addType(type);
+    this.imports.push({module: module, name: name, kind: kExternalFunction,
+                       type: type_index});
+    return this.num_imported_funcs++;
+  }
+
+  addImportedGlobal(module = "", name, type) {
+    let o = {module: module, name: name, kind: kExternalGlobal, type: type,
+             mutable: false}
+    this.imports.push(o);
+    return this.num_imported_globals++;
+  }
+
+  addImportedMemory(module = "", name, initial = 0, maximum) {
+    let o = {module: module, name: name, kind: kExternalMemory,
+             initial: initial, maximum: maximum};
+    this.imports.push(o);
+    return this;
+  }
+
+  addImportedTable(module = "", name, initial, maximum) {
+    let o = {module: module, name: name, kind: kExternalTable, initial: initial,
+             maximum: maximum};
+    this.imports.push(o);
+  }
+
+  addExport(name, index) {
+    this.exports.push({name: name, kind: kExternalFunction, index: index});
+    return this;
+  }
+
+  addExportOfKind(name, kind, index) {
+    this.exports.push({name: name, kind: kind, index: index});
+    return this;
+  }
+
+  addDataSegment(addr, data, is_global = false) {
+    this.segments.push({addr: addr, data: data, is_global: is_global});
+    return this.segments.length - 1;
+  }
+
+  exportMemoryAs(name) {
+    this.exports.push({name: name, kind: kExternalMemory, index: 0});
+  }
+
+  addFunctionTableInit(base, is_global, array, is_import = false) {
+    this.function_table_inits.push({base: base, is_global: is_global,
+                                    array: array});
+    if (!is_global) {
+      var length = base + array.length;
+      if (length > this.function_table_length && !is_import) {
+        this.function_table_length = length;
+      }
+    }
+    return this;
+  }
+
+  appendToTable(array) {
+    return this.addFunctionTableInit(this.function_table.length, false, array);
+  }
+
+  setFunctionTableLength(length) {
+    this.function_table_length = length;
+    return this;
+  }
+
+  toArray(debug = false) {
+    let binary = new Binary;
+    let wasm = this;
+
+    // Add header
+    binary.emit_header();
+
+    // Add type section
+    if (wasm.types.length > 0) {
+      if (debug) print("emitting types @ " + binary.length);
+      binary.emit_section(kTypeSectionCode, section => {
+        section.emit_u32v(wasm.types.length);
+        for (let type of wasm.types) {
+          section.emit_u8(kWasmFunctionTypeForm);
+          section.emit_u32v(type.params.length);
+          for (let param of type.params) {
+            section.emit_u8(param);
+          }
+          section.emit_u32v(type.results.length);
+          for (let result of type.results) {
+            section.emit_u8(result);
+          }
+        }
+      });
+    }
+
+    // Add imports section
+    if (wasm.imports.length > 0) {
+      if (debug) print("emitting imports @ " + binary.length);
+      binary.emit_section(kImportSectionCode, section => {
+        section.emit_u32v(wasm.imports.length);
+        for (let imp of wasm.imports) {
+          section.emit_string(imp.module);
+          section.emit_string(imp.name || '');
+          section.emit_u8(imp.kind);
+          if (imp.kind == kExternalFunction) {
+            section.emit_u32v(imp.type);
+          } else if (imp.kind == kExternalGlobal) {
+            section.emit_u32v(imp.type);
+            section.emit_u8(imp.mutable);
+          } else if (imp.kind == kExternalMemory) {
+            var has_max = (typeof imp.maximum) != "undefined";
+            section.emit_u8(has_max ? 1 : 0); // flags
+            section.emit_u32v(imp.initial); // initial
+            if (has_max) section.emit_u32v(imp.maximum); // maximum
+          } else if (imp.kind == kExternalTable) {
+            section.emit_u8(kWasmAnyFunctionTypeForm);
+            var has_max = (typeof imp.maximum) != "undefined";
+            section.emit_u8(has_max ? 1 : 0); // flags
+            section.emit_u32v(imp.initial); // initial
+            if (has_max) section.emit_u32v(imp.maximum); // maximum
+          } else {
+            throw new Error("unknown/unsupported import kind " + imp.kind);
+          }
+        }
+      });
+    }
+
+    // Add functions declarations
+    let has_names = false;
+    let names = false;
+    if (wasm.functions.length > 0) {
+      if (debug) print("emitting function decls @ " + binary.length);
+      binary.emit_section(kFunctionSectionCode, section => {
+        section.emit_u32v(wasm.functions.length);
+        for (let func of wasm.functions) {
+          has_names = has_names || (func.name != undefined &&
+                                   func.name.length > 0);
+          section.emit_u32v(func.type_index);
+        }
+      });
+    }
+
+    // Add function_table.
+    if (wasm.function_table_length > 0) {
+      if (debug) print("emitting table @ " + binary.length);
+      binary.emit_section(kTableSectionCode, section => {
+        section.emit_u8(1);  // one table entry
+        section.emit_u8(kWasmAnyFunctionTypeForm);
+        section.emit_u8(1);
+        section.emit_u32v(wasm.function_table_length);
+        section.emit_u32v(wasm.function_table_length);
+      });
+    }
+
+    // Add memory section
+    if (wasm.memory != undefined) {
+      if (debug) print("emitting memory @ " + binary.length);
+      binary.emit_section(kMemorySectionCode, section => {
+        section.emit_u8(1);  // one memory entry
+        section.emit_u32v(kResizableMaximumFlag);
+        section.emit_u32v(wasm.memory.min);
+        section.emit_u32v(wasm.memory.max);
+      });
+    }
+
+    // Add global section.
+    if (wasm.globals.length > 0) {
+      if (debug) print ("emitting globals @ " + binary.length);
+      binary.emit_section(kGlobalSectionCode, section => {
+        section.emit_u32v(wasm.globals.length);
+        for (let global of wasm.globals) {
+          section.emit_u8(global.type);
+          section.emit_u8(global.mutable);
+          if ((typeof global.init_index) == "undefined") {
+            // Emit a constant initializer.
+            switch (global.type) {
+            case kWasmI32:
+              section.emit_u8(kExprI32Const);
+              section.emit_u32v(global.init);
+              break;
+            case kWasmI64:
+              section.emit_u8(kExprI64Const);
+              section.emit_u32v(global.init);
+              break;
+            case kWasmF32:
+              section.emit_u8(kExprF32Const);
+              f32_view[0] = global.init;
+              section.emit_u8(byte_view[0]);
+              section.emit_u8(byte_view[1]);
+              section.emit_u8(byte_view[2]);
+              section.emit_u8(byte_view[3]);
+              break;
+            case kWasmF64:
+              section.emit_u8(kExprF64Const);
+              f64_view[0] = global.init;
+              section.emit_u8(byte_view[0]);
+              section.emit_u8(byte_view[1]);
+              section.emit_u8(byte_view[2]);
+              section.emit_u8(byte_view[3]);
+              section.emit_u8(byte_view[4]);
+              section.emit_u8(byte_view[5]);
+              section.emit_u8(byte_view[6]);
+              section.emit_u8(byte_view[7]);
+              break;
+            }
+          } else {
+            // Emit a global-index initializer.
+            section.emit_u8(kExprGetGlobal);
+            section.emit_u32v(global.init_index);
+          }
+          section.emit_u8(kExprEnd);  // end of init expression
+        }
+      });
+    }
+
+    // Add export table.
+    var mem_export = (wasm.memory != undefined && wasm.memory.exp);
+    var exports_count = wasm.exports.length + (mem_export ? 1 : 0);
+    if (exports_count > 0) {
+      if (debug) print("emitting exports @ " + binary.length);
+      binary.emit_section(kExportSectionCode, section => {
+        section.emit_u32v(exports_count);
+        for (let exp of wasm.exports) {
+          section.emit_string(exp.name);
+          section.emit_u8(exp.kind);
+          section.emit_u32v(exp.index);
+        }
+        if (mem_export) {
+          section.emit_string("memory");
+          section.emit_u8(kExternalMemory);
+          section.emit_u8(0);
+        }
+      });
+    }
+
+    // Add start function section.
+    if (wasm.start_index != undefined) {
+      if (debug) print("emitting start function @ " + binary.length);
+      binary.emit_section(kStartSectionCode, section => {
+        section.emit_u32v(wasm.start_index);
+      });
+    }
+
+    // Add table elements.
+    if (wasm.function_table_inits.length > 0) {
+      if (debug) print("emitting table @ " + binary.length);
+      binary.emit_section(kElementSectionCode, section => {
+        var inits = wasm.function_table_inits;
+        section.emit_u32v(inits.length);
+        section.emit_u8(0); // table index
+
+        for (let init of inits) {
+          if (init.is_global) {
+            section.emit_u8(kExprGetGlobal);
+          } else {
+            section.emit_u8(kExprI32Const);
+          }
+          section.emit_u32v(init.base);
+          section.emit_u8(kExprEnd);
+          section.emit_u32v(init.array.length);
+          for (let index of init.array) {
+            section.emit_u32v(index);
+          }
+        }
+      });
+    }
+
+    // Add function bodies.
+    if (wasm.functions.length > 0) {
+      // emit function bodies
+      if (debug) print("emitting code @ " + binary.length);
+      binary.emit_section(kCodeSectionCode, section => {
+        section.emit_u32v(wasm.functions.length);
+        for (let func of wasm.functions) {
+          // Function body length will be patched later.
+          let local_decls = [];
+          let l = func.locals;
+          if (l != undefined) {
+            let local_decls_count = 0;
+            if (l.i32_count > 0) {
+              local_decls.push({count: l.i32_count, type: kWasmI32});
+            }
+            if (l.i64_count > 0) {
+              local_decls.push({count: l.i64_count, type: kWasmI64});
+            }
+            if (l.f32_count > 0) {
+              local_decls.push({count: l.f32_count, type: kWasmF32});
+            }
+            if (l.f64_count > 0) {
+              local_decls.push({count: l.f64_count, type: kWasmF64});
+            }
+          }
+
+          let header = new Binary;
+          header.emit_u32v(local_decls.length);
+          for (let decl of local_decls) {
+            header.emit_u32v(decl.count);
+            header.emit_u8(decl.type);
+          }
+
+          section.emit_u32v(header.length + func.body.length);
+          section.emit_bytes(header);
+          section.emit_bytes(func.body);
+        }
+      });
+    }
+
+    // Add data segments.
+    if (wasm.segments.length > 0) {
+      if (debug) print("emitting data segments @ " + binary.length);
+      binary.emit_section(kDataSectionCode, section => {
+        section.emit_u32v(wasm.segments.length);
+        for (let seg of wasm.segments) {
+          section.emit_u8(0);  // linear memory index 0
+          if (seg.is_global) {
+            // initializer is a global variable
+            section.emit_u8(kExprGetGlobal);
+            section.emit_u32v(seg.addr);
+          } else {
+            // initializer is a constant
+            section.emit_u8(kExprI32Const);
+            section.emit_u32v(seg.addr);
+          }
+          section.emit_u8(kExprEnd);
+          section.emit_u32v(seg.data.length);
+          section.emit_bytes(seg.data);
+        }
+      });
+    }
+
+    // Add any explicitly added sections
+    for (let exp of wasm.explicit) {
+      if (debug) print("emitting explicit @ " + binary.length);
+      binary.emit_bytes(exp);
+    }
+
+    // Add function names.
+    if (has_names) {
+      if (debug) print("emitting names @ " + binary.length);
+      binary.emit_section(kUnknownSectionCode, section => {
+        section.emit_string("name");
+        var count = wasm.functions.length + wasm.num_imported_funcs;
+        section.emit_u32v(count);
+        for (var i = 0; i < wasm.num_imported_funcs; i++) {
+          section.emit_u8(0); // empty string
+          section.emit_u8(0); // local names count == 0
+        }
+        for (let func of wasm.functions) {
+          var name = func.name == undefined ? "" : func.name;
+          section.emit_string(name);
+          section.emit_u8(0);  // local names count == 0
+        }
+      });
+    }
+
+    return binary;
+  }
+
+  toBuffer(debug = false) {
+    let bytes = this.toArray(debug);
+    let buffer = new ArrayBuffer(bytes.length);
+    let view = new Uint8Array(buffer);
+    for (let i = 0; i < bytes.length; i++) {
+      let val = bytes[i];
+      if ((typeof val) == "string") val = val.charCodeAt(0);
+      view[i] = val | 0;
+    }
+    return buffer;
+  }
+
+  instantiate(ffi) {
+    let module = new WebAssembly.Module(this.toBuffer());
+    let instance = new WebAssembly.Instance(module, ffi);
+    return instance;
+  }
+}
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.html b/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.html
index b6b1d4fb..0e9c22a5 100644
--- a/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.html
+++ b/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.html
@@ -2,11 +2,19 @@
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
 <script src="wasm_response_apis.js"></script>
+<script src="../wasm/resources/wasm-constants.js"></script>
+<script src="../wasm/resources/wasm-module-builder.js"></script>
 <script>
   promise_test(TestStreamedCompile, "test streamed compile");
   promise_test(TestShortFormStreamedCompile, "test streamed compile with promise parameter");
   promise_test(NegativeTestStreamedCompilePromise, "promise must produce a Response");
-  promise_test(BlankResponse, "blank response");
-  promise_test(FromArrayBuffer, "from array buffer");
-  promise_test(FromInvalidArrayBuffer, "from an invalid array buffer");
+  promise_test(CompileBlankResponse, "compile blank response");
+  promise_test(InstantiateBlankResponse, "instantiate blank response");
+  promise_test(CompileFromArrayBuffer, "compile from array buffer");
+  promise_test(CompileFromInvalidArrayBuffer, "compile from an invalid array buffer");
+  promise_test(TestStreamedInstantiate, "test streamed instantiate");
+  promise_test(InstantiateFromArrayBuffer, "test regular instantiate");
+  promise_test(InstantiateFromInvalidArrayBuffer, "test instantiate from invalid buffer");
+  promise_test(TestShortFormStreamedInstantiate, "test streamed instantiate with promise parameter");
+  promise_test(TestInstantiateComplexModule, "instantiate locally built module");
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.js b/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.js
index e8b8f921..26d6e3bd 100644
--- a/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.js
+++ b/third_party/WebKit/LayoutTests/http/tests/wasm_streaming/wasm_response_apis.js
@@ -23,13 +23,19 @@
           e => assert_true(e instanceof TypeError));
 }
 
-function BlankResponse() {
+function CompileBlankResponse() {
   return WebAssembly.compile(new Response())
     .then(assert_unreached,
           e => assert_true(e instanceof TypeError));
 }
 
-function FromArrayBuffer() {
+function InstantiateBlankResponse() {
+  return WebAssembly.instantiate(new Response())
+    .then(assert_unreached,
+          e => assert_true(e instanceof TypeError));
+}
+
+function CompileFromArrayBuffer() {
   return fetch(incrementer_url)
     .then(r => r.arrayBuffer())
     .then(arr => new Response(arr))
@@ -38,7 +44,7 @@
     .then(i => assert_equals(6, i.exports.increment(5)));
 }
 
-function FromInvalidArrayBuffer() {
+function CompileFromInvalidArrayBuffer() {
   var arr = new ArrayBuffer(10);
   var view = new Uint8Array(arr);
   for (var i = 0; i < view.length; ++i) view[i] = i;
@@ -47,3 +53,89 @@
     .then(assert_unreached,
           e => assert_true(e instanceof Error));
 }
+
+function InstantiateFromInvalidArrayBuffer() {
+  var arr = new ArrayBuffer(10);
+  var view = new Uint8Array(arr);
+  for (var i = 0; i < view.length; ++i) view[i] = i;
+
+  return WebAssembly.instantiate(new Response(arr))
+    .then(assert_unreached,
+          e => assert_true(e instanceof Error));
+}
+
+function TestStreamedInstantiate() {
+  return fetch(incrementer_url)
+    .then(WebAssembly.instantiate)
+    .then(pair => assert_equals(5, pair.instance.exports.increment(4)));
+}
+
+function InstantiateFromArrayBuffer() {
+  return fetch(incrementer_url)
+    .then(response => response.arrayBuffer())
+    .then(WebAssembly.instantiate)
+    .then(pair => assert_equals(5, pair.instance.exports.increment(4)));
+}
+
+function TestShortFormStreamedInstantiate() {
+  return WebAssembly.instantiate(fetch(incrementer_url))
+    .then(pair => assert_equals(5, pair.instance.exports.increment(4)));
+}
+
+function InstantiateFromInvalidArrayBuffer() {
+  var arr = new ArrayBuffer(10);
+  var view = new Uint8Array(arr);
+  for (var i = 0; i < view.length; ++i) view[i] = i;
+
+  return WebAssembly.compile(new Response(arr))
+    .then(assert_unreached,
+          e => assert_true(e instanceof Error));
+}
+
+function buildImportingModuleBytes() {
+  var builder = new WasmModuleBuilder();
+  builder.addImportedMemory("", "memory", 1);
+  var kSig_v_i = makeSig([kWasmI32], []);
+  var signature = builder.addType(kSig_v_i);
+  builder.addImport("", "some_value", kSig_i_v);
+  builder.addImport("", "writer", signature);
+
+  builder.addFunction("main", kSig_i_i)
+    .addBody([
+      kExprGetLocal, 0,
+      kExprI32LoadMem, 0, 0,
+      kExprI32Const, 1,
+      kExprCallIndirect, signature, kTableZero,
+      kExprGetLocal,0,
+      kExprI32LoadMem,0, 0,
+      kExprCallFunction, 0,
+      kExprI32Add
+    ]).exportFunc();
+
+  // writer(mem[i]);
+  // return mem[i] + some_value();
+  builder.addFunction("_wrap_writer", signature)
+    .addBody([
+      kExprGetLocal, 0,
+      kExprCallFunction, 1]);
+  builder.appendToTable([2, 3]);
+
+  var wire_bytes = builder.toBuffer();
+  return wire_bytes;
+}
+
+function TestInstantiateComplexModule() {
+  var mem_1 = new WebAssembly.Memory({initial: 1});
+  var view_1 = new Int32Array(mem_1.buffer);
+  view_1[0] = 42;
+  var outval_1;
+
+  var ffi = {"":
+             {some_value: () => 1,
+              writer: (x) => outval_1 = x ,
+              memory: mem_1}
+            };
+  return Promise.resolve(buildImportingModuleBytes())
+    .then(b => WebAssembly.instantiate(b, ffi))
+    .then(pair => assert_true(pair.instance instanceof WebAssembly.Instance));
+}
diff --git a/third_party/WebKit/LayoutTests/media_capabilities/encodingInfo.html b/third_party/WebKit/LayoutTests/media_capabilities/encodingInfo.html
new file mode 100644
index 0000000..cc9ffdb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/media_capabilities/encodingInfo.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<script src=../resources/testharness.js></script>
+<script src=../resources/testharnessreport.js></script>
+<script>
+
+// Check navigator.mediaCapabilities.encodingInfo() with some MIME types that
+// should be recordable and a few that shouldn't.
+
+var createTestForContentType = function(mimeType, isSupported = true) {
+  async_test(function(t) {
+    const media = mimeType.split('/')[0];
+    var queryParameters;
+    if (media == 'video') {
+      queryParameters = {
+        type : 'record',
+        video : {
+          contentType : mimeType,
+          width : 640,
+          height : 480,
+          bitrate : 10000,
+          framerate : 30
+        }
+      };
+    } else if (media == 'audio') {
+      queryParameters = {type : 'record', audio : {contentType : mimeType}};
+    } else {
+      assert_unreached('Unsupported media type');
+    }
+
+    navigator.mediaCapabilities.encodingInfo(queryParameters)
+        .then((result) => {
+          assert_equals(isSupported, result.supported, mimeType + 'supported?');
+          t.done();
+        })
+        .catch(() => {
+          assert_unreached('encodingInfo() ' + mimeType);
+        });
+  });
+};
+
+generate_tests(createTestForContentType, [
+  [ 'video/webm', 'video/webm' ],
+  [ 'video/webm;codecs=vp8', 'video/webm;codecs=vp8' ],
+  [ 'video/webm;codecs=vp9', 'video/webm;codecs=vp9' ],
+  [ 'video/webm;codecs=VP8.0', 'video/webm;codecs=vp8.0' ],
+  [ 'video/webm;codecs=vp9.0', 'video/webm;codecs=vp9.0' ],
+  [ 'video/webm;codecs=h264', 'video/webm;codecs=h264' ],
+  [ 'video/webm;codecs=H264', 'video/webm;codecs=H264' ],
+  [ 'video/webm;codecs=avc1', 'video/webm;codecs=avc1' ],
+  // 'video/webm' supports audio codec specification, see
+  // http://www.webmproject.org/docs/container/
+  [ 'video/webm;codecs=vp8,opus', 'video/webm;codecs=vp8,opus' ],
+  [ 'video/WEBM;codecs=VP8,OPUS', 'video/WEBM;codecs=VP8,OPUS' ],
+  [ 'video/webm;codecs=vp9,opus', 'video/webm;codecs=vp9,opus' ],
+  [ 'video/webm;codecs=vp8,vp9,opus', 'video/webm;codecs=vp8,vp9,opus' ],
+  [ 'video/webm;codecs=h264,opus', 'video/webm;codecs=h264,opus' ],
+  [ 'video/webm;codecs=h264,vp9,opus', 'video/webm;codecs=h264,vp9,opus' ],
+  // https://matroska.org/technical/specs/notes.html#MIME
+  [ 'video/x-matroska;codecs=vorbis', 'video/x-matroska;codecs=opus' ],
+  [ 'audio/webm', 'audio/webm' ],
+  [ 'audio/webm;codecs=opus', 'audio/webm;codecs=opus' ],
+
+  // Rejected MIME types
+  [ 'video/invalid', 'video/invalid', false],
+  [ 'video/mpeg4', 'video/mpeg4', false],
+  [ 'video/webm;codecs=daala', 'video/webm;codecs=daala', false],
+  [ 'audio/invalid', 'audio/invalid', false],
+  [ 'audio/ogg', 'audio/ogg', false],
+  [ 'audio/webm;codecs=vorbis', 'audio/webm;codecs=vorbis', false],
+]);
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
index 960ac76c..65655ea 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
@@ -3934,6 +3934,7 @@
     attribute @@toStringTag
     method constructor
     method decodingInfo
+    method encodingInfo
 interface MediaCapabilitiesInfo
     attribute @@toStringTag
     getter powerEfficient
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 9027ab77..b4001d3 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3934,6 +3934,7 @@
     attribute @@toStringTag
     method constructor
     method decodingInfo
+    method encodingInfo
 interface MediaCapabilitiesInfo
     attribute @@toStringTag
     getter powerEfficient
diff --git a/third_party/WebKit/Source/build/scripts/json5_generator.py b/third_party/WebKit/Source/build/scripts/json5_generator.py
index f2e1f322..7b113eee 100644
--- a/third_party/WebKit/Source/build/scripts/json5_generator.py
+++ b/third_party/WebKit/Source/build/scripts/json5_generator.py
@@ -99,7 +99,7 @@
         self._process(doc)
 
     @classmethod
-    def load_from_files(cls, file_paths, default_metadata, default_parameters=None):
+    def load_from_files(cls, file_paths, default_metadata=None, default_parameters=None):
         merged_doc = dict()
         for path in file_paths:
             assert path.endswith(".json5")
@@ -198,8 +198,6 @@
     def __init__(self, json5_files):
         self._outputs = {}  # file_name -> generator
         self.gperf_path = None
-        if isinstance(json5_files, basestring):
-            json5_files = [json5_files]
         if json5_files:
             self.json5_file = Json5File.load_from_files(json5_files,
                                                         self.default_metadata,
diff --git a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
index c5ec411..533c0cf8 100755
--- a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
+++ b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
@@ -17,66 +17,6 @@
 from collections import OrderedDict
 
 
-# Temporary hard-coded list of fields that are not CSS properties.
-# TODO(shend): Put this into its own JSON5 file.
-NONPROPERTIES = [
-    {'name': 'IsLink', 'field_template': 'monotonic_flag',
-     'inherited': False, 'independent': False, 'default_value': False},
-    {'name': 'OriginalDisplay', 'field_template': 'keyword', 'default_value': 'inline',
-     'type_name': 'EDisplay', 'inherited': False, 'independent': False,
-     'keywords': [
-         "inline", "block", "list-item", "inline-block", "table", "inline-table", "table-row-group", "table-header-group",
-         "table-footer-group", "table-row", "table-column-group", "table-column", "table-cell", "table-caption", "-webkit-box",
-         "-webkit-inline-box", "flex", "inline-flex", "grid", "inline-grid", "contents", "flow-root", "none"
-     ]},
-    {'name': 'InsideLink', 'field_template': 'keyword', 'default_value': 'not-inside-link',
-     'keywords': ['not-inside-link', 'inside-unvisited-link', 'inside-visited-link'],
-     'inherited': True, 'independent': False},
-    # Style can not be shared.
-    {'name': 'Unique', 'field_template': 'monotonic_flag',
-     'inherited': False, 'independent': False, 'default_value': False},
-    # Whether this style is affected by these pseudo-classes.
-    {'name': 'AffectedByFocus', 'field_template': 'monotonic_flag',
-     'inherited': False, 'independent': False, 'default_value': False},
-    {'name': 'AffectedByFocusWithin', 'field_template': 'monotonic_flag',
-     'inherited': False, 'independent': False, 'default_value': False},
-    {'name': 'AffectedByHover', 'field_template': 'monotonic_flag',
-     'inherited': False, 'independent': False, 'default_value': False},
-    {'name': 'AffectedByActive', 'field_template': 'monotonic_flag',
-     'inherited': False, 'independent': False, 'default_value': False},
-    {'name': 'AffectedByDrag', 'field_template': 'monotonic_flag',
-     'inherited': False, 'independent': False, 'default_value': False},
-    # A non-inherited property references a variable or @apply is used
-    {'name': 'HasVariableReferenceFromNonInheritedProperty', 'field_template': 'monotonic_flag',
-     'inherited': False, 'independent': False, 'default_value': False},
-    # Explicitly inherits a non-inherited property
-    {'name': 'HasExplicitlyInheritedProperties', 'field_template': 'monotonic_flag',
-     'inherited': False, 'independent': False, 'default_value': False},
-    # These are set if we used viewport or rem units when resolving a length.
-    # TODO(shend): HasViewportUnits should be a monotonic_flag.
-    {'name': 'HasViewportUnits', 'field_template': 'primitive', 'default_value': 'false',
-     'type_name': 'bool', 'inherited': False, 'independent': False},
-    {'name': 'HasRemUnits', 'field_template': 'monotonic_flag', 'default_value': 'false',
-     'inherited': False, 'independent': False},
-    # These properties only have generated storage, and their methods are handwritten in ComputedStyle.
-    # TODO(shend): Remove these fields and delete the 'storage_only' template.
-    {'name': 'EmptyState', 'field_template': 'storage_only', 'field_size': 1, 'default_value': 'false',
-     'type_name': 'bool', 'inherited': False, 'independent': False},
-    {'name': 'StyleType', 'field_template': 'storage_only', 'field_size': 6, 'default_value': '0',
-     'type_name': 'PseudoId', 'inherited': False, 'independent': False},
-    {'name': 'PseudoBits', 'field_template': 'storage_only', 'field_size': 8, 'default_value': 'kPseudoIdNone',
-     'type_name': 'PseudoId', 'inherited': False, 'independent': False},
-    # True if 'underline solid' is the only text decoration on this element.
-    {'name': 'HasSimpleUnderline', 'field_template': 'storage_only', 'field_size': 1, 'default_value': 'false',
-     'type_name': 'bool', 'inherited': True, 'independent': False},
-    # TODO(shend): vertical align is actually a CSS property, but since we don't support union fields
-    # which can be either a keyword or Length, this is generated as a nonproperty for now. Remove this
-    # once we can support union fields and groups.
-    {'name': 'VerticalAlign', 'field_template': 'storage_only', 'field_size': 4, 'default_value': 'EVerticalAlign::kBaseline',
-     'type_name': 'EVerticalAlign', 'inherited': False, 'independent': False},
-]
-
-
 class Field(object):
     """
     The generated ComputedStyle object is made up of a series of Fields.
@@ -253,7 +193,7 @@
     )
 
 
-def _create_fields(field_role, properties):
+def _create_fields(properties):
     """
     Create ComputedStyle fields from properties or nonproperties and return a list of Field objects.
     """
@@ -266,6 +206,8 @@
             if property_['independent']:
                 fields.append(_create_inherited_flag_field(property_))
 
+            # TODO(shend): Get rid of the property/nonproperty field roles.
+            field_role = 'nonproperty' if property_['has_custom_compare_and_copy'] else 'property'
             fields.append(_create_field(field_role, property_))
 
     return fields
@@ -305,23 +247,9 @@
 
 
 class ComputedStyleBaseWriter(make_style_builder.StyleBuilderWriter):
-    def __init__(self, json5_file_path):
-        super(ComputedStyleBaseWriter, self).__init__(json5_file_path)
-        self._outputs = {
-            'ComputedStyleBase.h': self.generate_base_computed_style_h,
-            'ComputedStyleBase.cpp': self.generate_base_computed_style_cpp,
-            'ComputedStyleBaseConstants.h': self.generate_base_computed_style_constants,
-        }
-
-        # TODO(shend): Remove this once we move NONPROPERTIES to its own JSON file,
-        # since the JSON5 reader will handle missing fields and defaults.
-        for property_ in NONPROPERTIES:
-            for parameter in self.json5_file.parameters:
-                if parameter not in property_:
-                    property_[parameter] = None
-
-        for property_ in NONPROPERTIES:
-            make_style_builder.apply_property_naming_defaults(property_)
+    def __init__(self, json5_file_paths):
+        # Read CSS properties
+        super(ComputedStyleBaseWriter, self).__init__([json5_file_paths[0]])
 
         # Ignore shorthand properties
         for property_ in self._properties.values():
@@ -329,19 +257,33 @@
                 assert not property_['longhands'], \
                     "Shorthand '{}' cannot have a field_template.".format(property_['name'])
 
-        property_values = [value for value in self._properties.values() if not value['longhands']]
+        css_properties = [value for value in self._properties.values() if not value['longhands']]
 
-        for property_ in property_values:
-            # Override the type name when field_type_path is specified
-            if property_['field_type_path']:
-                property_['type_name'] = property_['field_type_path'].split('/')[-1]
+        for property_ in css_properties:
+            # All CSS properties that are generated do not have custom comparison and copy logic.
+            property_['has_custom_compare_and_copy'] = False
             # CSS properties are not allowed to explicitly specify their field_size.
             property_['field_size'] = None
 
-        self._generated_enums = _create_enums(property_values + NONPROPERTIES)
+        # Read extra fields using the parameter specification from the CSS properties file.
+        extra_fields = json5_generator.Json5File.load_from_files(
+            [json5_file_paths[1]],
+            default_parameters=self.json5_file.parameters
+        ).name_dictionaries
 
-        all_fields = (_create_fields('property', property_values) +
-                      _create_fields('nonproperty', NONPROPERTIES))
+        for property_ in extra_fields:
+            make_style_builder.apply_property_naming_defaults(property_)
+
+        all_properties = css_properties + extra_fields
+
+        # Override the type name when field_type_path is specified
+        for property_ in all_properties:
+            if property_['field_type_path']:
+                property_['type_name'] = property_['field_type_path'].split('/')[-1]
+
+        self._generated_enums = _create_enums(all_properties)
+
+        all_fields = _create_fields(all_properties)
 
         # Separate the normal fields from the bit fields
         bit_fields = [field for field in all_fields if field.is_bit_field]
@@ -378,8 +320,12 @@
             for field in bucket:
                 self._fields.append(field)
 
-        self._include_paths = _get_include_paths(property_values + NONPROPERTIES)
-
+        self._include_paths = _get_include_paths(all_properties)
+        self._outputs = {
+            'ComputedStyleBase.h': self.generate_base_computed_style_h,
+            'ComputedStyleBase.cpp': self.generate_base_computed_style_cpp,
+            'ComputedStyleBaseConstants.h': self.generate_base_computed_style_constants,
+        }
 
     @template_expander.use_jinja('ComputedStyleBase.h.tmpl')
     def generate_base_computed_style_h(self):
diff --git a/third_party/WebKit/Source/build/scripts/make_css_property_apis.py b/third_party/WebKit/Source/build/scripts/make_css_property_apis.py
index 1fd786a..c092ae9 100755
--- a/third_party/WebKit/Source/build/scripts/make_css_property_apis.py
+++ b/third_party/WebKit/Source/build/scripts/make_css_property_apis.py
@@ -35,12 +35,12 @@
 
 class CSSPropertyAPIWriter(StyleBuilderWriter):
     def __init__(self, json5_file_paths):
-        super(CSSPropertyAPIWriter, self).__init__(json5_file_paths[0])
+        super(CSSPropertyAPIWriter, self).__init__([json5_file_paths[0]])
         # TODO(aazzam): Move the logic for loading CSSPropertyAPIMethods.json5 into a new class APIMethodsWriter().
         assert len(json5_file_paths) == 2,\
             'CSSPropertyAPIWriter requires 2 input json5 files files, got {}.'.format(len(json5_file_paths))
 
-        self.css_property_api_methods = Json5File.load_from_files([json5_file_paths[1]], {}, {})
+        self.css_property_api_methods = Json5File.load_from_files([json5_file_paths[1]])
 
         self._outputs = {
             'CSSPropertyDescriptor.cpp': self.generate_property_descriptor_cpp,
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 575e0d43..8997ff4 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -410,6 +410,7 @@
 
 css_properties("make_core_generated_computed_style_base") {
   script = "../build/scripts/make_computed_style_base.py"
+  in_files = [ "css/ComputedStyleExtraFields.json5" ]
   other_inputs = [
     "../build/scripts/templates/fields/field.tmpl",
     "../build/scripts/templates/fields/base.tmpl",
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5 b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
new file mode 100644
index 0000000..eccee69b
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
@@ -0,0 +1,168 @@
+{
+// This file specifies fields in ComputedStyle that we would like to
+// generate, but are not CSS properties.
+
+  parameters: {
+    // - field_size
+    // Number of bits needed to store this field. Only used for storage_only
+    // fields. If specified, the field will be stored as bit field. Otherwise
+    // it will be stored as a normal data member.
+    field_size: {
+      valid_type: "int",
+    },
+
+    // If the field has_custom_compare_and_copy, then it does not appear in
+    // ComputedStyle::operator== and ComputedStyle::CopyNonInheritedFromCached.
+    has_custom_compare_and_copy: {
+      default: false,
+    },
+
+    // The rest is the same as CSSProperties.json5, but the only relevant ones in
+    // this file are:
+    // name, field_template, field_type_path, default_value, type_name, keyword,
+    // inherited
+  },
+
+  data: [
+    {
+      name: "IsLink",
+      field_template: "monotonic_flag",
+      default_value: "false",
+      has_custom_compare_and_copy: true,
+    },
+    {
+      name: "OriginalDisplay",
+      field_template: "keyword",
+      default_value: "inline",
+      type_name: "EDisplay",
+      keywords: [
+          "inline", "block", "list-item", "inline-block", "table", "inline-table", "table-row-group", "table-header-group",
+          "table-footer-group", "table-row", "table-column-group", "table-column", "table-cell", "table-caption", "-webkit-box",
+          "-webkit-inline-box", "flex", "inline-flex", "grid", "inline-grid", "contents", "flow-root", "none",
+      ],
+      has_custom_compare_and_copy: true,
+    },
+    {
+      name: "InsideLink",
+      field_template: "keyword",
+      default_value: "not-inside-link",
+      keywords: ["not-inside-link", "inside-unvisited-link", "inside-visited-link"],
+      inherited: true,
+      has_custom_compare_and_copy: true,
+    },
+    // Style can not be shared.
+    {
+      name: "Unique",
+      field_template: "monotonic_flag",
+      default_value: "false",
+      has_custom_compare_and_copy: true,
+    },
+    // Whether this style is affected by these pseudo-classes.
+    {
+      name: "AffectedByFocus",
+      field_template: "monotonic_flag",
+      default_value: "false",
+      has_custom_compare_and_copy: true,
+    },
+    {
+      name: "AffectedByFocusWithin",
+      field_template: "monotonic_flag",
+      default_value: "false",
+      has_custom_compare_and_copy: true,
+    },
+    {
+      name: "AffectedByHover",
+      field_template: "monotonic_flag",
+      default_value: "false",
+      has_custom_compare_and_copy: true,
+    },
+    {
+      name: "AffectedByActive",
+      field_template: "monotonic_flag",
+      default_value: "false",
+      has_custom_compare_and_copy: true,
+    },
+    {
+      name: "AffectedByDrag",
+      field_template: "monotonic_flag",
+      default_value: "false",
+      has_custom_compare_and_copy: true,
+    },
+    // A non-inherited property references a variable or @apply is used
+    {
+      name: "HasVariableReferenceFromNonInheritedProperty",
+      field_template: "monotonic_flag",
+      default_value: "false",
+      has_custom_compare_and_copy: true,
+    },
+    // Explicitly inherits a non-inherited property
+    {
+      name: "HasExplicitlyInheritedProperties",
+      field_template: "monotonic_flag",
+      default_value: "false",
+      has_custom_compare_and_copy: true,
+    },
+    // These are set if we used viewport or rem units when resolving a length.
+    // TODO(shend): HasViewportUnits should be a monotonic_flag.
+    {
+      name: "HasViewportUnits",
+      field_template: "primitive",
+      default_value: "false",
+      type_name: "bool",
+      has_custom_compare_and_copy: true,
+    },
+    {
+      name: "HasRemUnits",
+      field_template: "monotonic_flag",
+      default_value: "false",
+      has_custom_compare_and_copy: true,
+    },
+    // These properties only have generated storage, and their methods are handwritten in ComputedStyle.
+    // TODO(shend): Remove these fields and delete the 'storage_only' template.
+    {
+      name: "EmptyState",
+      field_template: "storage_only",
+      field_size: 1,
+      default_value: "false",
+      type_name: "bool",
+      has_custom_compare_and_copy: true,
+    },
+    {
+      name: "StyleType",
+      field_template: "storage_only",
+      field_size: 6,
+      default_value: "0",
+      type_name: "PseudoId",
+      has_custom_compare_and_copy: true,
+    },
+    {
+      name: "PseudoBits",
+      field_template: "storage_only",
+      field_size: 8,
+      default_value: "kPseudoIdNone",
+      type_name: "PseudoId",
+      has_custom_compare_and_copy: true,
+    },
+    // True if 'underline solid' is the only text decoration on this element.
+    {
+      name: "HasSimpleUnderline",
+      field_template: "storage_only",
+      field_size: 1,
+      default_value: "false",
+      type_name: "bool",
+      inherited: true,
+      has_custom_compare_and_copy: true,
+    },
+    // TODO(shend): vertical align is actually a CSS property, but since we don't support union fields
+    // which can be either a keyword or Length, this is generated as a nonproperty for now. Remove this
+    // once we can support union fields and groups.
+    {
+      name: "VerticalAlign",
+      field_template: "storage_only",
+      field_size: 4,
+      default_value: "EVerticalAlign::kBaseline",
+      type_name: "EVerticalAlign",
+      has_custom_compare_and_copy: true,
+    },
+  ],
+}
diff --git a/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp b/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp
index c66e3fb..eb950da 100644
--- a/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp
+++ b/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp
@@ -265,7 +265,7 @@
       if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled() &&
           next_state == kInCompositingUpdate)
         return true;
-      if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() &&
+      if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled() &&
           next_state == kInPrePaint)
         return true;
       break;
@@ -281,7 +281,7 @@
       if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled() &&
           next_state == kInCompositingUpdate)
         return true;
-      if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() &&
+      if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled() &&
           next_state == kInPrePaint)
         return true;
       break;
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp
index 89546cd..ab4370b6 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -409,7 +409,7 @@
           "removal and may be removed no earlier than %s. If you depend on it, "
           "please see https://www.chromestatus.com/features/5654810086866944 "
           "for more details.",
-          milestoneString(M60));
+          milestoneString(M62));
 
     case UseCounter::kV8IDBFactory_WebkitGetDatabaseNames_Method:
       return willBeRemoved("indexedDB.webkitGetDatabaseNames()", M60,
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h
index 7c67bcc..683424a8 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -1853,7 +1853,7 @@
   }
   void SetSubtreeNeedsPaintPropertyUpdate() {
     bitfields_.SetSubtreeNeedsPaintPropertyUpdate(true);
-    bitfields_.SetNeedsPaintPropertyUpdate(true);
+    SetNeedsPaintPropertyUpdate();
   }
   bool SubtreeNeedsPaintPropertyUpdate() const {
     return bitfields_.SubtreeNeedsPaintPropertyUpdate();
diff --git a/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp b/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp
index e1beee3..b099b184 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp
@@ -198,10 +198,11 @@
   EXPECT_TRUE(object->BackgroundChangedSinceLastPaintInvalidation());
   object->SetNeedsPaintPropertyUpdate();
   EXPECT_TRUE(object->NeedsPaintPropertyUpdate());
+  EXPECT_TRUE(object->Parent()->DescendantNeedsPaintPropertyUpdate());
   object->bitfields_.SetDescendantNeedsPaintPropertyUpdate(true);
   EXPECT_TRUE(object->DescendantNeedsPaintPropertyUpdate());
 
-  ScopedSlimmingPaintV2ForTest enable_s_pv2(true);
+  ScopedSlimmingPaintInvalidationForTest enable_sp_invalidation(true);
   GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInPrePaint);
   object->GetMutableForPainting().ClearPaintFlags();
 
@@ -215,6 +216,21 @@
   EXPECT_FALSE(object->DescendantNeedsPaintPropertyUpdate());
 }
 
+TEST_F(LayoutObjectTest, SubtreeNeedsPaintPropertyUpdate) {
+  LayoutObject* object = GetDocument().body()->GetLayoutObject();
+  object->SetSubtreeNeedsPaintPropertyUpdate();
+  EXPECT_TRUE(object->SubtreeNeedsPaintPropertyUpdate());
+  EXPECT_TRUE(object->NeedsPaintPropertyUpdate());
+  EXPECT_TRUE(object->Parent()->DescendantNeedsPaintPropertyUpdate());
+
+  ScopedSlimmingPaintInvalidationForTest enable_sp_invalidation(true);
+  GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInPrePaint);
+  object->GetMutableForPainting().ClearPaintFlags();
+
+  EXPECT_FALSE(object->SubtreeNeedsPaintPropertyUpdate());
+  EXPECT_FALSE(object->NeedsPaintPropertyUpdate());
+}
+
 TEST_F(LayoutObjectTest, NeedsPaintOffsetAndVisualRectUpdate) {
   LayoutObject* object = GetDocument().body()->GetLayoutObject();
   LayoutObject* parent = object->Parent();
diff --git a/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.cpp b/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.cpp
index 1858f56..0ec5372 100644
--- a/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.cpp
+++ b/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.cpp
@@ -8,9 +8,13 @@
 #include "bindings/core/v8/ScriptPromise.h"
 #include "bindings/core/v8/ScriptPromiseResolver.h"
 #include "bindings/core/v8/ScriptState.h"
+#include "core/dom/DOMException.h"
 #include "modules/media_capabilities/MediaCapabilitiesInfo.h"
+#include "modules/media_capabilities/MediaConfiguration.h"
 #include "modules/media_capabilities/MediaDecodingConfiguration.h"
+#include "modules/media_capabilities/MediaEncodingConfiguration.h"
 #include "public/platform/Platform.h"
+#include "public/platform/WebMediaRecorderHandler.h"
 #include "public/platform/modules/media_capabilities/WebMediaCapabilitiesClient.h"
 #include "public/platform/modules/media_capabilities/WebMediaCapabilitiesInfo.h"
 #include "public/platform/modules/media_capabilities/WebMediaConfiguration.h"
@@ -65,12 +69,9 @@
 }
 
 WebMediaConfiguration ToWebMediaConfiguration(
-    const MediaDecodingConfiguration& configuration) {
+    const MediaConfiguration& configuration) {
   WebMediaConfiguration web_configuration;
 
-  // |type| is mandatory.
-  DCHECK(configuration.hasType());
-
   if (configuration.hasAudio()) {
     web_configuration.audio_configuration =
         ToWebAudioConfiguration(configuration.audio());
@@ -94,6 +95,9 @@
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
   ScriptPromise promise = resolver->Promise();
 
+  // |type| is mandatory.
+  DCHECK(configuration.hasType());
+
   Platform::Current()->MediaCapabilitiesClient()->DecodingInfo(
       ToWebMediaConfiguration(configuration),
       WTF::MakeUnique<CallbackPromiseAdapter<MediaCapabilitiesInfo, void>>(
@@ -102,6 +106,36 @@
   return promise;
 }
 
+ScriptPromise MediaCapabilities::encodingInfo(
+    ScriptState* script_state,
+    const MediaEncodingConfiguration& configuration) {
+  ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
+  ScriptPromise promise = resolver->Promise();
+
+  if (!configuration.hasVideo() && !configuration.hasAudio()) {
+    resolver->Reject(DOMException::Create(
+        kSyntaxError,
+        "The configuration dictionary has neither |video| nor |audio| "
+        "specified and needs at least one of them."));
+    return promise;
+  }
+
+  WebMediaRecorderHandler* handler =
+      Platform::Current()->CreateMediaRecorderHandler();
+  if (!handler) {
+    resolver->Reject(DOMException::Create(
+        kInvalidStateError,
+        "Platform error: could not create MediaRecorderHandler."));
+    return promise;
+  }
+
+  handler->EncodingInfo(
+      ToWebMediaConfiguration(configuration),
+      WTF::MakeUnique<CallbackPromiseAdapter<MediaCapabilitiesInfo, void>>(
+          resolver));
+  return promise;
+}
+
 DEFINE_TRACE(MediaCapabilities) {}
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.h b/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.h
index 35d0781..d482adb 100644
--- a/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.h
+++ b/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.h
@@ -11,6 +11,7 @@
 namespace blink {
 
 class MediaDecodingConfiguration;
+class MediaEncodingConfiguration;
 class ScriptPromise;
 class ScriptState;
 
@@ -23,6 +24,7 @@
   MediaCapabilities();
 
   ScriptPromise decodingInfo(ScriptState*, const MediaDecodingConfiguration&);
+  ScriptPromise encodingInfo(ScriptState*, const MediaEncodingConfiguration&);
 
   DECLARE_VIRTUAL_TRACE();
 };
diff --git a/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.idl b/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.idl
index 75e767e4..21def833 100644
--- a/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.idl
+++ b/third_party/WebKit/Source/modules/media_capabilities/MediaCapabilities.idl
@@ -9,6 +9,6 @@
     RuntimeEnabled=MediaCapabilities
 ] interface MediaCapabilities {
     [CallWith=ScriptState] Promise<MediaCapabilitiesInfo> decodingInfo(MediaDecodingConfiguration configuration);
-
-    // TODO(mcasas): Implement encodingInfo(), https://crbug.com/709181
+    [CallWith=ScriptState] Promise<MediaCapabilitiesInfo> encodingInfo(
+        MediaEncodingConfiguration configuration);
 };
diff --git a/third_party/WebKit/Source/modules/media_capabilities/MediaEncodingConfiguration.idl b/third_party/WebKit/Source/modules/media_capabilities/MediaEncodingConfiguration.idl
new file mode 100644
index 0000000..d433c362
--- /dev/null
+++ b/third_party/WebKit/Source/modules/media_capabilities/MediaEncodingConfiguration.idl
@@ -0,0 +1,14 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/media-capabilities/#dictdef-mediaencodingconfiguration
+
+enum MediaEncodingType {
+    "record",
+    // TODO(mcasas): Implement other types https://crbug.com/709181
+};
+
+dictionary MediaEncodingConfiguration : MediaConfiguration{
+  required MediaEncodingType type;
+};
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni
index c68f3ec..7a09ee1 100644
--- a/third_party/WebKit/Source/modules/modules_idl_files.gni
+++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -448,6 +448,7 @@
                     "media_capabilities/AudioConfiguration.idl",
                     "media_capabilities/MediaConfiguration.idl",
                     "media_capabilities/MediaDecodingConfiguration.idl",
+                    "media_capabilities/MediaEncodingConfiguration.idl",
                     "media_capabilities/VideoConfiguration.idl",
                     "mediarecorder/BlobEventInit.idl",
                     "mediarecorder/MediaRecorderOptions.idl",
@@ -798,6 +799,8 @@
   "$blink_modules_output_dir/media_capabilities/MediaConfiguration.h",
   "$blink_modules_output_dir/media_capabilities/MediaDecodingConfiguration.cpp",
   "$blink_modules_output_dir/media_capabilities/MediaDecodingConfiguration.h",
+  "$blink_modules_output_dir/media_capabilities/MediaEncodingConfiguration.cpp",
+  "$blink_modules_output_dir/media_capabilities/MediaEncodingConfiguration.h",
   "$blink_modules_output_dir/media_capabilities/VideoConfiguration.cpp",
   "$blink_modules_output_dir/media_capabilities/VideoConfiguration.h",
   "$blink_modules_output_dir/mediarecorder/BlobEventInit.cpp",
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/host_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/host_mock.py
index 52e82e0..97dd87e25 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/host_mock.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/host_mock.py
@@ -80,7 +80,7 @@
     def _add_base_manifest_to_mock_filesystem(self, filesystem):
         webkit_finder = WebKitFinder(filesystem)
 
-        external_dir = webkit_finder.path_from_webkit_base('LayoutTests', 'external')
+        external_dir = webkit_finder.path_from_layout_tests('external')
         filesystem.maybe_make_directory(filesystem.join(external_dir, 'wpt'))
 
         manifest_base_path = filesystem.join(external_dir, 'WPT_BASE_MANIFEST.json')
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/webkit_finder.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/webkit_finder.py
index fa5a775..7b4a97c2 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/webkit_finder.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/webkit_finder.py
@@ -82,6 +82,9 @@
         self._chromium_base = None
         self._depot_tools = None
 
+    # TODO(tkent): Make this private. We should use functions for
+    # sub-directories in order to make the code robust against directory
+    # structure changes.
     def webkit_base(self):
         """Returns the absolute path to the top of the WebKit tree.
 
@@ -102,21 +105,33 @@
             self._chromium_base = self._filesystem.dirname(self._filesystem.dirname(self.webkit_base()))
         return self._chromium_base
 
+    # TODO(tkent): Make this private. We should use functions for
+    # sub-directories in order to make the code robust against directory
+    # structure changes.
     def path_from_webkit_base(self, *comps):
         return self._filesystem.join(self.webkit_base(), *comps)
 
     def path_from_chromium_base(self, *comps):
         return self._filesystem.join(self.chromium_base(), *comps)
 
+    def path_from_blink_source(self, *comps):
+        return self._filesystem.join(self._filesystem.join(self.webkit_base(), 'Source'), *comps)
+
     def path_to_script(self, script_name):
         """Returns the relative path to the script from the top of the WebKit tree."""
         # This is intentionally relative in order to force callers to consider what
         # their current working directory is (and change to the top of the tree if necessary).
         return self._filesystem.join('Tools', 'Scripts', script_name)
 
+    def path_from_tools_scripts(self, *comps):
+        return self._filesystem.join(self._filesystem.join(self.webkit_base(), 'Tools', 'Scripts'), *comps)
+
     def layout_tests_dir(self):
         return self.path_from_webkit_base('LayoutTests')
 
+    def path_from_layout_tests(self, *comps):
+        return self._filesystem.join(self.layout_tests_dir(), *comps)
+
     def perf_tests_dir(self):
         return self.path_from_webkit_base('PerformanceTests')
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/bisect_test_ordering.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/bisect_test_ordering.py
index 035ba59..7920da4 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/bisect_test_ordering.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/bisect_test_ordering.py
@@ -145,7 +145,7 @@
 
     def test_fails(self, tests):
         extra_args = ['--debug'] if self.is_debug else []
-        path_to_run_webkit_tests = self.webkit_finder.path_from_webkit_base('Tools', 'Scripts', 'run-webkit-tests')
+        path_to_run_webkit_tests = self.webkit_finder.path_from_tools_scripts('run-webkit-tests')
         output = self.executive.popen(
             [path_to_run_webkit_tests, '--child-processes', '1', '--order', 'none', '--no-retry',
              '--no-show-results', '--verbose'] + extra_args + tests, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
index 3f3aabf..cbcb91b2c 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
@@ -537,7 +537,7 @@
             _log.error("Upload failed: %s", err)
 
     def _copy_results_html_file(self, destination_path):
-        base_dir = self._port.path_from_webkit_base('LayoutTests', 'fast', 'harness')
+        base_dir = self._webkit_finder.path_from_layout_tests('fast', 'harness')
         results_file = self._filesystem.join(base_dir, 'results.html')
         # Note that the results.html template file won't exist when we're using a MockFileSystem during unit tests,
         # so make sure it exists before we try to copy it.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
index f679d17..62c523a 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
@@ -33,6 +33,7 @@
 import logging
 import re
 
+from webkitpy.common.webkit_finder import WebKitFinder
 from webkitpy.layout_tests.models.test_configuration import TestConfigurationConverter
 
 _log = logging.getLogger(__name__)
@@ -1095,8 +1096,10 @@
         return REBASELINE in self._model.get_expectations(test)
 
     def _shorten_filename(self, filename):
-        if filename.startswith(self._port.path_from_webkit_base()):
-            return self._port.host.filesystem.relpath(filename, self._port.path_from_webkit_base())
+        finder = WebKitFinder(self._port.host.filesystem)
+        # TODO(tkent): Can we use path_from_layout_tests() instead?
+        if filename.startswith(finder.path_from_webkit_base()):
+            return self._port.host.filesystem.relpath(filename, finder.path_from_webkit_base())
         return filename
 
     def _report_warnings(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
index dbcd2ea84..821ac4f3 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -178,7 +178,7 @@
         self._dump_reader = None
 
         # FIXME: prettypatch.py knows this path; it should not be copied here.
-        self._pretty_patch_path = self.path_from_webkit_base('Tools', 'Scripts', 'webkitruby', 'PrettyPatch', 'prettify.rb')
+        self._pretty_patch_path = self._webkit_finder.path_from_tools_scripts('webkitruby', 'PrettyPatch', 'prettify.rb')
         self._pretty_patch_available = None
 
         if not hasattr(options, 'configuration') or not options.configuration:
@@ -869,13 +869,10 @@
         self._filesystem.write_binary_file(baseline_path, data)
 
     # TODO(qyearsley): Update callers to create a finder and call it instead
-    # of these next five routines (which should be protected).
+    # of these next three routines (which should be protected).
     def webkit_base(self):
         return self._webkit_finder.webkit_base()
 
-    def path_from_webkit_base(self, *comps):
-        return self._webkit_finder.path_from_webkit_base(*comps)
-
     def path_from_chromium_base(self, *comps):
         return self._webkit_finder.path_from_chromium_base(*comps)
 
@@ -1029,7 +1026,7 @@
         return self._build_path('resources', 'inspector')
 
     def apache_config_directory(self):
-        return self.path_from_webkit_base('Tools', 'Scripts', 'apache_config')
+        return self._webkit_finder.path_from_tools_scripts('apache_config')
 
     def default_results_directory(self):
         """Returns the absolute path to the default place to store the test results."""
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/pywebsocket.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/pywebsocket.py
index 063792b..69e1fe0 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/pywebsocket.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/pywebsocket.py
@@ -32,6 +32,7 @@
 import sys
 import time
 
+from webkitpy.common.webkit_finder import WebKitFinder
 from webkitpy.layout_tests.servers import server_base
 
 
@@ -55,7 +56,7 @@
         time_str = time.strftime('%d%b%Y-%H%M%S')
         log_file_name = _WS_LOG_PREFIX + time_str
         self._error_log = self._filesystem.join(self._output_dir, log_file_name + '-err.txt')
-        pywebsocket_base = self._port_obj.path_from_webkit_base('Tools', 'Scripts', 'webkitpy', 'thirdparty')
+        pywebsocket_base = WebKitFinder(self._filesystem).path_from_tools_scripts('webkitpy', 'thirdparty')
         pywebsocket_script = self._filesystem.join(pywebsocket_base, 'mod_pywebsocket', 'standalone.py')
 
         self._start_cmd = [
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/wptserve.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/wptserve.py
index c0efd2a0..e77cca1 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/wptserve.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/wptserve.py
@@ -7,6 +7,7 @@
 import datetime
 import logging
 
+from webkitpy.common.webkit_finder import WebKitFinder
 from webkitpy.layout_tests.servers import server_base
 
 
@@ -32,8 +33,9 @@
         fs = self._filesystem
         self._pid_file = fs.join(self._runtime_path, '%s.pid' % self._name)
 
-        path_to_thirdparty = self._port_obj.path_from_webkit_base('Tools', 'Scripts', 'webkitpy', 'thirdparty')
-        path_to_wpt_support = self._port_obj.path_from_webkit_base('Tools', 'Scripts', 'webkitpy', 'thirdparty', 'wpt')
+        finder = WebKitFinder(fs)
+        path_to_thirdparty = finder.path_from_tools_scripts('webkitpy', 'thirdparty')
+        path_to_wpt_support = finder.path_from_tools_scripts('webkitpy', 'thirdparty', 'wpt')
         path_to_wpt_root = fs.join(path_to_wpt_support, 'wpt')
         path_to_wpt_config = fs.join(path_to_wpt_support, 'wpt.config.json')
         path_to_wpt_tests = fs.abspath(fs.join(self._port_obj.layout_tests_dir(), 'external', 'wpt'))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python.py
index 365d4278..475be32 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python.py
@@ -76,10 +76,10 @@
         executive = Executive()
         env = os.environ.copy()
         env['PYTHONPATH'] = os.pathsep.join([
-            wkf.path_from_webkit_base('Tools', 'Scripts'),
-            wkf.path_from_webkit_base('Source', 'build', 'scripts'),
-            wkf.path_from_webkit_base('Tools', 'Scripts', 'webkitpy', 'thirdparty'),
-            wkf.path_from_webkit_base('Source', 'bindings', 'scripts'),
+            wkf.path_from_tools_scripts(),
+            wkf.path_from_blink_source('build', 'scripts'),
+            wkf.path_from_tools_scripts('webkitpy', 'thirdparty'),
+            wkf.path_from_blink_source('bindings', 'scripts'),
             wkf.path_from_chromium_base('build', 'android'),
             wkf.path_from_chromium_base('third_party', 'catapult', 'devil'),
             wkf.path_from_chromium_base('third_party', 'pymock'),
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/servers/layout_tests_server.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/servers/layout_tests_server.py
index 7e9e6fe8..77007531 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/servers/layout_tests_server.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/servers/layout_tests_server.py
@@ -55,7 +55,7 @@
             test_list += each + ' '
         filesystem = FileSystem()
         webkit_finder = WebKitFinder(filesystem)
-        script_dir = webkit_finder.path_from_webkit_base('Tools', 'Scripts')
+        script_dir = webkit_finder.path_from_tools_scripts()
         executable_path = script_dir + '/run-webkit-tests'
         cmd = 'python ' + executable_path + ' --no-show-results '
         cmd += test_list
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_finder.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_finder.py
index 9b56ada..5320390 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_finder.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_finder.py
@@ -9,7 +9,7 @@
 @memoized
 def absolute_chromium_wpt_dir(host):
     finder = WebKitFinder(host.filesystem)
-    return finder.path_from_webkit_base('LayoutTests', 'external', 'wpt')
+    return finder.path_from_layout_tests('external', 'wpt')
 
 
 @memoized
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py
index d701aac..3da67383 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/directory_owners_extractor.py
@@ -18,7 +18,7 @@
 
     def read_owner_map(self):
         """Reads the W3CImportExpectations file and returns a map of directories to owners."""
-        input_path = self.finder.path_from_webkit_base('LayoutTests', 'W3CImportExpectations')
+        input_path = self.finder.path_from_layout_tests('W3CImportExpectations')
         input_contents = self.filesystem.read_text_file(input_path)
         self.owner_map = self.lines_to_owner_map(input_contents.splitlines())
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier.py
index 6b865bf5..5fedc8a 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_copier.py
@@ -61,7 +61,7 @@
         self.filesystem = self.host.filesystem
         self.webkit_finder = WebKitFinder(self.filesystem)
         self._webkit_root = self.webkit_finder.webkit_base()
-        self.layout_tests_dir = self.webkit_finder.path_from_webkit_base('LayoutTests')
+        self.layout_tests_dir = self.webkit_finder.layout_tests_dir()
         self.destination_directory = self.filesystem.normpath(
             self.filesystem.join(
                 self.layout_tests_dir,
@@ -142,7 +142,7 @@
     def find_paths_to_skip(self):
         paths_to_skip = set()
         port = self.host.port_factory.get()
-        w3c_import_expectations_path = self.webkit_finder.path_from_webkit_base('LayoutTests', 'W3CImportExpectations')
+        w3c_import_expectations_path = self.webkit_finder.path_from_layout_tests('W3CImportExpectations')
         w3c_import_expectations = self.filesystem.read_text_file(w3c_import_expectations_path)
         parser = TestExpectationParser(port, all_tests=(), is_lint_mode=False)
         expectation_lines = parser.parse(w3c_import_expectations_path, w3c_import_expectations)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
index 26ce818..c64588e1 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
@@ -67,7 +67,7 @@
 
         # TODO(qyearsley): Simplify this to use LocalWPT.fetch when csswg-test
         # is merged into web-platform-tests (crbug.com/706118).
-        temp_repo_path = self.path_from_webkit_base(dest_dir_name)
+        temp_repo_path = self.finder.path_from_webkit_base(dest_dir_name)
         _log.info('Cloning repo: %s', repo_url)
         _log.info('Local path: %s', temp_repo_path)
         self.run(['git', 'clone', repo_url, temp_repo_path])
@@ -139,7 +139,7 @@
             _log.warning('Checkout has local commits; aborting. Use --allow-local-commits to allow this.')
             return False
 
-        if self.fs.exists(self.path_from_webkit_base(WPT_DEST_NAME)):
+        if self.fs.exists(self.finder.path_from_webkit_base(WPT_DEST_NAME)):
             _log.warning('WebKit/%s exists; aborting.', WPT_DEST_NAME)
             return False
 
@@ -178,8 +178,8 @@
             ('testharness.js', 'resources'),
         ]
         for filename, wpt_subdir in resources_to_copy_from_wpt:
-            source = self.path_from_webkit_base('LayoutTests', 'external', WPT_DEST_NAME, wpt_subdir, filename)
-            destination = self.path_from_webkit_base('LayoutTests', 'resources', filename)
+            source = self.finder.path_from_layout_tests('external', WPT_DEST_NAME, wpt_subdir, filename)
+            destination = self.finder.path_from_layout_tests('resources', filename)
             self.copyfile(source, destination)
             self.run(['git', 'add', destination])
 
@@ -222,7 +222,7 @@
         _, show_ref_output = self.run(['git', 'show-ref', 'origin/master'], cwd=temp_repo_path)
         master_commitish = show_ref_output.split()[0]
 
-        dest_path = self.path_from_webkit_base('LayoutTests', 'external', dest_dir_name)
+        dest_path = self.finder.path_from_layout_tests('external', dest_dir_name)
         self._clear_out_dest_path(dest_path)
 
         _log.info('Importing the tests.')
@@ -312,18 +312,15 @@
         self.fs.copyfile(source, destination)
 
     def remove(self, *comps):
-        dest = self.path_from_webkit_base(*comps)
+        dest = self.finder.path_from_webkit_base(*comps)
         _log.debug('rm %s', dest)
         self.fs.remove(dest)
 
     def rmtree(self, *comps):
-        dest = self.path_from_webkit_base(*comps)
+        dest = self.finder.path_from_webkit_base(*comps)
         _log.debug('rm -fr %s', dest)
         self.fs.rmtree(dest)
 
-    def path_from_webkit_base(self, *comps):
-        return self.finder.path_from_webkit_base(*comps)
-
     def do_auto_update(self):
         """Attempts to upload a CL, make any required adjustments, and commit.
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py
index ff48742d..ec6009c 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py
@@ -91,8 +91,8 @@
     def ensure_manifest(host):
         """Checks whether the manifest exists, and then generates it if necessary."""
         finder = WebKitFinder(host.filesystem)
-        manifest_path = finder.path_from_webkit_base('LayoutTests', 'external', 'wpt', 'MANIFEST.json')
-        base_manifest_path = finder.path_from_webkit_base('LayoutTests', 'external', 'WPT_BASE_MANIFEST.json')
+        manifest_path = finder.path_from_layout_tests('external', 'wpt', 'MANIFEST.json')
+        base_manifest_path = finder.path_from_layout_tests('external', 'WPT_BASE_MANIFEST.json')
 
         if not host.filesystem.exists(base_manifest_path):
             _log.error('Manifest base not found at "%s".', base_manifest_path)
@@ -102,7 +102,7 @@
             _log.debug('Manifest not found, copying from base "%s".', base_manifest_path)
             host.filesystem.copyfile(base_manifest_path, manifest_path)
 
-        wpt_path = manifest_path = finder.path_from_webkit_base('LayoutTests', 'external', 'wpt')
+        wpt_path = manifest_path = finder.path_from_layout_tests('external', 'wpt')
         WPTManifest.generate_manifest(host, wpt_path)
 
     @staticmethod
@@ -110,7 +110,7 @@
         """Generates MANIFEST.json on the specified directory."""
         executive = host.executive
         finder = WebKitFinder(host.filesystem)
-        manifest_exec_path = finder.path_from_webkit_base('Tools', 'Scripts', 'webkitpy', 'thirdparty', 'wpt', 'wpt', 'manifest')
+        manifest_exec_path = finder.path_from_tools_scripts('webkitpy', 'thirdparty', 'wpt', 'wpt', 'manifest')
 
         cmd = ['python', manifest_exec_path, '--work', '--tests-root', dest_path]
         _log.debug('Running command: %s', ' '.join(cmd))
diff --git a/third_party/WebKit/public/platform/WebMediaRecorderHandler.h b/third_party/WebKit/public/platform/WebMediaRecorderHandler.h
index fe9c90c..ddc064a1 100644
--- a/third_party/WebKit/public/platform/WebMediaRecorderHandler.h
+++ b/third_party/WebKit/public/platform/WebMediaRecorderHandler.h
@@ -5,11 +5,16 @@
 #ifndef WebMediaRecorderHandler_h
 #define WebMediaRecorderHandler_h
 
+#include <memory>
+
 #include "WebCommon.h"
 
+#include "public/platform/modules/media_capabilities/WebMediaCapabilitiesInfo.h"
+
 namespace blink {
 
 class WebMediaRecorderHandlerClient;
+struct WebMediaConfiguration;
 class WebMediaStream;
 class WebString;
 
@@ -41,6 +46,12 @@
                                   const WebString& codecs) {
     return false;
   }
+
+  // Implements WICG Media Capabilities encodingInfo() call for local encoding.
+  // https://wicg.github.io/media-capabilities/#media-capabilities-interface
+  virtual void EncodingInfo(
+      const WebMediaConfiguration&,
+      std::unique_ptr<blink::WebMediaCapabilitiesQueryCallbacks>) {}
 };
 
 }  // namespace blink
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 1d5b079..956a7f6 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -37462,6 +37462,24 @@
   </summary>
 </histogram>
 
+<histogram name="Net.ResourceDispatcherHost.OutstandingRequests.PerProcess"
+    units="requests">
+  <owner>xunjieli@chromium.org</owner>
+  <summary>
+    The largest number of outstanding requests that are handled by the resource
+    dispatcher host for a single process.
+  </summary>
+</histogram>
+
+<histogram name="Net.ResourceDispatcherHost.OutstandingRequests.Total"
+    units="requests">
+  <owner>xunjieli@chromium.org</owner>
+  <summary>
+    The largest number of outstanding requests that are handled by the resource
+    dispatcher host across all processes.
+  </summary>
+</histogram>
+
 <histogram name="Net.ResourceLoader.ExpectedContentSizeResult"
     enum="ResourceLoaderExpectedContentSizeResult">
   <owner>maksim.sisov@intel.com</owner>
diff --git a/tools/perf/benchmarks/media.py b/tools/perf/benchmarks/media.py
index 5c0c2b5..f37ce44 100644
--- a/tools/perf/benchmarks/media.py
+++ b/tools/perf/benchmarks/media.py
@@ -114,7 +114,7 @@
   test = media.Media
   tag = 'android'
   page_set = page_sets.ToughVideoCasesPageSet
-  options = {'story_tag_filter_exclude': 'is_4k,is_50fps,theora'}
+  options = {'story_tag_filter_exclude': 'is_4k,is_50fps'}
 
   @classmethod
   def ShouldDisable(cls, possible_browser):
@@ -136,7 +136,7 @@
   Will eventually replace MediaAndroidToughVideoCases class."""
 
   tag = 'android'
-  options = {'story_tag_filter_exclude': 'is_4k,is_50fps,theora'}
+  options = {'story_tag_filter_exclude': 'is_4k,is_50fps'}
 
   @classmethod
   def ShouldDisable(cls, possible_browser):
diff --git a/tools/perf/page_sets/tough_video_cases.py b/tools/perf/page_sets/tough_video_cases.py
index 6ff629b15..bc7bb6f7 100644
--- a/tools/perf/page_sets/tough_video_cases.py
+++ b/tools/perf/page_sets/tough_video_cases.py
@@ -12,7 +12,6 @@
     'vorbis',
     'opus',
     # Video codecs:
-    'theora',
     'h264',
     'vp8',
     'vp9',
@@ -56,20 +55,6 @@
                             label='seek_cold')
 
 
-class Page1(ToughVideoCasesPage):
-
-  def __init__(self, page_set):
-    super(Page1, self).__init__(
-      url='file://tough_video_cases/video.html?src=crowd.wav&type=audio',
-      page_set=page_set,
-      tags=['pcm', 'audio_only'])
-
-    self.add_browser_metrics = True
-
-  def RunPageInteractions(self, action_runner):
-    self.PlayAction(action_runner)
-
-
 class Page2(ToughVideoCasesPage):
 
   def __init__(self, page_set):
@@ -84,23 +69,6 @@
     self.PlayAction(action_runner)
 
 
-class Page3(ToughVideoCasesPage):
-
-  # Note that ffprobe reports about this file:
-  # "[ogg @ 0x31a3ba0] Broken file, keyframe not correctly marked."
-  # This media file should probably be removed or replaced.
-  def __init__(self, page_set):
-    super(Page3, self).__init__(
-      url='file://tough_video_cases/video.html?src=crowd1080.ogv',
-      page_set=page_set,
-      tags=['is_50fps', 'theora', 'vorbis', 'audio_video'])
-
-    self.add_browser_metrics = True
-
-  def RunPageInteractions(self, action_runner):
-    self.PlayAction(action_runner)
-
-
 class Page4(ToughVideoCasesPage):
 
   def __init__(self, page_set):
@@ -115,34 +83,6 @@
     self.PlayAction(action_runner)
 
 
-class Page5(ToughVideoCasesPage):
-
-  def __init__(self, page_set):
-    super(Page5, self).__init__(
-      url='file://tough_video_cases/video.html?src=crowd2160.ogv',
-      page_set=page_set,
-      tags=['is_4k', 'is_50fps', 'theora', 'vorbis', 'audio_video'])
-
-    self.add_browser_metrics = True
-
-  def RunPageInteractions(self, action_runner):
-    self.PlayAction(action_runner)
-
-
-class Page6(ToughVideoCasesPage):
-
-  def __init__(self, page_set):
-    super(Page6, self).__init__(
-      url='file://tough_video_cases/video.html?src=crowd2160.webm',
-      page_set=page_set,
-      tags=['is_4k', 'is_50fps', 'vp8', 'vorbis', 'audio_video'])
-
-    self.add_browser_metrics = True
-
-  def RunPageInteractions(self, action_runner):
-    self.PlayAction(action_runner)
-
-
 class Page7(ToughVideoCasesPage):
 
   def __init__(self, page_set):
@@ -171,34 +111,6 @@
     self.PlayAction(action_runner)
 
 
-class Page9(ToughVideoCasesPage):
-
-  def __init__(self, page_set):
-    super(Page9, self).__init__(
-      url='file://tough_video_cases/video.html?src=tulip2.ogv',
-      page_set=page_set,
-      tags=['theora', 'vorbis', 'audio_video'])
-
-    self.add_browser_metrics = True
-
-  def RunPageInteractions(self, action_runner):
-    self.PlayAction(action_runner)
-
-
-class Page10(ToughVideoCasesPage):
-
-  def __init__(self, page_set):
-    super(Page10, self).__init__(
-      url='file://tough_video_cases/video.html?src=tulip2.webm',
-      page_set=page_set,
-      tags=['vp8', 'vorbis', 'audio_video'])
-
-    self.add_browser_metrics = True
-
-  def RunPageInteractions(self, action_runner):
-    self.PlayAction(action_runner)
-
-
 class Page11(ToughVideoCasesPage):
 
   def __init__(self, page_set):
@@ -297,20 +209,6 @@
     self.PlayAction(action_runner)
 
 
-class Page18(ToughVideoCasesPage):
-
-  def __init__(self, page_set):
-    super(Page18, self).__init__(
-      url='file://tough_video_cases/video.html?src=garden2_10s.ogv',
-      page_set=page_set,
-      tags=['is_4k', 'theora', 'vorbis', 'audio_video'])
-
-    self.add_browser_metrics = True
-
-  def RunPageInteractions(self, action_runner):
-    self.PlayAction(action_runner)
-
-
 class Page19(ToughVideoCasesPage):
 
   def __init__(self, page_set):
@@ -339,37 +237,6 @@
     self.SeekBeforeAndAfterPlayhead(action_runner)
 
 
-class Page21(ToughVideoCasesPage):
-
-  # Note that ffprobe reports about this file:
-  # "[ogg @ 0x39adba0] Broken file, keyframe not correctly marked."
-  # This media file should probably be removed or replaced.
-  def __init__(self, page_set):
-    super(Page21, self).__init__(
-      url='file://tough_video_cases/video.html?src=tulip2.ogv',
-      page_set=page_set,
-      tags=['theora', 'vorbis', 'audio_video'])
-
-    self.skip_basic_metrics = True
-
-  def RunPageInteractions(self, action_runner):
-    self.SeekBeforeAndAfterPlayhead(action_runner)
-
-
-class Page22(ToughVideoCasesPage):
-
-  def __init__(self, page_set):
-    super(Page22, self).__init__(
-      url='file://tough_video_cases/video.html?src=tulip2.webm',
-      page_set=page_set,
-      tags=['vp8', 'vorbis', 'audio_video'])
-
-    self.skip_basic_metrics = True
-
-  def RunPageInteractions(self, action_runner):
-    self.SeekBeforeAndAfterPlayhead(action_runner)
-
-
 class Page23(ToughVideoCasesPage):
 
   def __init__(self, page_set):
@@ -426,20 +293,6 @@
     self.SeekBeforeAndAfterPlayhead(action_runner)
 
 
-class Page27(ToughVideoCasesPage):
-
-  def __init__(self, page_set):
-    super(Page27, self).__init__(
-      url='file://tough_video_cases/video.html?src=garden2_10s.ogv',
-      page_set=page_set,
-      tags=['is_4k', 'theora', 'vorbis', 'audio_video'])
-
-    self.skip_basic_metrics = True
-
-  def RunPageInteractions(self, action_runner):
-    self.SeekBeforeAndAfterPlayhead(action_runner)
-
-
 class Page30(ToughVideoCasesPage):
 
   def __init__(self, page_set):
@@ -574,22 +427,6 @@
   def RunPageInteractions(self, action_runner):
     self.PlayAction(action_runner)
 
-class Page40(ToughVideoCasesPage):
-
-  # Note that ffprobe reports about this file:
-  # "[ogg @ 0x31a3ba0] Broken file, keyframe not correctly marked."
-  # This media file should probably be removed or replaced.
-  def __init__(self, page_set):
-    super(Page40, self).__init__(
-      url='file://tough_video_cases/video.html?src=crowd1080.ogv&canvas=true',
-      page_set=page_set,
-      tags=['is_50fps', 'theora', 'vorbis', 'audio_video'])
-
-    self.add_browser_metrics = True
-
-  def RunPageInteractions(self, action_runner):
-    self.PlayAction(action_runner)
-
 class ToughVideoCasesPageSet(story.StorySet):
   """
   Description: Video Stack Perf pages that report time_to_play and many other
@@ -603,16 +440,10 @@
     # This may be a non-issue because we plan to merge these two page sets back
     # together and use tags to allow teams to filter which pages they want.
 
-    self.AddStory(Page1(self))
     self.AddStory(Page2(self))
-    self.AddStory(Page3(self))
     self.AddStory(Page4(self))
-    self.AddStory(Page5(self))
-    self.AddStory(Page6(self))
     self.AddStory(Page7(self))
     self.AddStory(Page8(self))
-    self.AddStory(Page9(self))
-    self.AddStory(Page10(self))
     self.AddStory(Page11(self))
     self.AddStory(Page12(self))
     self.AddStory(Page13(self))
@@ -620,7 +451,6 @@
     self.AddStory(Page15(self))
     self.AddStory(Page16(self))
     self.AddStory(Page17(self))
-    self.AddStory(Page18(self))
     self.AddStory(Page30(self))
     self.AddStory(Page32(self))
     self.AddStory(Page34(self))
@@ -628,7 +458,6 @@
     self.AddStory(Page37(self))
     self.AddStory(Page38(self))
     self.AddStory(Page39(self))
-    self.AddStory(Page40(self))
 
 
 class ToughVideoCasesExtraPageSet(story.StorySet):
@@ -641,13 +470,10 @@
 
     self.AddStory(Page19(self))
     self.AddStory(Page20(self))
-    self.AddStory(Page21(self))
-    self.AddStory(Page22(self))
     self.AddStory(Page23(self))
     self.AddStory(Page24(self))
     self.AddStory(Page25(self))
     self.AddStory(Page26(self))
-    self.AddStory(Page27(self))
     self.AddStory(Page31(self))
     self.AddStory(Page33(self))
     self.AddStory(Page35(self))
diff --git a/tools/perf/page_sets/tough_video_cases/bear.webm.sha1 b/tools/perf/page_sets/tough_video_cases/bear.webm.sha1
deleted file mode 100644
index 211df9c..0000000
--- a/tools/perf/page_sets/tough_video_cases/bear.webm.sha1
+++ /dev/null
@@ -1 +0,0 @@
-4415d9927e32855eb21c371827d0427c354f2588
\ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/crowd.wav.sha1 b/tools/perf/page_sets/tough_video_cases/crowd.wav.sha1
deleted file mode 100644
index 065dc001..0000000
--- a/tools/perf/page_sets/tough_video_cases/crowd.wav.sha1
+++ /dev/null
@@ -1 +0,0 @@
-17d48d36b74701799999a0d3dc25a67038c75caa
\ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/crowd1080.ogv.sha1 b/tools/perf/page_sets/tough_video_cases/crowd1080.ogv.sha1
deleted file mode 100644
index 75f8866..0000000
--- a/tools/perf/page_sets/tough_video_cases/crowd1080.ogv.sha1
+++ /dev/null
@@ -1 +0,0 @@
-c3da321e4f90e9aa61d1237058af65131f027854
\ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/crowd2160.mp4.sha1 b/tools/perf/page_sets/tough_video_cases/crowd2160.mp4.sha1
deleted file mode 100644
index f079662c..0000000
--- a/tools/perf/page_sets/tough_video_cases/crowd2160.mp4.sha1
+++ /dev/null
@@ -1 +0,0 @@
-c9651176398fa86932adac7fe534eb018f7862ce
\ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/crowd2160.webm.sha1 b/tools/perf/page_sets/tough_video_cases/crowd2160.webm.sha1
deleted file mode 100644
index 0cb63a3..0000000
--- a/tools/perf/page_sets/tough_video_cases/crowd2160.webm.sha1
+++ /dev/null
@@ -1 +0,0 @@
-c1e3675623f4d2cd72e56dcaad432e0e8cc26d9c
\ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/crowd360.ogv.sha1 b/tools/perf/page_sets/tough_video_cases/crowd360.ogv.sha1
deleted file mode 100644
index ff29292..0000000
--- a/tools/perf/page_sets/tough_video_cases/crowd360.ogv.sha1
+++ /dev/null
@@ -1 +0,0 @@
-59ea02c91615499cfa15026de0c3c56821105d44
\ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/crowd480.webm.sha1 b/tools/perf/page_sets/tough_video_cases/crowd480.webm.sha1
deleted file mode 100644
index c2724f3..0000000
--- a/tools/perf/page_sets/tough_video_cases/crowd480.webm.sha1
+++ /dev/null
@@ -1 +0,0 @@
-470f851bcde812871187afbdf79db1625c8c48fc
\ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/crowd720.webm.sha1 b/tools/perf/page_sets/tough_video_cases/crowd720.webm.sha1
deleted file mode 100644
index 6bc8d0d5..0000000
--- a/tools/perf/page_sets/tough_video_cases/crowd720.webm.sha1
+++ /dev/null
@@ -1 +0,0 @@
-7ff870ce89dee7718455ba2eb8e1b0d835fc0d56
\ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/garden2_10s.ogv.sha1 b/tools/perf/page_sets/tough_video_cases/garden2_10s.ogv.sha1
deleted file mode 100644
index beadbd9..0000000
--- a/tools/perf/page_sets/tough_video_cases/garden2_10s.ogv.sha1
+++ /dev/null
@@ -1 +0,0 @@
-ba612b13ab5b8c555beac5c30d825bbfb58fdb11
\ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/tulip2.ogv.sha1 b/tools/perf/page_sets/tough_video_cases/tulip2.ogv.sha1
deleted file mode 100644
index e33446c..0000000
--- a/tools/perf/page_sets/tough_video_cases/tulip2.ogv.sha1
+++ /dev/null
@@ -1 +0,0 @@
-e6e14183467faad4f5800b02ca8c9deb5d59191f
\ No newline at end of file
diff --git a/tools/perf/page_sets/tough_video_cases/tulip2.webm.sha1 b/tools/perf/page_sets/tough_video_cases/tulip2.webm.sha1
deleted file mode 100644
index cd93dcf..0000000
--- a/tools/perf/page_sets/tough_video_cases/tulip2.webm.sha1
+++ /dev/null
@@ -1 +0,0 @@
-091425493334b1505aa0fe5b1d0f36fd1d8ac8bb
\ No newline at end of file
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index dea73f5..e0686043 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -138,6 +138,7 @@
     "cocoa/tool_tip_base_view.h",
     "cocoa/tool_tip_base_view.mm",
     "cocoa/touch_bar_forward_declarations.h",
+    "cocoa/touch_bar_forward_declarations.mm",
     "cocoa/tracking_area.h",
     "cocoa/tracking_area.mm",
     "cocoa/underlay_opengl_hosting_window.h",
diff --git a/ui/base/cocoa/touch_bar_forward_declarations.h b/ui/base/cocoa/touch_bar_forward_declarations.h
index 0e33268..ce03c6aa 100644
--- a/ui/base/cocoa/touch_bar_forward_declarations.h
+++ b/ui/base/cocoa/touch_bar_forward_declarations.h
@@ -6,9 +6,11 @@
 #define UI_BASE_COCOA_TOUCH_BAR_FORWARD_DECLARATIONS_H_
 
 // Once Chrome no longer supports OSX 10.12.0, this file can be deleted.
-
+#import <AppKit/AppKit.h>
 #import <Foundation/Foundation.h>
 
+#include "ui/base/ui_base_export.h"
+
 #if !defined(MAC_OS_X_VERSION_10_12_1)
 
 #pragma clang assume_nonnull begin
@@ -24,12 +26,6 @@
 typedef NSString* NSTouchBarItemIdentifier;
 typedef NSString* NSTouchBarCustomizationIdentifier;
 
-static const NSTouchBarItemIdentifier NSTouchBarItemIdentifierFixedSpaceSmall =
-    @"NSTouchBarItemIdentifierFixedSpaceSmall";
-
-static const NSTouchBarItemIdentifier NSTouchBarItemIdentifierFlexibleSpace =
-    @"NSTouchBarItemIdentifierFlexibleSpace";
-
 @interface NSTouchBar : NSObject<NSCoding>
 
 - (instancetype)init NS_DESIGNATED_INITIALIZER;
@@ -97,8 +93,6 @@
                makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier;
 @end
 
-#pragma clang assume_nonnull end
-
 #elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12_1
 
 // When compiling against the 10.12.1 SDK or later, just provide forward
@@ -116,4 +110,14 @@
 
 #endif  // MAC_OS_X_VERSION_10_12_1
 
+extern "C" {
+#if !defined(MAC_OS_X_VERSION_10_12_1) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12_1
+UI_BASE_EXPORT extern NSString* const NSTouchBarItemIdentifierFixedSpaceSmall;
+UI_BASE_EXPORT extern NSString* const NSTouchBarItemIdentifierFlexibleSpace;
+#endif  // MAC_OS_X_VERSION_10_12_1
+}  // extern "C"
+
+#pragma clang assume_nonnull end
+
 #endif  // UI_BASE_COCOA_TOUCH_BAR_FORWARD_DECLARATIONS_H_
diff --git a/ui/base/cocoa/touch_bar_forward_declarations.mm b/ui/base/cocoa/touch_bar_forward_declarations.mm
new file mode 100644
index 0000000..1df5a9b
--- /dev/null
+++ b/ui/base/cocoa/touch_bar_forward_declarations.mm
@@ -0,0 +1,13 @@
+// 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 "ui/base/cocoa/touch_bar_forward_declarations.h"
+
+#if !defined(MAC_OS_X_VERSION_10_12_1) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12_1
+NSString* const NSTouchBarItemIdentifierFixedSpaceSmall =
+    @"NSTouchBarItemIdentifierFixedSpaceSmall";
+NSString* const NSTouchBarItemIdentifierFlexibleSpace =
+    @"NSTouchBarItemIdentifierFlexibleSpace";
+#endif  // MAC_OS_X_VERSION_10_12_1