diff --git a/DEPS b/DEPS
index b48a753c..ecf8e66 100644
--- a/DEPS
+++ b/DEPS
@@ -59,7 +59,7 @@
   # 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': '206bda5b79311da9a6ea0ee112302bf8115c41c5',
+  'skia_revision': 'd29e0da3523e390eeb77b5a823d7ff86569ac1d3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -83,7 +83,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': 'a85e5ca5f2dfadcf9f3812a8ef039d1f206833a4',
+  'pdfium_revision': '1bc5e494b675aeb5e73cae1d0d3cfad341a05a60',
   # 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.
@@ -127,7 +127,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
-  'libprotobuf-mutator': '52af4b0f6f55f9d8836acb605e902db49eb8e6b4',
+  'libprotobuf-mutator': '3fc43a01d721ef1bacfefed170bc22abf1b8b051',
 }
 
 # Only these hosts are allowed for dependencies in this DEPS file.
@@ -440,7 +440,7 @@
   },
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '401e6d48bfd3cbf74a41da724d05c989e207662b',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '3ba9a2c8b2341430b001ed531f1eedf7c9b0384f',
 
   'src/third_party/libwebm/source':
     Var('chromium_git') + '/webm/libwebm.git' + '@' + '4956b2dec65352af32dc71bab553acb631c64177',
@@ -605,7 +605,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '34842fa3c36988840c89f5bc6a68503175acf7d9',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'c4a14324e29cd1210cfa5d0c061e7a1f10dacf00', # commit position 20528
+    Var('webrtc_git') + '/src.git' + '@' + '6063e98dcb5044eb010bc69cc307b26925dd033b', # commit position 20528
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index 9e9c4217..a18d9234 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -504,7 +504,6 @@
             'android_clang_dbg_recipe',
             'android_compile_dbg',
             'android_compile_mips_dbg',
-            'android_compile_rel',
             'android_compile_x64_dbg',
             'android_compile_x86_dbg',
             'android_coverage',
diff --git a/WATCHLISTS b/WATCHLISTS
index ff51440..32b755b 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -980,7 +980,8 @@
       'filepath': 'ipc/ipc',
     },
     'libvpx': {
-      'filepath': 'third_party/libvpx'
+      'filepath': 'third_party/libaom/|'\
+                  'third_party/libvpx/',
     },
     'libwebp': {
       'filepath': 'third_party/libwebp'
diff --git a/ash/mus/window_manager.cc b/ash/mus/window_manager.cc
index 2eabaa1..e72b1a8 100644
--- a/ash/mus/window_manager.cc
+++ b/ash/mus/window_manager.cc
@@ -29,6 +29,7 @@
 #include "ash/public/cpp/window_state_type.h"
 #include "ash/public/interfaces/window_actions.mojom.h"
 #include "ash/public/interfaces/window_pin_type.mojom.h"
+#include "ash/public/interfaces/window_properties.mojom.h"
 #include "ash/public/interfaces/window_state_type.mojom.h"
 #include "ash/root_window_controller.h"
 #include "ash/root_window_settings.h"
@@ -106,6 +107,10 @@
   property_converter_->RegisterPrimitiveProperty(
       kWindowPinTypeKey, ash::mojom::kWindowPinType_Property,
       base::Bind(&ash::IsValidWindowPinType));
+  property_converter_->RegisterPrimitiveProperty(
+      kWindowPositionManagedTypeKey,
+      ash::mojom::kWindowPositionManaged_Property,
+      aura::PropertyConverter::CreateAcceptAnyValueCallback());
   property_converter_->RegisterStringProperty(
       kShelfIDKey, ui::mojom::WindowManager::kShelfID_Property);
 }
diff --git a/ash/public/cpp/window_properties.cc b/ash/public/cpp/window_properties.cc
index de6a0d9..f780615 100644
--- a/ash/public/cpp/window_properties.cc
+++ b/ash/public/cpp/window_properties.cc
@@ -19,11 +19,12 @@
 DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kShelfIDKey, nullptr);
 DEFINE_UI_CLASS_PROPERTY_KEY(int32_t, kShelfItemTypeKey, TYPE_UNDEFINED);
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kShowInOverviewKey, true);
-DEFINE_UI_CLASS_PROPERTY_KEY(mojom::WindowStateType,
-                             kWindowStateTypeKey,
-                             mojom::WindowStateType::DEFAULT);
 DEFINE_UI_CLASS_PROPERTY_KEY(mojom::WindowPinType,
                              kWindowPinTypeKey,
                              mojom::WindowPinType::NONE);
+DEFINE_UI_CLASS_PROPERTY_KEY(bool, kWindowPositionManagedTypeKey, false);
+DEFINE_UI_CLASS_PROPERTY_KEY(mojom::WindowStateType,
+                             kWindowStateTypeKey,
+                             mojom::WindowStateType::DEFAULT);
 
 }  // namespace ash
diff --git a/ash/public/cpp/window_properties.h b/ash/public/cpp/window_properties.h
index 89eb4f5..8e4ea5f 100644
--- a/ash/public/cpp/window_properties.h
+++ b/ash/public/cpp/window_properties.h
@@ -44,10 +44,6 @@
 ASH_PUBLIC_EXPORT extern const aura::WindowProperty<bool>* const
     kShowInOverviewKey;
 
-// A property key to indicate ash's extended window state.
-ASH_PUBLIC_EXPORT extern const aura::WindowProperty<
-    mojom::WindowStateType>* const kWindowStateTypeKey;
-
 // A property key to store ash::WindowPinType for a window.
 // When setting this property to PINNED or TRUSTED_PINNED, the window manager
 // will try to fullscreen the window and pin it on the top of the screen. If the
@@ -56,6 +52,16 @@
 ASH_PUBLIC_EXPORT extern const aura::WindowProperty<mojom::WindowPinType>* const
     kWindowPinTypeKey;
 
+// A property key to indicate whether ash should perform auto management of
+// window positions; when you open a second browser, ash will move the two to
+// minimize overlap.
+ASH_PUBLIC_EXPORT extern const aura::WindowProperty<bool>* const
+    kWindowPositionManagedTypeKey;
+
+// A property key to indicate ash's extended window state.
+ASH_PUBLIC_EXPORT extern const aura::WindowProperty<
+    mojom::WindowStateType>* const kWindowStateTypeKey;
+
 // Alphabetical sort.
 
 }  // namespace ash
diff --git a/ash/public/interfaces/BUILD.gn b/ash/public/interfaces/BUILD.gn
index b1aaaa13..3aa2427 100644
--- a/ash/public/interfaces/BUILD.gn
+++ b/ash/public/interfaces/BUILD.gn
@@ -42,6 +42,7 @@
     "wallpaper.mojom",
     "window_actions.mojom",
     "window_pin_type.mojom",
+    "window_properties.mojom",
     "window_state_type.mojom",
     "window_style.mojom",
   ]
diff --git a/ash/public/interfaces/window_properties.mojom b/ash/public/interfaces/window_properties.mojom
new file mode 100644
index 0000000..8d2ee1fa
--- /dev/null
+++ b/ash/public/interfaces/window_properties.mojom
@@ -0,0 +1,11 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module ash.mojom;
+
+// This is put on windows to indicate that ash should perform auto management of
+// window positions; when you open a second browser, ash will move the two to
+// minimize overlap.
+const string kWindowPositionManaged_Property =
+  "ash:window-position-managed";
diff --git a/ash/shelf/voice_interaction_overlay.cc b/ash/shelf/voice_interaction_overlay.cc
index b5136d5..93f2f94 100644
--- a/ash/shelf/voice_interaction_overlay.cc
+++ b/ash/shelf/voice_interaction_overlay.cc
@@ -114,7 +114,8 @@
 
 }  // namespace
 
-class VoiceInteractionIcon : public ui::Layer {
+class VoiceInteractionIcon : public ui::Layer,
+                             public ui::CompositorAnimationObserver {
  public:
   VoiceInteractionIcon() : Layer(ui::LAYER_NOT_DRAWN) {
     set_name("VoiceInteractionOverlay:ICON_LAYER");
@@ -126,14 +127,32 @@
   }
 
   void StartAnimation() {
-    animation_timer_.Start(FROM_HERE,
-                           base::TimeDelta::FromMilliseconds(
-                               base::TimeTicks::kMillisecondsPerSecond /
-                               gfx::LinearAnimation::kDefaultFrameRate),
-                           this, &VoiceInteractionIcon::AnimationProgressed);
+    if (!GetCompositor()->HasAnimationObserver(this))
+      GetCompositor()->AddAnimationObserver(this);
   }
 
-  void StopAnimation() { animation_timer_.Stop(); }
+  void StopAnimation() {
+    if (GetCompositor()->HasAnimationObserver(this))
+      GetCompositor()->RemoveAnimationObserver(this);
+  }
+
+  // ui::CompositorAnimationObserver
+  void OnCompositingShuttingDown(ui::Compositor* compositor) override {}
+  void OnAnimationStep(base::TimeTicks timestamp) override {
+    uint64_t elapsed = (timestamp - base::TimeTicks()).InMilliseconds();
+    for (int i = 0; i < DOT_COUNT; ++i) {
+      float normalizedTime =
+          ((elapsed - kMoleculeAnimationOffset * kMoleculeOrder[i]) %
+           kMoleculeAnimationDurationMs) /
+          static_cast<float>(kMoleculeAnimationDurationMs);
+
+      gfx::Transform transform;
+      transform.Translate(0,
+                          kMoleculeAmplitude * sin(normalizedTime * 2 * M_PI));
+
+      dot_layers_[i]->SetTransform(transform);
+    }
+  }
 
  private:
   enum Dot {
@@ -162,25 +181,6 @@
     return "UNKNOWN";
   }
 
-  void AnimationProgressed() {
-    gfx::Transform transform;
-
-    uint64_t now =
-        (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds();
-    for (int i = 0; i < DOT_COUNT; ++i) {
-      float normalizedTime =
-          ((now - kMoleculeAnimationOffset * kMoleculeOrder[i]) %
-           kMoleculeAnimationDurationMs) /
-          static_cast<float>(kMoleculeAnimationDurationMs);
-
-      transform.MakeIdentity();
-      transform.Translate(0,
-                          kMoleculeAmplitude * sin(normalizedTime * 2 * M_PI));
-
-      dot_layers_[i]->SetTransform(transform);
-    }
-  }
-
   /**
    * Convenience method to place dots to Molecule shape used by Molecule
    * animations.
@@ -209,8 +209,6 @@
   std::unique_ptr<ui::Layer> dot_layers_[DOT_COUNT];
   std::unique_ptr<views::CircleLayerDelegate> dot_layer_delegates_[DOT_COUNT];
 
-  base::RepeatingTimer animation_timer_;
-
   DISALLOW_COPY_AND_ASSIGN(VoiceInteractionIcon);
 };
 
diff --git a/ash/shell/toplevel_window.cc b/ash/shell/toplevel_window.cc
index bb373e7..2a8970d 100644
--- a/ash/shell/toplevel_window.cc
+++ b/ash/shell/toplevel_window.cc
@@ -38,7 +38,7 @@
       new ToplevelWindow(params), Shell::GetPrimaryRootWindow());
   widget->GetNativeView()->SetName("Examples:ToplevelWindow");
   wm::WindowState* window_state = wm::GetWindowState(widget->GetNativeView());
-  window_state->set_window_position_managed(true);
+  window_state->SetWindowPositionManaged(true);
   widget->Show();
   return widget;
 }
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc
index 4c472e4b..adea79f3 100644
--- a/ash/system/palette/palette_tray.cc
+++ b/ash/system/palette/palette_tray.cc
@@ -183,10 +183,10 @@
 void PaletteTray::RegisterProfilePrefs(PrefRegistrySimple* registry) {
   registry->RegisterBooleanPref(
       prefs::kEnableStylusTools, true,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
   registry->RegisterBooleanPref(
       prefs::kLaunchPaletteOnEjectEvent, true,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
 }
 
 bool PaletteTray::ContainsPointInScreen(const gfx::Point& point) {
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index 8a9d929..aa70c0c 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -31,20 +31,14 @@
 
 namespace {
 
-// Five fixed position ratios of the divider.
-constexpr float kFixedPositionRatios[] = {0.0f, 0.33f, 0.5f, 0.67f, 1.0f};
+// Three fixed position ratios of the divider, which means the divider can
+// always be moved to these three positions.
+constexpr float kFixedPositionRatios[] = {0.f, 0.5f, 1.0f};
 
-float FindClosestFixedPositionRatio(float distance, float length) {
-  float current_ratio = distance / length;
-  float closest_ratio = 0.f;
-  for (float ratio : kFixedPositionRatios) {
-    if (std::abs(current_ratio - ratio) <
-        std::abs(current_ratio - closest_ratio)) {
-      closest_ratio = ratio;
-    }
-  }
-  return closest_ratio;
-}
+// Two optional position ratios of the divider. Whether the divider can be moved
+// to these two positions depends on the minimum size of the snapped windows.
+constexpr float kOneThirdPositionRatio = 0.33f;
+constexpr float kTwoThirdPositionRatio = 0.67f;
 
 gfx::Point GetBoundedPosition(const gfx::Point& location_in_screen,
                               const gfx::Rect& bounds_in_screen) {
@@ -608,41 +602,53 @@
 
 SplitViewController::SnapPosition SplitViewController::GetBlackScrimPosition(
     const gfx::Point& location_in_screen) {
-  SnapPosition position = SplitViewController::NONE;
   const gfx::Rect work_area_bounds =
       GetDisplayWorkAreaBoundsInScreen(GetDefaultSnappedWindow());
   if (!work_area_bounds.Contains(location_in_screen))
-    return position;
+    return NONE;
 
-  switch (screen_orientation_) {
-    case blink::kWebScreenOrientationLockLandscapePrimary:
-    case blink::kWebScreenOrientationLockLandscapeSecondary:
-      if (location_in_screen.x() <
-          work_area_bounds.x() +
-              work_area_bounds.width() * kFixedPositionRatios[1]) {
-        position = IsCurrentScreenOrientationPrimary() ? LEFT : RIGHT;
-      } else if (location_in_screen.x() >
-                 work_area_bounds.x() +
-                     work_area_bounds.width() * kFixedPositionRatios[3]) {
-        position = IsCurrentScreenOrientationPrimary() ? RIGHT : LEFT;
-      }
-      break;
-    case blink::kWebScreenOrientationLockPortraitPrimary:
-    case blink::kWebScreenOrientationLockPortraitSecondary:
-      if (location_in_screen.y() >
-          work_area_bounds.y() +
-              work_area_bounds.height() * kFixedPositionRatios[3]) {
-        position = IsCurrentScreenOrientationPrimary() ? LEFT : RIGHT;
-      } else if (location_in_screen.y() <
-                 work_area_bounds.y() +
-                     work_area_bounds.height() * kFixedPositionRatios[1]) {
-        position = IsCurrentScreenOrientationPrimary() ? RIGHT : LEFT;
-      }
-      break;
-    default:
-      break;
+  gfx::Size left_window_min_size, right_window_min_size;
+  if (left_window_ && left_window_->delegate())
+    left_window_min_size = left_window_->delegate()->GetMinimumSize();
+  if (right_window_ && right_window_->delegate())
+    right_window_min_size = right_window_->delegate()->GetMinimumSize();
+
+  bool is_primary = IsCurrentScreenOrientationPrimary();
+  int long_length = GetDividerEndPosition();
+  // The distance from the current resizing position to the left or right side
+  // of the screen. Note: left or right side here means the side of the
+  // |left_window_| or |right_window_|.
+  int left_window_distance = 0, right_window_distance = 0;
+  int min_left_length = 0, min_right_length = 0;
+
+  if (IsCurrentScreenOrientationLandscape()) {
+    int left_distance = location_in_screen.x() - work_area_bounds.x();
+    int right_distance = work_area_bounds.right() - location_in_screen.x();
+    left_window_distance = is_primary ? left_distance : right_distance;
+    right_window_distance = is_primary ? right_distance : left_distance;
+
+    min_left_length = left_window_min_size.width();
+    min_right_length = right_window_min_size.width();
+  } else {
+    int top_distance = location_in_screen.y() - work_area_bounds.y();
+    int bottom_distance = work_area_bounds.bottom() - location_in_screen.y();
+    left_window_distance = is_primary ? bottom_distance : top_distance;
+    right_window_distance = is_primary ? top_distance : bottom_distance;
+
+    min_left_length = left_window_min_size.height();
+    min_right_length = right_window_min_size.height();
   }
-  return position;
+
+  if (left_window_distance < long_length * kOneThirdPositionRatio ||
+      left_window_distance < min_left_length) {
+    return LEFT;
+  }
+  if (right_window_distance < long_length * kOneThirdPositionRatio ||
+      right_window_distance < min_right_length) {
+    return RIGHT;
+  }
+
+  return NONE;
 }
 
 void SplitViewController::UpdateDividerPosition(
@@ -699,11 +705,25 @@
   // extract the center from |divider_position_|. The result will also be the
   // center of the divider, so extract the origin, unless the result is on of
   // the endpoints.
-  float ratio = FindClosestFixedPositionRatio(
-      divider_position_ + std::floor(divider_thickness / 2.f),
-      GetDividerEndPosition());
-  divider_position_ = std::floor(GetDividerEndPosition() * ratio);
-  if (ratio > 0.f && ratio < 1.f)
+  float divider_distance =
+      divider_position_ + std::floor(divider_thickness / 2.f);
+
+  int work_area_long_length = GetDividerEndPosition();
+  float current_ratio = divider_distance / work_area_long_length;
+  float closest_ratio = 0.f;
+  std::vector<float> position_ratios(
+      kFixedPositionRatios,
+      kFixedPositionRatios + sizeof(kFixedPositionRatios) / sizeof(float));
+  GetDividerOptionalPositionRatios(position_ratios);
+  for (float ratio : position_ratios) {
+    if (std::abs(current_ratio - ratio) <
+        std::abs(current_ratio - closest_ratio)) {
+      closest_ratio = ratio;
+    }
+  }
+
+  divider_position_ = std::floor(work_area_long_length * closest_ratio);
+  if (closest_ratio > 0.f && closest_ratio < 1.f)
     divider_position_ -= std::floor(divider_thickness / 2.f);
 }
 
@@ -790,4 +810,34 @@
     TransposeRect(left_or_top_rect);
 }
 
+void SplitViewController::GetDividerOptionalPositionRatios(
+    std::vector<float>& position_ratios) {
+  bool is_left_or_top = IsLeftWindowOnTopOrLeftOfScreen(screen_orientation_);
+  aura::Window* left_or_top_window =
+      is_left_or_top ? left_window_ : right_window_;
+  aura::Window* right_or_bottom_window =
+      is_left_or_top ? right_window_ : left_window_;
+  bool is_landscape = IsCurrentScreenOrientationLandscape();
+
+  int long_length = GetDividerEndPosition();
+  float min_size_left_ratio = 0.f, min_size_right_ratio = 0.f;
+  int min_left_size = 0, min_right_size = 0;
+  if (left_or_top_window && left_or_top_window->delegate()) {
+    gfx::Size min_size = left_or_top_window->delegate()->GetMinimumSize();
+    min_left_size = is_landscape ? min_size.width() : min_size.height();
+  }
+  if (right_or_bottom_window && right_or_bottom_window->delegate()) {
+    gfx::Size min_size = right_or_bottom_window->delegate()->GetMinimumSize();
+    min_right_size = is_landscape ? min_size.width() : min_size.height();
+  }
+
+  min_size_left_ratio = static_cast<float>(min_left_size) / long_length;
+  min_size_right_ratio = static_cast<float>(min_right_size) / long_length;
+  if (min_size_left_ratio <= kOneThirdPositionRatio)
+    position_ratios.push_back(kOneThirdPositionRatio);
+
+  if (min_size_right_ratio <= kOneThirdPositionRatio)
+    position_ratios.push_back(kTwoThirdPositionRatio);
+}
+
 }  // namespace ash
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h
index 33e9218..1a0e7e7 100644
--- a/ash/wm/splitview/split_view_controller.h
+++ b/ash/wm/splitview/split_view_controller.h
@@ -215,6 +215,12 @@
   void AdjustLeftOrTopSnappedWindowBoundsDuringResizing(
       gfx::Rect* left_or_top_rect);
 
+  // Gets the divider optional position ratios. The divider can always be
+  // moved to the positions in |kFixedPositionRatios|. Whether the divider can
+  // be moved to |kOneThirdPositionRatio| or |kTwoThirdPositionRatio| depends
+  // on the minimum size of current snapped windows.
+  void GetDividerOptionalPositionRatios(std::vector<float>& positionRatios);
+
   // The current left/right snapped window.
   aura::Window* left_window_ = nullptr;
   aura::Window* right_window_ = nullptr;
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index 2aa4db7..ba11276 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -84,6 +84,12 @@
     return split_view_controller()->split_view_divider();
   }
 
+  blink::WebScreenOrientationLockType screen_orientation() {
+    return split_view_controller()->screen_orientation();
+  }
+
+  int divider_position() { return split_view_controller()->divider_position(); }
+
  private:
   class SplitViewTestWindowDelegate : public aura::test::TestWindowDelegate {
    public:
@@ -959,4 +965,87 @@
   EndSplitView();
 }
 
+// Tests that if a snapped window's minumum size is larger than one third but
+// smaller than half of the work area's longer side. The divider should be
+// snapped to a position that is larger than the window's minimum size.
+TEST_F(SplitViewControllerTest, DividerPositionWithWindowMinimumSizeTest) {
+  const gfx::Rect bounds(0, 0, 200, 200);
+  std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
+  aura::test::TestWindowDelegate* delegate1 =
+      static_cast<aura::test::TestWindowDelegate*>(window1->delegate());
+  ui::test::EventGenerator& generator(GetEventGenerator());
+  EXPECT_EQ(blink::kWebScreenOrientationLockLandscapePrimary,
+            screen_orientation());
+  gfx::Rect workarea_bounds =
+      split_view_controller()->GetDisplayWorkAreaBoundsInScreen(window1.get());
+
+  // Snap the divider to one third position when there is only left window with
+  // minimum size larger than one third of the display's width. The divider
+  // should be snapped to the middle position after dragging.
+  split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
+  delegate1->set_minimum_size(
+      gfx::Size(workarea_bounds.width() * 0.4f, workarea_bounds.height()));
+  gfx::Rect divider_bounds =
+      split_view_divider()->GetDividerBoundsInScreen(false);
+  generator.set_current_location(divider_bounds.CenterPoint());
+  generator.DragMouseTo(gfx::Point(workarea_bounds.width() * 0.33f, 0));
+  EXPECT_GT(divider_position(), 0.33f * workarea_bounds.width());
+  EXPECT_LE(divider_position(), 0.5f * workarea_bounds.width());
+
+  // Snap the divider to two third position, it should be kept at there after
+  // dragging.
+  generator.set_current_location(divider_bounds.CenterPoint());
+  generator.DragMouseTo(gfx::Point(workarea_bounds.width() * 0.67f, 0));
+  EXPECT_GT(divider_position(), 0.5f * workarea_bounds.width());
+  EXPECT_LE(divider_position(), 0.67f * workarea_bounds.width());
+  EndSplitView();
+
+  // Snap the divider to two third position when there is only right window with
+  // minium size larger than one third of the display's width. The divider
+  // should be snapped to the middle position after dragging.
+  delegate1->set_minimum_size(
+      gfx::Size(workarea_bounds.width() * 0.4f, workarea_bounds.height()));
+  split_view_controller()->SnapWindow(window1.get(),
+                                      SplitViewController::RIGHT);
+  divider_bounds = split_view_divider()->GetDividerBoundsInScreen(false);
+  generator.set_current_location(divider_bounds.CenterPoint());
+  generator.DragMouseTo(gfx::Point(workarea_bounds.width() * 0.67f, 0));
+  EXPECT_GT(divider_position(), 0.33f * workarea_bounds.width());
+  EXPECT_LE(divider_position(), 0.5f * workarea_bounds.width());
+
+  // Snap the divider to one third position, it should be kept at there after
+  // dragging.
+  generator.set_current_location(divider_bounds.CenterPoint());
+  generator.DragMouseTo(gfx::Point(workarea_bounds.width() * 0.33f, 0));
+  EXPECT_GT(divider_position(), 0);
+  EXPECT_LE(divider_position(), 0.33f * workarea_bounds.width());
+  EndSplitView();
+
+  // Snap the divider to one third position when there are both left and right
+  // snapped windows with the same minimum size larger than one third of the
+  // display's width. The divider should be snapped to the middle position after
+  // dragging.
+  std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
+  aura::test::TestWindowDelegate* delegate2 =
+      static_cast<aura::test::TestWindowDelegate*>(window2->delegate());
+  delegate2->set_minimum_size(
+      gfx::Size(workarea_bounds.width() * 0.4f, workarea_bounds.height()));
+  split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
+  split_view_controller()->SnapWindow(window2.get(),
+                                      SplitViewController::RIGHT);
+  divider_bounds = split_view_divider()->GetDividerBoundsInScreen(false);
+  generator.set_current_location(divider_bounds.CenterPoint());
+  generator.DragMouseTo(gfx::Point(workarea_bounds.width() * 0.33f, 0));
+  EXPECT_GT(divider_position(), 0.33f * workarea_bounds.width());
+  EXPECT_LE(divider_position(), 0.5f * workarea_bounds.width());
+
+  // Snap the divider to two third position, it should be snapped to the middle
+  // position after dragging.
+  generator.set_current_location(divider_bounds.CenterPoint());
+  generator.DragMouseTo(gfx::Point(workarea_bounds.width() * 0.67f, 0));
+  EXPECT_GT(divider_position(), 0.33f * workarea_bounds.width());
+  EXPECT_LE(divider_position(), 0.5f * workarea_bounds.width());
+  EndSplitView();
+}
+
 }  // namespace ash
diff --git a/ash/wm/toplevel_window_event_handler.cc b/ash/wm/toplevel_window_event_handler.cc
index adaa9f6..e498df2 100644
--- a/ash/wm/toplevel_window_event_handler.cc
+++ b/ash/wm/toplevel_window_event_handler.cc
@@ -89,8 +89,8 @@
   // Disable window position auto management while dragging and restore it
   // aftrewards.
   wm::WindowState* window_state = wm::GetWindowState(source);
-  const bool window_position_managed = window_state->window_position_managed();
-  window_state->set_window_position_managed(false);
+  const bool window_position_managed = window_state->GetWindowPositionManaged();
+  window_state->SetWindowPositionManaged(false);
   aura::WindowTracker tracker({source});
 
   run_loop.Run();
@@ -100,7 +100,7 @@
 
   // Make sure the window hasn't been deleted.
   if (tracker.Contains(source))
-    window_state->set_window_position_managed(window_position_managed);
+    window_state->SetWindowPositionManaged(window_position_managed);
 
   in_move_loop_ = false;
   return result == wm::WmToplevelWindowEventHandler::DragResult::SUCCESS
diff --git a/ash/wm/toplevel_window_event_handler_unittest.cc b/ash/wm/toplevel_window_event_handler_unittest.cc
index 32b2537..c82f0a9 100644
--- a/ash/wm/toplevel_window_event_handler_unittest.cc
+++ b/ash/wm/toplevel_window_event_handler_unittest.cc
@@ -112,7 +112,7 @@
                              wm::WindowState* window_state,
                              aura::Window* window) {
   ASSERT_TRUE(window->HasCapture());
-  ASSERT_FALSE(window_state->window_position_managed());
+  ASSERT_FALSE(window_state->GetWindowPositionManaged());
   generator->DragMouseBy(100, 100);
   generator->ReleaseLeftButton();
 }
@@ -129,7 +129,7 @@
 
   // Explicitly enable window position auto management, and expect it to be
   // restored after drag completes.
-  window_state->set_window_position_managed(true);
+  window_state->SetWindowPositionManaged(true);
   generator.PressLeftButton();
   ::wm::WindowMoveClient* move_client =
       ::wm::GetWindowMoveClient(w1->GetRootWindow());
@@ -141,7 +141,7 @@
             move_client->RunMoveLoop(w1.get(), gfx::Vector2d(100, 100),
                                      ::wm::WINDOW_MOVE_SOURCE_MOUSE));
   // Window position auto manage property should be restored to true.
-  EXPECT_TRUE(window_state->window_position_managed());
+  EXPECT_TRUE(window_state->GetWindowPositionManaged());
   // Position should have been offset by 100,100.
   EXPECT_EQ("100,100", w1->bounds().origin().ToString());
   // Size should remain the same.
@@ -149,7 +149,7 @@
 
   // Explicitly disable window position auto management, and expect it to be
   // restored after drag completes.
-  window_state->set_window_position_managed(false);
+  window_state->SetWindowPositionManaged(false);
   generator.PressLeftButton();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
@@ -159,7 +159,7 @@
             move_client->RunMoveLoop(w1.get(), gfx::Vector2d(100, 100),
                                      ::wm::WINDOW_MOVE_SOURCE_MOUSE));
   // Window position auto manage property should be restored to true.
-  EXPECT_FALSE(window_state->window_position_managed());
+  EXPECT_FALSE(window_state->GetWindowPositionManaged());
   // Position should have been offset by 100,100.
   EXPECT_EQ("200,200", w1->bounds().origin().ToString());
   // Size should remain the same.
diff --git a/ash/wm/window_positioner.cc b/ash/wm/window_positioner.cc
index 22160d2..0f89656 100644
--- a/ash/wm/window_positioner.cc
+++ b/ash/wm/window_positioner.cc
@@ -55,7 +55,8 @@
   if (disable_auto_positioning)
     return false;
   const wm::WindowState* window_state = wm::GetWindowState(window);
-  return !window_state->is_dragged() && window_state->window_position_managed();
+  return !window_state->is_dragged() &&
+         window_state->GetWindowPositionManaged();
 }
 
 // Check if a given |window| can be managed. This includes that its
@@ -66,7 +67,7 @@
   if (disable_auto_positioning)
     return false;
   const wm::WindowState* window_state = wm::GetWindowState(window);
-  return window_state->window_position_managed() &&
+  return window_state->GetWindowPositionManaged() &&
          !window_state->IsMinimized() && !window_state->IsMaximized() &&
          !window_state->IsFullscreen() && !window_state->IsPinned() &&
          !window_state->bounds_changed_by_user();
@@ -196,7 +197,7 @@
     if (window != exclude &&
         window->type() == aura::client::WINDOW_TYPE_NORMAL &&
         window->GetRootWindow() == root_window && window->TargetVisibility() &&
-        wm::GetWindowState(window)->window_position_managed()) {
+        wm::GetWindowState(window)->GetWindowPositionManaged()) {
       if (found && found != window) {
         // no need to check !single_window because the function must have
         // been already returned in the "if (!single_window)" below.
diff --git a/ash/wm/window_positioner_unittest.cc b/ash/wm/window_positioner_unittest.cc
index afb6fb61..cc80299 100644
--- a/ash/wm/window_positioner_unittest.cc
+++ b/ash/wm/window_positioner_unittest.cc
@@ -192,7 +192,7 @@
   views::Widget* widget1 = shell::ToplevelWindow::CreateToplevelWindow(params);
   wm::WindowState* managed_state =
       wm::GetWindowState(widget1->GetNativeWindow());
-  EXPECT_TRUE(managed_state->window_position_managed());
+  EXPECT_TRUE(managed_state->GetWindowPositionManaged());
   EXPECT_EQ("300x300", widget1->GetWindowBoundsInScreen().size().ToString());
   widget1->SetFullscreen(true);
   ASSERT_EQ("1400x800", widget1->GetWindowBoundsInScreen().size().ToString());
@@ -201,7 +201,7 @@
   params.use_saved_placement = false;
   views::Widget* widget2 = shell::ToplevelWindow::CreateToplevelWindow(params);
   wm::WindowState* state_2 = wm::GetWindowState(widget2->GetNativeWindow());
-  EXPECT_TRUE(state_2->window_position_managed());
+  EXPECT_TRUE(state_2->GetWindowPositionManaged());
   EXPECT_EQ("300x300", widget2->GetWindowBoundsInScreen().size().ToString());
 
   // Restores to the original size.
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index 654d5188..b0b147a 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -328,6 +328,14 @@
   observer_list_.RemoveObserver(observer);
 }
 
+bool WindowState::GetWindowPositionManaged() const {
+  return window_->GetProperty(kWindowPositionManagedTypeKey);
+}
+
+void WindowState::SetWindowPositionManaged(bool managed) {
+  window_->SetProperty(kWindowPositionManagedTypeKey, managed);
+}
+
 void WindowState::set_bounds_changed_by_user(bool bounds_changed_by_user) {
   bounds_changed_by_user_ = bounds_changed_by_user;
   if (bounds_changed_by_user)
@@ -353,7 +361,6 @@
 
 WindowState::WindowState(aura::Window* window)
     : window_(window),
-      window_position_managed_(false),
       bounds_changed_by_user_(false),
       ignored_by_shelf_(false),
       can_consume_system_keys_(false),
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h
index e14e995..6bf98b84 100644
--- a/ash/wm/window_state.h
+++ b/ash/wm/window_state.h
@@ -226,7 +226,7 @@
   // If the minimum visibility is true, ash will try to keep a
   // minimum amount of the window is always visible on the work area
   // when shown.
-  // TODO(oshima): Consolidate this and window_position_managed
+  // TODO(oshima): Consolidate this and GetWindowPositionManaged
   // into single parameter to control the window placement.
   bool minimum_visibility() const { return minimum_visibility_; }
   void set_minimum_visibility(bool minimum_visibility) {
@@ -256,10 +256,8 @@
 
   // Whether or not the window's position can be managed by the
   // auto management logic.
-  bool window_position_managed() const { return window_position_managed_; }
-  void set_window_position_managed(bool window_position_managed) {
-    window_position_managed_ = window_position_managed;
-  }
+  bool GetWindowPositionManaged() const;
+  void SetWindowPositionManaged(bool managed);
 
   // Whether or not the window's position or size was changed by a user.
   bool bounds_changed_by_user() const { return bounds_changed_by_user_; }
@@ -384,7 +382,6 @@
   aura::Window* window_;
   std::unique_ptr<WindowStateDelegate> delegate_;
 
-  bool window_position_managed_;
   bool bounds_changed_by_user_;
   bool ignored_by_shelf_;
   bool can_consume_system_keys_;
diff --git a/ash/wm/window_state_unittest.cc b/ash/wm/window_state_unittest.cc
index dd1096e..07cd311 100644
--- a/ash/wm/window_state_unittest.cc
+++ b/ash/wm/window_state_unittest.cc
@@ -253,7 +253,7 @@
 TEST_F(WindowStateTest, AutoManaged) {
   std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
   WindowState* window_state = GetWindowState(window.get());
-  window_state->set_window_position_managed(true);
+  window_state->SetWindowPositionManaged(true);
   window->Hide();
   window->SetBounds(gfx::Rect(100, 100, 100, 100));
   window->Show();
@@ -271,7 +271,7 @@
             window->GetBoundsInScreen().ToString());
 
   // The window should still be auto managed despite being right maximized.
-  EXPECT_TRUE(window_state->window_position_managed());
+  EXPECT_TRUE(window_state->GetWindowPositionManaged());
 }
 
 // Test that the replacement of a State object works as expected.
diff --git a/ash/wm/workspace_controller_unittest.cc b/ash/wm/workspace_controller_unittest.cc
index afd8cb4..67828d3 100644
--- a/ash/wm/workspace_controller_unittest.cc
+++ b/ash/wm/workspace_controller_unittest.cc
@@ -101,7 +101,7 @@
     aura::Window* window = CreateTestWindow();
     window->SetBounds(bounds);
     wm::WindowState* window_state = wm::GetWindowState(window);
-    window_state->set_window_position_managed(true);
+    window_state->SetWindowPositionManaged(true);
     window->Show();
     return window;
   }
@@ -764,7 +764,7 @@
   // Create an auto-positioned window.
   std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
   gfx::Rect desktop_area = window1->parent()->bounds();
-  wm::GetWindowState(window1.get())->set_window_position_managed(true);
+  wm::GetWindowState(window1.get())->SetWindowPositionManaged(true);
   // Hide and then show |window1| to trigger auto-positioning logic.
   window1->Hide();
   window1->SetBounds(gfx::Rect(16, 32, 300, 300));
@@ -791,7 +791,7 @@
   // Create and show a second window forcing the first window and its child to
   // move.
   std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
-  wm::GetWindowState(window2.get())->set_window_position_managed(true);
+  wm::GetWindowState(window2.get())->SetWindowPositionManaged(true);
   // Hide and then show |window2| to trigger auto-positioning logic.
   window2->Hide();
   window2->SetBounds(gfx::Rect(32, 48, 250, 250));
@@ -833,10 +833,10 @@
 
   wm::WindowState* window1_state = wm::GetWindowState(window1.get());
   // Test 2: Set up two managed windows and check their auto positioning.
-  window1_state->set_window_position_managed(true);
+  window1_state->SetWindowPositionManaged(true);
 
   std::unique_ptr<aura::Window> window3(CreateTestWindowInShellWithId(2));
-  wm::GetWindowState(window3.get())->set_window_position_managed(true);
+  wm::GetWindowState(window3.get())->SetWindowPositionManaged(true);
   // To avoid any auto window manager changes due to SetBounds, the window
   // gets first hidden and then shown again.
   window3->Hide();
@@ -897,8 +897,8 @@
   wm::WindowState* window1_state = wm::GetWindowState(window1.get());
   wm::WindowState* window2_state = wm::GetWindowState(window2.get());
 
-  window1_state->set_window_position_managed(true);
-  window2_state->set_window_position_managed(true);
+  window1_state->SetWindowPositionManaged(true);
+  window2_state->SetWindowPositionManaged(true);
   EXPECT_FALSE(window1_state->bounds_changed_by_user());
   EXPECT_FALSE(window2_state->bounds_changed_by_user());
 
@@ -943,9 +943,9 @@
   window1->Hide();
   window2->Hide();
   window3->Hide();
-  wm::GetWindowState(window1.get())->set_window_position_managed(true);
-  wm::GetWindowState(window2.get())->set_window_position_managed(true);
-  wm::GetWindowState(window3.get())->set_window_position_managed(true);
+  wm::GetWindowState(window1.get())->SetWindowPositionManaged(true);
+  wm::GetWindowState(window2.get())->SetWindowPositionManaged(true);
+  wm::GetWindowState(window3.get())->SetWindowPositionManaged(true);
 
   window1->Show();
   wm::ActivateWindow(window1.get());
@@ -996,8 +996,8 @@
   window2->SetBounds(gfx::Rect(32, 48, 256, 512));
   window1->Hide();
   window2->Hide();
-  wm::GetWindowState(window1.get())->set_window_position_managed(true);
-  wm::GetWindowState(window2.get())->set_window_position_managed(true);
+  wm::GetWindowState(window1.get())->SetWindowPositionManaged(true);
+  wm::GetWindowState(window2.get())->SetWindowPositionManaged(true);
   window1->Show();
   EXPECT_EQ(user_pos.ToString(), window1->bounds().ToString());
   window2->Show();
@@ -1027,7 +1027,7 @@
       CreateTestWindowInShellWithBounds(default_bounds));
   wm::WindowState* window1_state = wm::GetWindowState(window1.get());
   window1->Hide();
-  window1_state->set_window_position_managed(true);
+  window1_state->SetWindowPositionManaged(true);
   window1->Show();
   // First window is centered.
   EXPECT_EQ("150,0 100x100", window1->bounds().ToString());
@@ -1035,7 +1035,7 @@
       CreateTestWindowInShellWithBounds(default_bounds));
   wm::WindowState* window2_state = wm::GetWindowState(window2.get());
   window2->Hide();
-  window2_state->set_window_position_managed(true);
+  window2_state->SetWindowPositionManaged(true);
   window2->Show();
 
   // Auto positioning pushes windows to each sides.
@@ -1072,13 +1072,13 @@
 TEST_F(WorkspaceControllerTest, ToMinimizeRepositionsRemaining) {
   std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
   wm::WindowState* window1_state = wm::GetWindowState(window1.get());
-  window1_state->set_window_position_managed(true);
+  window1_state->SetWindowPositionManaged(true);
   window1->SetBounds(gfx::Rect(16, 32, 640, 320));
   gfx::Rect desktop_area = window1->parent()->bounds();
 
   std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
   wm::WindowState* window2_state = wm::GetWindowState(window2.get());
-  window2_state->set_window_position_managed(true);
+  window2_state->SetWindowPositionManaged(true);
   window2->SetBounds(gfx::Rect(32, 48, 256, 512));
 
   window1_state->Minimize();
@@ -1104,12 +1104,12 @@
 TEST_F(WorkspaceControllerTest, MaxToMinRepositionsRemaining) {
   std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
   wm::WindowState* window1_state = wm::GetWindowState(window1.get());
-  window1_state->set_window_position_managed(true);
+  window1_state->SetWindowPositionManaged(true);
   gfx::Rect desktop_area = window1->parent()->bounds();
 
   std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
   wm::WindowState* window2_state = wm::GetWindowState(window2.get());
-  window2_state->set_window_position_managed(true);
+  window2_state->SetWindowPositionManaged(true);
   window2->SetBounds(gfx::Rect(32, 48, 256, 512));
 
   window1_state->Maximize();
@@ -1129,12 +1129,12 @@
   std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
   window1->SetBounds(gfx::Rect(16, 32, 640, 320));
   wm::WindowState* window1_state = wm::GetWindowState(window1.get());
-  window1_state->set_window_position_managed(true);
+  window1_state->SetWindowPositionManaged(true);
   gfx::Rect desktop_area = window1->parent()->bounds();
 
   std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
   wm::WindowState* window2_state = wm::GetWindowState(window2.get());
-  window2_state->set_window_position_managed(true);
+  window2_state->SetWindowPositionManaged(true);
   window2->SetBounds(gfx::Rect(32, 40, 256, 512));
 
   // Trigger the auto window placement function by showing (and hiding) it.
@@ -1165,11 +1165,11 @@
   std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
   window1->SetBounds(gfx::Rect(16, 32, 640, 320));
   wm::WindowState* window1_state = wm::GetWindowState(window1.get());
-  window1_state->set_window_position_managed(true);
+  window1_state->SetWindowPositionManaged(true);
   gfx::Rect desktop_area = window1->parent()->bounds();
 
   std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
-  wm::GetWindowState(window2.get())->set_window_position_managed(true);
+  wm::GetWindowState(window2.get())->SetWindowPositionManaged(true);
   window2->SetBounds(gfx::Rect(32, 40, 256, 512));
 
   // Trigger the auto window placement function by showing (and hiding) it.
@@ -1206,8 +1206,8 @@
   window2->Hide();
   window2->SetBounds(gfx::Rect(32, 48, 256, 512));
 
-  wm::GetWindowState(window1.get())->set_window_position_managed(true);
-  wm::GetWindowState(window2.get())->set_window_position_managed(true);
+  wm::GetWindowState(window1.get())->SetWindowPositionManaged(true);
+  wm::GetWindowState(window2.get())->SetWindowPositionManaged(true);
   // Make sure nothing is animating.
   window1->layer()->GetAnimator()->StopAnimating();
   window2->layer()->GetAnimator()->StopAnimating();
@@ -1308,7 +1308,7 @@
   // Create an auto-positioned window.
   std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
   wm::WindowState* window_state = wm::GetWindowState(window.get());
-  window_state->set_window_position_managed(true);
+  window_state->SetWindowPositionManaged(true);
   window->SetBounds(gfx::Rect(10, 20, 100, 200));
   window->Show();
 
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 92a131a..164d39f 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -373,6 +373,8 @@
     "hash.cc",
     "hash.h",
     "ios/block_types.h",
+    "ios/callback_counter.h",
+    "ios/callback_counter.mm",
     "ios/crb_protocol_observers.h",
     "ios/crb_protocol_observers.mm",
     "ios/device_util.h",
@@ -2061,6 +2063,7 @@
     "i18n/string_search_unittest.cc",
     "i18n/time_formatting_unittest.cc",
     "i18n/timezone_unittest.cc",
+    "ios/callback_counter_unittest.mm",
     "ios/crb_protocol_observers_unittest.mm",
     "ios/device_util_unittest.mm",
     "ios/weak_nsobject_unittest.mm",
@@ -2767,6 +2770,17 @@
     java_files = [ "test/android/javatests/src/org/chromium/base/test/TestChildProcessConnection.java" ]
   }
 
+  java_library("base_junit_test_support") {
+    # Skip platform checks since Robolectric depends on requires_android targets.
+    bypass_platform_checks = true
+    testonly = true
+    java_files = [ "android/junit/src/org/chromium/base/metrics/test/ShadowRecordHistogram.java" ]
+    deps = [
+      ":base_java",
+      "//third_party/robolectric:robolectric_all_java",
+    ]
+  }
+
   junit_binary("base_junit_tests") {
     java_files = [
       "android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java",
diff --git a/base/android/junit/src/org/chromium/base/metrics/test/ShadowRecordHistogram.java b/base/android/junit/src/org/chromium/base/metrics/test/ShadowRecordHistogram.java
new file mode 100644
index 0000000..02745482
--- /dev/null
+++ b/base/android/junit/src/org/chromium/base/metrics/test/ShadowRecordHistogram.java
@@ -0,0 +1,46 @@
+// 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.
+
+package org.chromium.base.metrics.test;
+
+import android.util.Pair;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+import org.chromium.base.metrics.RecordHistogram;
+
+import java.util.HashMap;
+
+/**
+ * Implementation of RecordHistogram which does not rely on native and still enables testing of
+ * histogram counts.
+ */
+@Implements(RecordHistogram.class)
+public class ShadowRecordHistogram {
+    private static HashMap<Pair<String, Integer>, Integer> sSamples =
+            new HashMap<Pair<String, Integer>, Integer>();
+
+    @Resetter
+    public static void reset() {
+        sSamples.clear();
+    }
+
+    @Implementation
+    public static void recordCountHistogram(String name, int sample) {
+        Pair<String, Integer> key = Pair.create(name, sample);
+        Integer i = sSamples.get(key);
+        if (i == null) {
+            i = 0;
+        }
+        sSamples.put(key, i + 1);
+    }
+
+    @Implementation
+    public static int getHistogramValueCountForTesting(String name, int sample) {
+        Integer i = sSamples.get(Pair.create(name, sample));
+        return (i != null) ? i : 0;
+    }
+}
diff --git a/ios/chrome/browser/callback_counter.h b/base/ios/callback_counter.h
similarity index 100%
rename from ios/chrome/browser/callback_counter.h
rename to base/ios/callback_counter.h
diff --git a/ios/chrome/browser/callback_counter.mm b/base/ios/callback_counter.mm
similarity index 83%
rename from ios/chrome/browser/callback_counter.mm
rename to base/ios/callback_counter.mm
index 73b1aa26..530d0af 100644
--- a/ios/chrome/browser/callback_counter.mm
+++ b/base/ios/callback_counter.mm
@@ -2,11 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ios/chrome/browser/callback_counter.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
+#include "base/ios/callback_counter.h"
 
 CallbackCounter::CallbackCounter(const FinalCallback& final_callback)
     : callback_count_(0U), final_callback_(final_callback) {
diff --git a/ios/chrome/browser/callback_counter_unittest.mm b/base/ios/callback_counter_unittest.mm
similarity index 83%
rename from ios/chrome/browser/callback_counter_unittest.mm
rename to base/ios/callback_counter_unittest.mm
index a58911f..04ada661 100644
--- a/ios/chrome/browser/callback_counter_unittest.mm
+++ b/base/ios/callback_counter_unittest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ios/chrome/browser/callback_counter.h"
+#include "base/ios/callback_counter.h"
 
 #include "base/bind.h"
 #include "base/mac/bind_objc_block.h"
@@ -10,17 +10,13 @@
 #import "base/test/ios/wait_util.h"
 #include "testing/platform_test.h"
 
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
 using CallbackCounterTest = PlatformTest;
 
 // Tests that CallbackCounter works with 2 callbacks.
 TEST_F(CallbackCounterTest, Basic) {
   __block BOOL block_was_called = NO;
   scoped_refptr<CallbackCounter> callback_counter =
-      new CallbackCounter(base::BindBlockArc(^{
+      new CallbackCounter(base::BindBlock(^{
         block_was_called = YES;
       }));
 
diff --git a/base/task_scheduler/scheduler_worker_pool_impl.cc b/base/task_scheduler/scheduler_worker_pool_impl.cc
index a0e74de..5e510b1 100644
--- a/base/task_scheduler/scheduler_worker_pool_impl.cc
+++ b/base/task_scheduler/scheduler_worker_pool_impl.cc
@@ -24,6 +24,13 @@
 #include "base/threading/scoped_blocking_call.h"
 #include "base/threading/thread_restrictions.h"
 
+#if defined(OS_WIN)
+#include "base/win/scoped_com_initializer.h"
+#include "base/win/scoped_windows_thread_environment.h"
+#include "base/win/scoped_winrt_initializer.h"
+#include "base/win/windows_version.h"
+#endif  // defined(OS_WIN)
+
 namespace base {
 namespace internal {
 
@@ -138,6 +145,10 @@
   // returned a non-empty sequence and DidRunTask() hasn't been called yet).
   bool is_running_task_ = false;
 
+#if defined(OS_WIN)
+  std::unique_ptr<win::ScopedWindowsThreadEnvironment> win_thread_environment_;
+#endif  // defined(OS_WIN)
+
   DISALLOW_COPY_AND_ASSIGN(SchedulerWorkerDelegateImpl);
 };
 
@@ -182,7 +193,8 @@
 
 void SchedulerWorkerPoolImpl::Start(
     const SchedulerWorkerPoolParams& params,
-    scoped_refptr<TaskRunner> service_thread_task_runner) {
+    scoped_refptr<TaskRunner> service_thread_task_runner,
+    WorkerEnvironment worker_environment) {
   AutoSchedulerLock auto_lock(lock_);
 
   DCHECK(workers_.empty());
@@ -191,6 +203,7 @@
   initial_worker_capacity_ = worker_capacity_;
   suggested_reclaim_time_ = params.suggested_reclaim_time();
   backward_compatibility_ = params.backward_compatibility();
+  worker_environment_ = worker_environment;
 
   service_thread_task_runner_ = std::move(service_thread_task_runner);
 
@@ -338,6 +351,18 @@
 #endif
   }
 
+#if defined(OS_WIN)
+  if (outer_->worker_environment_ == WorkerEnvironment::COM_MTA) {
+    if (win::GetVersion() >= win::VERSION_WIN8) {
+      win_thread_environment_ = std::make_unique<win::ScopedWinrtInitializer>();
+    } else {
+      win_thread_environment_ = std::make_unique<win::ScopedCOMInitializer>(
+          win::ScopedCOMInitializer::kMTA);
+    }
+    DCHECK(win_thread_environment_->Succeeded());
+  }
+#endif  // defined(OS_WIN)
+
   DCHECK_EQ(num_tasks_since_last_wait_, 0U);
 
   PlatformThread::SetName(
@@ -498,6 +523,10 @@
     DCHECK(!ContainsWorker(outer_->workers_, worker));
   }
 #endif
+
+#if defined(OS_WIN)
+  win_thread_environment_.reset();
+#endif  // defined(OS_WIN)
 }
 
 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::
diff --git a/base/task_scheduler/scheduler_worker_pool_impl.h b/base/task_scheduler/scheduler_worker_pool_impl.h
index a469bce..617c114 100644
--- a/base/task_scheduler/scheduler_worker_pool_impl.h
+++ b/base/task_scheduler/scheduler_worker_pool_impl.h
@@ -27,6 +27,7 @@
 #include "base/task_scheduler/sequence.h"
 #include "base/task_scheduler/task.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 
 namespace base {
 
@@ -46,6 +47,15 @@
 // This class is thread-safe.
 class BASE_EXPORT SchedulerWorkerPoolImpl : public SchedulerWorkerPool {
  public:
+  enum class WorkerEnvironment {
+    // No special worker environment required.
+    NONE,
+#if defined(OS_WIN)
+    // Initialize a COM MTA on the worker.
+    COM_MTA,
+#endif  // defined(OS_WIN)
+  };
+
   // Constructs a pool without workers.
   //
   // |name| is used to label the pool's threads ("TaskScheduler" + |name| +
@@ -62,9 +72,11 @@
 
   // Creates workers following the |params| specification, allowing existing and
   // future tasks to run. Uses |service_thread_task_runner| to monitor for
-  // blocked threads in the pool. Can only be called once. CHECKs on failure.
+  // blocked threads in the pool. |thread_environment| Can only be called once.
+  // CHECKs on failure.
   void Start(const SchedulerWorkerPoolParams& params,
-             scoped_refptr<TaskRunner> service_thread_task_runner);
+             scoped_refptr<TaskRunner> service_thread_task_runner,
+             WorkerEnvironment worker_environment);
 
   // Destroying a SchedulerWorkerPoolImpl returned by Create() is not allowed in
   // production; it is always leaked. In tests, it can only be destroyed after
@@ -229,6 +241,9 @@
   // but haven't caused a worker capacity increase yet.
   int num_pending_may_block_workers_ = 0;
 
+  // Environment to be initialized per worker.
+  WorkerEnvironment worker_environment_ = WorkerEnvironment::NONE;
+
   // Stack of idle workers. Initially, all workers are on this stack. A worker
   // is removed from the stack before its WakeUp() function is called and when
   // it receives work from GetWork() (a worker calls GetWork() when its sleep
diff --git a/base/task_scheduler/scheduler_worker_pool_impl_unittest.cc b/base/task_scheduler/scheduler_worker_pool_impl_unittest.cc
index d6074b7..06be8aa 100644
--- a/base/task_scheduler/scheduler_worker_pool_impl_unittest.cc
+++ b/base/task_scheduler/scheduler_worker_pool_impl_unittest.cc
@@ -43,8 +43,13 @@
 #include "base/threading/thread_local_storage.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_WIN)
+#include "base/win/com_init_util.h"
+#endif  // defined(OS_WIN)
+
 namespace base {
 namespace internal {
 namespace {
@@ -85,11 +90,13 @@
     ASSERT_TRUE(worker_pool_);
   }
 
-  void StartWorkerPool(TimeDelta suggested_reclaim_time, size_t num_workers) {
+  virtual void StartWorkerPool(TimeDelta suggested_reclaim_time,
+                               size_t num_workers) {
     ASSERT_TRUE(worker_pool_);
     worker_pool_->Start(
         SchedulerWorkerPoolParams(num_workers, suggested_reclaim_time),
-        service_thread_.task_runner());
+        service_thread_.task_runner(),
+        SchedulerWorkerPoolImpl::WorkerEnvironment::NONE);
   }
 
   void CreateAndStartWorkerPool(TimeDelta suggested_reclaim_time,
@@ -255,6 +262,29 @@
   worker_pool_->WaitForAllWorkersIdleForTesting();
 }
 
+#if defined(OS_WIN)
+TEST_P(TaskSchedulerWorkerPoolImplTestParam, NoEnvironment) {
+  // Verify that COM is not initialized in a SchedulerWorkerPoolImpl initialized
+  // with SchedulerWorkerPoolImpl::WorkerEnvironment::NONE.
+  scoped_refptr<TaskRunner> task_runner =
+      CreateTaskRunnerWithExecutionMode(worker_pool_.get(), GetParam());
+
+  WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL,
+                             WaitableEvent::InitialState::NOT_SIGNALED);
+  task_runner->PostTask(
+      FROM_HERE, BindOnce(
+                     [](WaitableEvent* task_running) {
+                       win::AssertComApartmentType(win::ComApartmentType::NONE);
+                       task_running->Signal();
+                     },
+                     &task_running));
+
+  task_running.Wait();
+
+  worker_pool_->WaitForAllWorkersIdleForTesting();
+}
+#endif  // defined(OS_WIN)
+
 INSTANTIATE_TEST_CASE_P(Parallel,
                         TaskSchedulerWorkerPoolImplTestParam,
                         ::testing::Values(test::ExecutionMode::PARALLEL));
@@ -262,6 +292,64 @@
                         TaskSchedulerWorkerPoolImplTestParam,
                         ::testing::Values(test::ExecutionMode::SEQUENCED));
 
+#if defined(OS_WIN)
+
+namespace {
+
+class TaskSchedulerWorkerPoolImplTestCOMMTAParam
+    : public TaskSchedulerWorkerPoolImplTestBase,
+      public testing::TestWithParam<test::ExecutionMode> {
+ protected:
+  TaskSchedulerWorkerPoolImplTestCOMMTAParam() = default;
+
+  void SetUp() override { TaskSchedulerWorkerPoolImplTestBase::SetUp(); }
+
+  void TearDown() override { TaskSchedulerWorkerPoolImplTestBase::TearDown(); }
+
+ private:
+  void StartWorkerPool(TimeDelta suggested_reclaim_time,
+                       size_t num_workers) override {
+    ASSERT_TRUE(worker_pool_);
+    worker_pool_->Start(
+        SchedulerWorkerPoolParams(num_workers, suggested_reclaim_time),
+        service_thread_.task_runner(),
+        SchedulerWorkerPoolImpl::WorkerEnvironment::COM_MTA);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerPoolImplTestCOMMTAParam);
+};
+
+}  // namespace
+
+TEST_P(TaskSchedulerWorkerPoolImplTestCOMMTAParam, COMMTAInitialized) {
+  // Verify that SchedulerWorkerPoolImpl workers have a COM MTA available.
+  scoped_refptr<TaskRunner> task_runner =
+      CreateTaskRunnerWithExecutionMode(worker_pool_.get(), GetParam());
+
+  WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL,
+                             WaitableEvent::InitialState::NOT_SIGNALED);
+  task_runner->PostTask(
+      FROM_HERE, BindOnce(
+                     [](WaitableEvent* task_running) {
+                       win::AssertComApartmentType(win::ComApartmentType::MTA);
+                       task_running->Signal();
+                     },
+                     &task_running));
+
+  task_running.Wait();
+
+  worker_pool_->WaitForAllWorkersIdleForTesting();
+}
+
+INSTANTIATE_TEST_CASE_P(Parallel,
+                        TaskSchedulerWorkerPoolImplTestCOMMTAParam,
+                        ::testing::Values(test::ExecutionMode::PARALLEL));
+INSTANTIATE_TEST_CASE_P(Sequenced,
+                        TaskSchedulerWorkerPoolImplTestCOMMTAParam,
+                        ::testing::Values(test::ExecutionMode::SEQUENCED));
+
+#endif  // defined(OS_WIN)
+
 namespace {
 
 class TaskSchedulerWorkerPoolImplPostTaskBeforeStartTest
@@ -694,7 +782,8 @@
       "OnePolicyWorkerPool", ThreadPriority::NORMAL, &task_tracker,
       &delayed_task_manager);
   worker_pool->Start(SchedulerWorkerPoolParams(8U, TimeDelta::Max()),
-                     service_thread_task_runner);
+                     service_thread_task_runner,
+                     SchedulerWorkerPoolImpl::WorkerEnvironment::NONE);
   ASSERT_TRUE(worker_pool);
   EXPECT_EQ(1U, worker_pool->NumberOfWorkersForTesting());
   worker_pool->JoinForTesting();
@@ -715,7 +804,8 @@
       &delayed_task_manager);
   worker_pool->Start(
       SchedulerWorkerPoolParams(worker_capacity, kReclaimTimeForCleanupTests),
-      service_thread_task_runner);
+      service_thread_task_runner,
+      SchedulerWorkerPoolImpl::WorkerEnvironment::NONE);
   ASSERT_TRUE(worker_pool);
   EXPECT_EQ(1U, worker_pool->NumberOfWorkersForTesting());
 
@@ -1237,7 +1327,8 @@
                                       &delayed_task_manager);
   worker_pool.Start(
       SchedulerWorkerPoolParams(kWorkerCapacity, kReclaimTimeForCleanupTests),
-      service_thread_task_runner);
+      service_thread_task_runner,
+      SchedulerWorkerPoolImpl::WorkerEnvironment::NONE);
 
   scoped_refptr<TaskRunner> task_runner =
       worker_pool.CreateTaskRunnerWithTraits({WithBaseSyncPrimitives()});
diff --git a/base/task_scheduler/scheduler_worker_pool_unittest.cc b/base/task_scheduler/scheduler_worker_pool_unittest.cc
index 54c9c9a..818af0dd 100644
--- a/base/task_scheduler/scheduler_worker_pool_unittest.cc
+++ b/base/task_scheduler/scheduler_worker_pool_unittest.cc
@@ -133,7 +133,8 @@
         scheduler_worker_pool_impl->Start(
             SchedulerWorkerPoolParams(kNumWorkersInWorkerPool,
                                       TimeDelta::Max()),
-            service_thread_.task_runner());
+            service_thread_.task_runner(),
+            SchedulerWorkerPoolImpl::WorkerEnvironment::NONE);
         break;
       }
 #if defined(OS_WIN)
diff --git a/base/task_scheduler/task_scheduler.cc b/base/task_scheduler/task_scheduler.cc
index e01426e..29f8db4 100644
--- a/base/task_scheduler/task_scheduler.cc
+++ b/base/task_scheduler/task_scheduler.cc
@@ -27,13 +27,15 @@
     const SchedulerWorkerPoolParams& background_worker_pool_params_in,
     const SchedulerWorkerPoolParams& background_blocking_worker_pool_params_in,
     const SchedulerWorkerPoolParams& foreground_worker_pool_params_in,
-    const SchedulerWorkerPoolParams& foreground_blocking_worker_pool_params_in)
+    const SchedulerWorkerPoolParams& foreground_blocking_worker_pool_params_in,
+    SharedWorkerPoolEnvironment shared_worker_pool_environment_in)
     : background_worker_pool_params(background_worker_pool_params_in),
       background_blocking_worker_pool_params(
           background_blocking_worker_pool_params_in),
       foreground_worker_pool_params(foreground_worker_pool_params_in),
       foreground_blocking_worker_pool_params(
-          foreground_blocking_worker_pool_params_in) {}
+          foreground_blocking_worker_pool_params_in),
+      shared_worker_pool_environment(shared_worker_pool_environment_in) {}
 
 TaskScheduler::InitParams::~InitParams() = default;
 
diff --git a/base/task_scheduler/task_scheduler.h b/base/task_scheduler/task_scheduler.h
index 6e30af0..13605151 100644
--- a/base/task_scheduler/task_scheduler.h
+++ b/base/task_scheduler/task_scheduler.h
@@ -51,19 +51,31 @@
 class BASE_EXPORT TaskScheduler {
  public:
   struct BASE_EXPORT InitParams {
+    enum class SharedWorkerPoolEnvironment {
+      // Use the default environment (no environment).
+      DEFAULT,
+#if defined(OS_WIN)
+      // Place the worker in a COM MTA.
+      COM_MTA,
+#endif  // defined(OS_WIN)
+    };
+
     InitParams(
         const SchedulerWorkerPoolParams& background_worker_pool_params_in,
         const SchedulerWorkerPoolParams&
             background_blocking_worker_pool_params_in,
         const SchedulerWorkerPoolParams& foreground_worker_pool_params_in,
         const SchedulerWorkerPoolParams&
-            foreground_blocking_worker_pool_params_in);
+            foreground_blocking_worker_pool_params_in,
+        SharedWorkerPoolEnvironment shared_worker_pool_environment_in =
+            SharedWorkerPoolEnvironment::DEFAULT);
     ~InitParams();
 
     SchedulerWorkerPoolParams background_worker_pool_params;
     SchedulerWorkerPoolParams background_blocking_worker_pool_params;
     SchedulerWorkerPoolParams foreground_worker_pool_params;
     SchedulerWorkerPoolParams foreground_blocking_worker_pool_params;
+    SharedWorkerPoolEnvironment shared_worker_pool_environment;
   };
 
   // Destroying a TaskScheduler is not allowed in production; it is always
diff --git a/base/task_scheduler/task_scheduler_impl.cc b/base/task_scheduler/task_scheduler_impl.cc
index 3901cfdc..942c844 100644
--- a/base/task_scheduler/task_scheduler_impl.cc
+++ b/base/task_scheduler/task_scheduler_impl.cc
@@ -86,16 +86,28 @@
 
   single_thread_task_runner_manager_.Start();
 
+  const SchedulerWorkerPoolImpl::WorkerEnvironment worker_environment =
+#if defined(OS_WIN)
+      init_params.shared_worker_pool_environment ==
+              InitParams::SharedWorkerPoolEnvironment::COM_MTA
+          ? SchedulerWorkerPoolImpl::WorkerEnvironment::COM_MTA
+          : SchedulerWorkerPoolImpl::WorkerEnvironment::NONE;
+#else
+      SchedulerWorkerPoolImpl::WorkerEnvironment::NONE;
+#endif
+
   worker_pools_[BACKGROUND]->Start(init_params.background_worker_pool_params,
-                                   service_thread_task_runner);
+                                   service_thread_task_runner,
+                                   worker_environment);
   worker_pools_[BACKGROUND_BLOCKING]->Start(
       init_params.background_blocking_worker_pool_params,
-      service_thread_task_runner);
+      service_thread_task_runner, worker_environment);
   worker_pools_[FOREGROUND]->Start(init_params.foreground_worker_pool_params,
-                                   service_thread_task_runner);
+                                   service_thread_task_runner,
+                                   worker_environment);
   worker_pools_[FOREGROUND_BLOCKING]->Start(
       init_params.foreground_blocking_worker_pool_params,
-      service_thread_task_runner);
+      service_thread_task_runner, worker_environment);
 }
 
 void TaskSchedulerImpl::PostDelayedTaskWithTraits(const Location& from_here,
diff --git a/build/secondary/third_party/crashpad/crashpad/minidump/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/minidump/BUILD.gn
index ebc8f3b..d1c29a09 100644
--- a/build/secondary/third_party/crashpad/crashpad/minidump/BUILD.gn
+++ b/build/secondary/third_party/crashpad/crashpad/minidump/BUILD.gn
@@ -20,6 +20,8 @@
   }
 
   sources = [
+    "minidump_byte_array_writer.cc",
+    "minidump_byte_array_writer.h",
     "minidump_context.h",
     "minidump_context_writer.cc",
     "minidump_context_writer.h",
diff --git a/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn
index 703aa550..4fca9fe 100644
--- a/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn
+++ b/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn
@@ -18,6 +18,8 @@
   }
 
   sources = [
+    "annotation_snapshot.cc",
+    "annotation_snapshot.h",
     "capture_memory.cc",
     "capture_memory.h",
     "cpu_architecture.h",
@@ -51,6 +53,7 @@
     "mac/process_types.cc",
     "mac/process_types.h",
     "mac/process_types/all.proctype",
+    "mac/process_types/annotation.proctype",
     "mac/process_types/crashpad_info.proctype",
     "mac/process_types/crashreporterclient.proctype",
     "mac/process_types/custom.cc",
@@ -79,6 +82,7 @@
     "posix/timezone.cc",
     "posix/timezone.h",
     "process_snapshot.h",
+    "snapshot_constants.h",
     "system_snapshot.h",
     "thread_snapshot.h",
     "unloaded_module_snapshot.cc",
diff --git a/build/secondary/third_party/crashpad/crashpad/test/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/test/BUILD.gn
index a194928d..5027ad36d 100644
--- a/build/secondary/third_party/crashpad/crashpad/test/BUILD.gn
+++ b/build/secondary/third_party/crashpad/crashpad/test/BUILD.gn
@@ -9,6 +9,8 @@
     "errors.h",
     "file.cc",
     "file.h",
+    "filesystem.cc",
+    "filesystem.h",
     "gtest_death_check.h",
     "gtest_disabled.cc",
     "gtest_disabled.h",
diff --git a/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn
index 65367b93..fea27982 100644
--- a/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn
+++ b/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn
@@ -326,8 +326,6 @@
     "file/file_io_test.cc",
     "file/file_reader_test.cc",
     "file/filesystem_test.cc",
-    "file/filesystem_test_util.cc",
-    "file/filesystem_test_util.h",
     "file/string_file_test.cc",
     "mac/launchd_test.mm",
     "mac/mac_util_test.mm",
diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc
index 89a92d7..5758caf 100644
--- a/cc/paint/paint_op_buffer.cc
+++ b/cc/paint/paint_op_buffer.cc
@@ -206,10 +206,12 @@
 static const SerializeFunction g_serialize_functions[kNumOpTypes] = {TYPES(M)};
 #undef M
 
-using DeserializeFunction = PaintOp* (*)(const volatile void* input,
-                                         size_t input_size,
-                                         void* output,
-                                         size_t output_size);
+using DeserializeFunction =
+    PaintOp* (*)(const volatile void* input,
+                 size_t input_size,
+                 void* output,
+                 size_t output_size,
+                 const PaintOp::DeserializeOptions& options);
 
 #define M(T) &T::Deserialize,
 static const DeserializeFunction g_deserialize_functions[kNumOpTypes] = {
@@ -599,7 +601,8 @@
 PaintOp* AnnotateOp::Deserialize(const volatile void* input,
                                  size_t input_size,
                                  void* output,
-                                 size_t output_size) {
+                                 size_t output_size,
+                                 const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(AnnotateOp));
   AnnotateOp* op = new (output) AnnotateOp;
 
@@ -619,7 +622,8 @@
 PaintOp* ClipPathOp::Deserialize(const volatile void* input,
                                  size_t input_size,
                                  void* output,
-                                 size_t output_size) {
+                                 size_t output_size,
+                                 const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(ClipPathOp));
   ClipPathOp* op = new (output) ClipPathOp;
 
@@ -639,7 +643,8 @@
 PaintOp* ClipRectOp::Deserialize(const volatile void* input,
                                  size_t input_size,
                                  void* output,
-                                 size_t output_size) {
+                                 size_t output_size,
+                                 const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(ClipRectOp));
   return SimpleDeserialize<ClipRectOp>(input, input_size, output, output_size);
 }
@@ -647,7 +652,8 @@
 PaintOp* ClipRRectOp::Deserialize(const volatile void* input,
                                   size_t input_size,
                                   void* output,
-                                  size_t output_size) {
+                                  size_t output_size,
+                                  const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(ClipRRectOp));
   return SimpleDeserialize<ClipRRectOp>(input, input_size, output, output_size);
 }
@@ -655,7 +661,8 @@
 PaintOp* ConcatOp::Deserialize(const volatile void* input,
                                size_t input_size,
                                void* output,
-                               size_t output_size) {
+                               size_t output_size,
+                               const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(ConcatOp));
   auto* op =
       SimpleDeserialize<ConcatOp>(input, input_size, output, output_size);
@@ -667,7 +674,8 @@
 PaintOp* DrawColorOp::Deserialize(const volatile void* input,
                                   size_t input_size,
                                   void* output,
-                                  size_t output_size) {
+                                  size_t output_size,
+                                  const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(DrawColorOp));
   return SimpleDeserialize<DrawColorOp>(input, input_size, output, output_size);
 }
@@ -675,7 +683,8 @@
 PaintOp* DrawDRRectOp::Deserialize(const volatile void* input,
                                    size_t input_size,
                                    void* output,
-                                   size_t output_size) {
+                                   size_t output_size,
+                                   const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(DrawDRRectOp));
   DrawDRRectOp* op = new (output) DrawDRRectOp;
 
@@ -694,7 +703,8 @@
 PaintOp* DrawImageOp::Deserialize(const volatile void* input,
                                   size_t input_size,
                                   void* output,
-                                  size_t output_size) {
+                                  size_t output_size,
+                                  const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(DrawImageOp));
   DrawImageOp* op = new (output) DrawImageOp;
 
@@ -714,7 +724,8 @@
 PaintOp* DrawImageRectOp::Deserialize(const volatile void* input,
                                       size_t input_size,
                                       void* output,
-                                      size_t output_size) {
+                                      size_t output_size,
+                                      const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(DrawImageRectOp));
   DrawImageRectOp* op = new (output) DrawImageRectOp;
 
@@ -735,7 +746,8 @@
 PaintOp* DrawIRectOp::Deserialize(const volatile void* input,
                                   size_t input_size,
                                   void* output,
-                                  size_t output_size) {
+                                  size_t output_size,
+                                  const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(DrawIRectOp));
   DrawIRectOp* op = new (output) DrawIRectOp;
 
@@ -753,7 +765,8 @@
 PaintOp* DrawLineOp::Deserialize(const volatile void* input,
                                  size_t input_size,
                                  void* output,
-                                 size_t output_size) {
+                                 size_t output_size,
+                                 const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(DrawLineOp));
   DrawLineOp* op = new (output) DrawLineOp;
 
@@ -774,7 +787,8 @@
 PaintOp* DrawOvalOp::Deserialize(const volatile void* input,
                                  size_t input_size,
                                  void* output,
-                                 size_t output_size) {
+                                 size_t output_size,
+                                 const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(DrawOvalOp));
   DrawOvalOp* op = new (output) DrawOvalOp;
 
@@ -792,7 +806,8 @@
 PaintOp* DrawPathOp::Deserialize(const volatile void* input,
                                  size_t input_size,
                                  void* output,
-                                 size_t output_size) {
+                                 size_t output_size,
+                                 const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(DrawPathOp));
   DrawPathOp* op = new (output) DrawPathOp;
 
@@ -810,7 +825,8 @@
 PaintOp* DrawRecordOp::Deserialize(const volatile void* input,
                                    size_t input_size,
                                    void* output,
-                                   size_t output_size) {
+                                   size_t output_size,
+                                   const DeserializeOptions& options) {
   // TODO(enne): these must be flattened and not sent directly.
   // TODO(enne): could also consider caching these service side.
   return nullptr;
@@ -819,7 +835,8 @@
 PaintOp* DrawRectOp::Deserialize(const volatile void* input,
                                  size_t input_size,
                                  void* output,
-                                 size_t output_size) {
+                                 size_t output_size,
+                                 const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(DrawRectOp));
   DrawRectOp* op = new (output) DrawRectOp;
 
@@ -837,7 +854,8 @@
 PaintOp* DrawRRectOp::Deserialize(const volatile void* input,
                                   size_t input_size,
                                   void* output,
-                                  size_t output_size) {
+                                  size_t output_size,
+                                  const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(DrawRRectOp));
   DrawRRectOp* op = new (output) DrawRRectOp;
 
@@ -855,7 +873,8 @@
 PaintOp* DrawTextBlobOp::Deserialize(const volatile void* input,
                                      size_t input_size,
                                      void* output,
-                                     size_t output_size) {
+                                     size_t output_size,
+                                     const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(DrawTextBlobOp));
   DrawTextBlobOp* op = new (output) DrawTextBlobOp;
 
@@ -875,7 +894,8 @@
 PaintOp* NoopOp::Deserialize(const volatile void* input,
                              size_t input_size,
                              void* output,
-                             size_t output_size) {
+                             size_t output_size,
+                             const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(NoopOp));
   return SimpleDeserialize<NoopOp>(input, input_size, output, output_size);
 }
@@ -883,7 +903,8 @@
 PaintOp* RestoreOp::Deserialize(const volatile void* input,
                                 size_t input_size,
                                 void* output,
-                                size_t output_size) {
+                                size_t output_size,
+                                const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(RestoreOp));
   return SimpleDeserialize<RestoreOp>(input, input_size, output, output_size);
 }
@@ -891,7 +912,8 @@
 PaintOp* RotateOp::Deserialize(const volatile void* input,
                                size_t input_size,
                                void* output,
-                               size_t output_size) {
+                               size_t output_size,
+                               const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(RotateOp));
   return SimpleDeserialize<RotateOp>(input, input_size, output, output_size);
 }
@@ -899,7 +921,8 @@
 PaintOp* SaveOp::Deserialize(const volatile void* input,
                              size_t input_size,
                              void* output,
-                             size_t output_size) {
+                             size_t output_size,
+                             const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(SaveOp));
   return SimpleDeserialize<SaveOp>(input, input_size, output, output_size);
 }
@@ -907,7 +930,8 @@
 PaintOp* SaveLayerOp::Deserialize(const volatile void* input,
                                   size_t input_size,
                                   void* output,
-                                  size_t output_size) {
+                                  size_t output_size,
+                                  const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(SaveLayerOp));
   SaveLayerOp* op = new (output) SaveLayerOp;
 
@@ -925,7 +949,8 @@
 PaintOp* SaveLayerAlphaOp::Deserialize(const volatile void* input,
                                        size_t input_size,
                                        void* output,
-                                       size_t output_size) {
+                                       size_t output_size,
+                                       const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(SaveLayerAlphaOp));
   return SimpleDeserialize<SaveLayerAlphaOp>(input, input_size, output,
                                              output_size);
@@ -934,7 +959,8 @@
 PaintOp* ScaleOp::Deserialize(const volatile void* input,
                               size_t input_size,
                               void* output,
-                              size_t output_size) {
+                              size_t output_size,
+                              const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(ScaleOp));
 
   return SimpleDeserialize<ScaleOp>(input, input_size, output, output_size);
@@ -943,7 +969,8 @@
 PaintOp* SetMatrixOp::Deserialize(const volatile void* input,
                                   size_t input_size,
                                   void* output,
-                                  size_t output_size) {
+                                  size_t output_size,
+                                  const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(SetMatrixOp));
   auto* op =
       SimpleDeserialize<SetMatrixOp>(input, input_size, output, output_size);
@@ -955,7 +982,8 @@
 PaintOp* TranslateOp::Deserialize(const volatile void* input,
                                   size_t input_size,
                                   void* output,
-                                  size_t output_size) {
+                                  size_t output_size,
+                                  const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(TranslateOp));
   return SimpleDeserialize<TranslateOp>(input, input_size, output, output_size);
 }
@@ -1268,7 +1296,8 @@
                               size_t input_size,
                               void* output,
                               size_t output_size,
-                              size_t* read_bytes) {
+                              size_t* read_bytes,
+                              const DeserializeOptions& options) {
   DCHECK_GE(output_size, sizeof(LargestPaintOp));
 
   uint32_t first_word = reinterpret_cast<const volatile uint32_t*>(input)[0];
@@ -1282,7 +1311,8 @@
   if (type > static_cast<uint8_t>(PaintOpType::LastPaintOpType))
     return nullptr;
   *read_bytes = skip;
-  return g_deserialize_functions[type](input, skip, output, output_size);
+  return g_deserialize_functions[type](input, skip, output, output_size,
+                                       options);
 }
 
 // static
diff --git a/cc/paint/paint_op_buffer.h b/cc/paint/paint_op_buffer.h
index 4446c76..0568c5bf 100644
--- a/cc/paint/paint_op_buffer.h
+++ b/cc/paint/paint_op_buffer.h
@@ -54,7 +54,8 @@
   static size_t Serialize(const PaintOp* op, void* memory, size_t size,      \
                           const SerializeOptions& options);                  \
   static PaintOp* Deserialize(const volatile void* input, size_t input_size, \
-                              void* output, size_t output_size);
+                              void* output, size_t output_size,              \
+                              const DeserializeOptions& options);
 
 enum class PaintOpType : uint8_t {
   Annotate,
@@ -114,6 +115,8 @@
     ImageDecodeCache* decode_cache = nullptr;
   };
 
+  struct DeserializeOptions {};
+
   // Subclasses should provide a static Serialize() method called from here.
   // If the op can be serialized to |memory| in no more than |size| bytes,
   // then return the number of bytes written.  If it won't fit, return 0.
@@ -132,7 +135,8 @@
                               size_t input_size,
                               void* output,
                               size_t output_size,
-                              size_t* read_bytes);
+                              size_t* read_bytes,
+                              const DeserializeOptions& options);
 
   // For draw ops, returns true if a conservative bounding rect can be provided
   // for the op.
diff --git a/cc/paint/paint_op_buffer_fuzzer.cc b/cc/paint/paint_op_buffer_fuzzer.cc
index 6a7cca6b..b296570 100644
--- a/cc/paint/paint_op_buffer_fuzzer.cc
+++ b/cc/paint/paint_op_buffer_fuzzer.cc
@@ -27,6 +27,7 @@
   SkCanvas* canvas = surface->getCanvas();
 
   cc::PlaybackParams params(nullptr, canvas->getTotalMatrix());
+  cc::PaintOp::DeserializeOptions deserialize_options;
 
   // Need 4 bytes to be able to read the type/skip.
   while (size >= 4) {
@@ -38,9 +39,9 @@
         static_cast<char*>(base::AlignedAlloc(
             sizeof(cc::LargestPaintOp), cc::PaintOpBuffer::PaintOpAlign)));
     size_t bytes_read = 0;
-    cc::PaintOp* deserialized_op =
-        cc::PaintOp::Deserialize(data, size, deserialized.get(),
-                                 sizeof(cc::LargestPaintOp), &bytes_read);
+    cc::PaintOp* deserialized_op = cc::PaintOp::Deserialize(
+        data, size, deserialized.get(), sizeof(cc::LargestPaintOp), &bytes_read,
+        deserialize_options);
 
     if (!deserialized_op)
       break;
diff --git a/cc/paint/paint_op_buffer_unittest.cc b/cc/paint/paint_op_buffer_unittest.cc
index af65cb8..56bdab6 100644
--- a/cc/paint/paint_op_buffer_unittest.cc
+++ b/cc/paint/paint_op_buffer_unittest.cc
@@ -1359,9 +1359,9 @@
 
     if (!remaining_)
       return;
-    deserialized_op_ =
-        PaintOp::Deserialize(current_, remaining_, data_.get(),
-                             sizeof(LargestPaintOp), &last_bytes_read_);
+    deserialized_op_ = PaintOp::Deserialize(current_, remaining_, data_.get(),
+                                            sizeof(LargestPaintOp),
+                                            &last_bytes_read_, options);
   }
 
   const void* input_ = nullptr;
@@ -1369,6 +1369,7 @@
   size_t input_size_ = 0u;
   size_t remaining_ = 0u;
   size_t last_bytes_read_ = 0u;
+  PaintOp::DeserializeOptions options;
   std::unique_ptr<char, base::AlignedFreeDeleter> data_;
   PaintOp* deserialized_op_ = nullptr;
 };
@@ -2153,6 +2154,7 @@
   static constexpr size_t kOutputOpSize = kBufferBytesPerOp;
   std::unique_ptr<char, base::AlignedFreeDeleter> deserialize_buffer_(
       static_cast<char*>(base::AlignedAlloc(kOutputOpSize, kAlign)));
+  PaintOp::DeserializeOptions deserialize_options;
 
   size_t op_idx = 0;
   for (PaintOpBuffer::Iterator iter(&buffer_); iter; ++iter, ++op_idx) {
@@ -2175,7 +2177,7 @@
       size_t bytes_read = 0;
       PaintOp* written =
           PaintOp::Deserialize(current, read_size, deserialize_buffer_.get(),
-                               kOutputOpSize, &bytes_read);
+                               kOutputOpSize, &bytes_read, deserialize_options);
 
       // Skips are only valid if they are aligned.
       if (read_size >= skip && read_size % kAlign == 0) {
@@ -2203,6 +2205,7 @@
       static_cast<char*>(base::AlignedAlloc(kSize, kAlign)));
   std::unique_ptr<char, base::AlignedFreeDeleter> output_(
       static_cast<char*>(base::AlignedAlloc(kSize, kAlign)));
+  PaintOp::DeserializeOptions deserialize_options;
 
   PaintOpBuffer buffer;
   buffer.push<DrawColorOp>(SK_ColorMAGENTA, SkBlendMode::kSrc);
@@ -2211,14 +2214,15 @@
   PaintOp* op = *iter;
   ASSERT_TRUE(op);
 
-  PaintOp::SerializeOptions options;
-  size_t bytes_written = op->Serialize(input_.get(), kSize, options);
+  PaintOp::SerializeOptions serialize_options;
+  size_t bytes_written = op->Serialize(input_.get(), kSize, serialize_options);
   ASSERT_GT(bytes_written, 0u);
 
   // can deserialize from exactly the right size
   size_t bytes_read = 0;
-  PaintOp* success = PaintOp::Deserialize(input_.get(), bytes_written,
-                                          output_.get(), kSize, &bytes_read);
+  PaintOp* success =
+      PaintOp::Deserialize(input_.get(), bytes_written, output_.get(), kSize,
+                           &bytes_read, deserialize_options);
   ASSERT_TRUE(success);
   EXPECT_EQ(bytes_written, bytes_read);
   success->DestroyThis();
@@ -2227,20 +2231,20 @@
   // (the DeserializationFailures test above tests if the skip is lying)
   for (size_t i = 0; i < bytes_written - 1; ++i)
     EXPECT_FALSE(PaintOp::Deserialize(input_.get(), i, output_.get(), kSize,
-                                      &bytes_read));
+                                      &bytes_read, deserialize_options));
 
   // unaligned skips fail to deserialize
   PaintOp* serialized = reinterpret_cast<PaintOp*>(input_.get());
   EXPECT_EQ(0u, serialized->skip % kAlign);
   serialized->skip -= 1;
   EXPECT_FALSE(PaintOp::Deserialize(input_.get(), bytes_written, output_.get(),
-                                    kSize, &bytes_read));
+                                    kSize, &bytes_read, deserialize_options));
   serialized->skip += 1;
 
   // bogus types fail to deserialize
   serialized->type = static_cast<uint8_t>(PaintOpType::LastPaintOpType) + 1;
   EXPECT_FALSE(PaintOp::Deserialize(input_.get(), bytes_written, output_.get(),
-                                    kSize, &bytes_read));
+                                    kSize, &bytes_read, deserialize_options));
 }
 
 // Test that deserializing invalid SkClipOp enums fails silently.
@@ -2271,18 +2275,19 @@
   SkClipOp bad_clip_max = static_cast<SkClipOp>(~static_cast<uint32_t>(0));
   buffer.push<ClipRectOp>(test_rects[1], bad_clip_max, false);
 
-  PaintOp::SerializeOptions options;
+  PaintOp::SerializeOptions serialize_options;
+  PaintOp::DeserializeOptions deserialize_options;
 
   int op_idx = 0;
   for (PaintOpBuffer::Iterator iter(&buffer); iter; ++iter) {
     const PaintOp* op = *iter;
     size_t bytes_written =
-        op->Serialize(serialized.get(), buffer_size, options);
+        op->Serialize(serialized.get(), buffer_size, serialize_options);
     ASSERT_GT(bytes_written, 0u);
     size_t bytes_read = 0;
-    PaintOp* written =
-        PaintOp::Deserialize(serialized.get(), bytes_written,
-                             deserialized.get(), buffer_size, &bytes_read);
+    PaintOp* written = PaintOp::Deserialize(serialized.get(), bytes_written,
+                                            deserialized.get(), buffer_size,
+                                            &bytes_read, deserialize_options);
     // First op should succeed.  Other ops with bad enums should
     // serialize correctly but fail to deserialize due to the bad
     // SkClipOp enum.
@@ -2351,18 +2356,19 @@
     buffer.push<DrawRectOp>(test_rects[i % test_rects.size()], flags);
   }
 
-  PaintOp::SerializeOptions options;
+  PaintOp::SerializeOptions serialize_options;
+  PaintOp::DeserializeOptions deserialize_options;
 
   int op_idx = 0;
   for (PaintOpBuffer::Iterator iter(&buffer); iter; ++iter) {
     const PaintOp* op = *iter;
     size_t bytes_written =
-        op->Serialize(serialized.get(), buffer_size, options);
+        op->Serialize(serialized.get(), buffer_size, serialize_options);
     ASSERT_GT(bytes_written, 0u);
     size_t bytes_read = 0;
-    PaintOp* written =
-        PaintOp::Deserialize(serialized.get(), bytes_written,
-                             deserialized.get(), buffer_size, &bytes_read);
+    PaintOp* written = PaintOp::Deserialize(serialized.get(), bytes_written,
+                                            deserialized.get(), buffer_size,
+                                            &bytes_read, deserialize_options);
     // First two ops should succeed.  Other ops with bad enums should
     // serialize correctly but fail to deserialize due to the bad
     // SkBlendMode enum.
@@ -2406,19 +2412,20 @@
   buffer.push<SaveLayerOp>(&bad_rect, &test_flags[0]);
   buffer.push<SaveLayerAlphaOp>(&bad_rect, test_uint8s[0], true);
 
-  PaintOp::SerializeOptions options;
+  PaintOp::SerializeOptions serialize_options;
+  PaintOp::DeserializeOptions deserialize_options;
 
   // Every op should serialize but fail to deserialize due to the bad rect.
   int op_idx = 0;
   for (PaintOpBuffer::Iterator iter(&buffer); iter; ++iter) {
     const PaintOp* op = *iter;
     size_t bytes_written =
-        op->Serialize(serialized.get(), buffer_size, options);
+        op->Serialize(serialized.get(), buffer_size, serialize_options);
     ASSERT_GT(bytes_written, 0u);
     size_t bytes_read = 0;
-    PaintOp* written =
-        PaintOp::Deserialize(serialized.get(), bytes_written,
-                             deserialized.get(), buffer_size, &bytes_read);
+    PaintOp* written = PaintOp::Deserialize(serialized.get(), bytes_written,
+                                            deserialized.get(), buffer_size,
+                                            &bytes_read, deserialize_options);
     EXPECT_FALSE(written) << "op: " << op_idx;
     ++op_idx;
   }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 556bb3a..2ede08c 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -400,6 +400,7 @@
     "$google_play_services_package:google_play_services_cast_java",
     "//base:base_java",
     "//base:base_java_test_support",
+    "//base:base_junit_test_support",
     "//chrome/android/webapk/libs/client:client_java",
     "//chrome/android/webapk/libs/common:common_java",
     "//chrome/android/webapk/test:junit_test_support",
diff --git a/chrome/android/java/res/drawable/site_explore_page_indicator.xml b/chrome/android/java/res/drawable/site_explore_page_indicator.xml
deleted file mode 100644
index 1c559f8..0000000
--- a/chrome/android/java/res/drawable/site_explore_page_indicator.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:exitFadeDuration="@android:integer/config_mediumAnimTime"
-    android:enterFadeDuration="@android:integer/config_mediumAnimTime">
-<item android:state_selected="true">
-    <shape android:shape="oval">
-        <solid android:color="@color/google_grey_600"/>
-        <size android:width="8dp" android:height="8dp"/>
-    </shape>
-</item>
-<item>
-    <shape android:shape="oval">
-        <solid android:color="@color/google_grey_400"/>
-        <size android:width="8dp" android:height="8dp"/>
-    </shape>
-</item>
-</selector>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/suggestions_site_explore.xml b/chrome/android/java/res/layout/suggestions_site_explore.xml
deleted file mode 100644
index 5fa541d1..0000000
--- a/chrome/android/java/res/layout/suggestions_site_explore.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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. -->
-
-<org.chromium.chrome.browser.suggestions.SiteExploreViewPager
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:chrome="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/site_explore_pager"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_marginStart="@dimen/tile_grid_layout_padding_start"
-    android:layout_marginEnd="@dimen/tile_grid_layout_padding_end"
-    android:layout_gravity="center_horizontal"
-    android:paddingBottom="20dp">
-
-    <android.support.design.widget.TabLayout
-        android:id="@+id/tab_layout"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top"
-        android:clipToPadding="false"
-        chrome:tabTextAppearance="@android:style/TextAppearance.Widget.TabWidget"
-        chrome:tabGravity="fill"
-        chrome:tabMode="scrollable"
-        />
-
-        <org.chromium.chrome.browser.suggestions.SiteExplorePageIndicatorView
-            android:id="@+id/tile_section_indicator_view"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="bottom"
-            android:paddingTop="10dp"
-            android:orientation="horizontal"
-            android:gravity="center_horizontal"
-            />
-    </org.chromium.chrome.browser.suggestions.SiteExploreViewPager>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index 102969d..bc6718e8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -215,7 +215,6 @@
     public static final String PWA_PERSISTENT_NOTIFICATION = "PwaPersistentNotification";
     public static final String READER_MODE_IN_CCT = "ReaderModeInCCT";
     public static final String SERVICE_WORKER_PAYMENT_APPS = "ServiceWorkerPaymentApps";
-    public static final String SITE_EXPLORATION_UI = "SiteExplorationUi";
     public static final String SITE_NOTIFICATION_CHANNELS = "SiteNotificationChannels";
     public static final String SOUND_CONTENT_SETTING = "SoundContentSetting";
     public static final String SPANNABLE_INLINE_AUTOCOMPLETE = "SpannableInlineAutocomplete";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
index 267131ac..8c8ce5dd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
@@ -162,6 +162,11 @@
                 TimeUnit.HOURS.toMillis(1), TimeUnit.DAYS.toMillis(30), TimeUnit.MILLISECONDS, 50);
     }
 
+    /** Records to UMA the count of old "WebAPK update request" files. */
+    public static void recordNumberOfStaleWebApkUpdateRequestFiles(int count) {
+        RecordHistogram.recordCountHistogram("WebApk.Update.NumStaleUpdateRequestFiles", count);
+    }
+
     /**
      * Log necessary disk usage and cache size UMAs when WebAPK installation fails.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
index f8203c8..dce01fb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -20,7 +20,6 @@
 import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView;
 import org.chromium.chrome.browser.ntp.snippets.SnippetsConfig;
 import org.chromium.chrome.browser.suggestions.SiteSection;
-import org.chromium.chrome.browser.suggestions.SuggestionsConfig;
 import org.chromium.chrome.browser.suggestions.TileGridLayout;
 
 /**
@@ -119,10 +118,7 @@
     }
 
     /**
-     * @return different result depending on whether {@link
-     * SuggestionsConfig#useSitesExplorationUi()} is enabled. When the sites exploration feature is
-     * enabled, this will return the enclosing view group of the explore layout file. Otherwise,
-     * this method will return a {@link TileGridLayout}.
+     * @return the embedded {@link TileGridLayout}.
      */
     public ViewGroup getSiteSectionView() {
         return mSiteSectionView;
@@ -147,19 +143,11 @@
         mLogoSpacer.setVisibility(View.GONE);
         mSearchBoxSpacer.setVisibility(View.GONE);
 
-        if (!SuggestionsConfig.useSitesExplorationUi()) {
-            // Remove the extra spacing before measuring because it might not be needed anymore.
-            ((TileGridLayout) mSiteSectionView).setExtraVerticalSpacing(0);
-        }
+        // Remove the extra spacing before measuring because it might not be needed anymore.
+        ((TileGridLayout) mSiteSectionView).setExtraVerticalSpacing(0);
 
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
-        if (SuggestionsConfig.useSitesExplorationUi()) {
-            // We want to skip vertical spacing when site explore is enabled, but we still need
-            // to call onMeasure() before returning.
-            return;
-        }
-
         boolean hasSpaceForPeekingCard = false;
         int spaceToFill = mParentViewportHeight - mPeekingCardHeight - mTabStripHeight;
         @NTPLayoutResult int layoutResult;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteExplorePageIndicatorView.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteExplorePageIndicatorView.java
deleted file mode 100644
index c5d4297..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteExplorePageIndicatorView.java
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.suggestions;
-
-import android.content.Context;
-import android.database.DataSetObserver;
-import android.support.annotation.Nullable;
-import android.support.v4.view.ViewPager;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.util.ViewUtils;
-
-/**
- * Page indicator view for a {@link ViewPager}. It has to be inserted as a child of the
- * {@link ViewPager}. After this, it will read the number of pages, display that many dots and
- * highlight the dot of the selected tab.
- */
-public class SiteExplorePageIndicatorView
-        extends LinearLayout implements ViewPager.OnPageChangeListener {
-    private static final int SPACE_BETWEEN_INDICATORS_DP = 8;
-
-    private ViewPager mViewPager;
-    private DataSetObserver mDataSetObserver;
-    private int mCurrentSelectedPosition;
-
-    public SiteExplorePageIndicatorView(Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-        mDataSetObserver = new DataSetObserver() {
-            @Override
-            public void onChanged() {
-                addPageIndicators();
-            }
-        };
-    }
-
-    @Override
-    public void onPageScrolled(int i, float v, int i1) {}
-
-    @Override
-    public void onPageSelected(int newPosition) {
-        // Switch the highlighted dot to the one corresponding to the newly selected page.
-        View currentSelectedView = getChildAt(mCurrentSelectedPosition);
-        View newSelectedView = getChildAt(newPosition);
-
-        currentSelectedView.setSelected(false);
-        newSelectedView.setSelected(true);
-
-        mCurrentSelectedPosition = newPosition;
-    }
-
-    @Override
-    public void onPageScrollStateChanged(int i) {}
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        mViewPager = (ViewPager) getParent();
-
-        mViewPager.addOnPageChangeListener(this);
-        mViewPager.getAdapter().registerDataSetObserver(mDataSetObserver);
-
-        ((ViewPager.LayoutParams) getLayoutParams()).isDecor = true;
-
-        addPageIndicators();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        mViewPager.removeOnPageChangeListener(this);
-        mViewPager.getAdapter().unregisterDataSetObserver(mDataSetObserver);
-        mViewPager = null;
-    }
-
-    private void addPageIndicators() {
-        int numberOfPages = mViewPager.getAdapter().getCount();
-        mCurrentSelectedPosition = mViewPager.getCurrentItem();
-
-        removeAllViews();
-
-        int indicatorSideMarginPx = ViewUtils.dpToPx(getContext(), SPACE_BETWEEN_INDICATORS_DP / 2);
-        for (int i = 0; i < numberOfPages; i++) {
-            ImageView singlePageIndicatorView = new ImageView(getContext());
-
-            singlePageIndicatorView.setBackgroundResource(R.drawable.site_explore_page_indicator);
-            singlePageIndicatorView.setAdjustViewBounds(true);
-
-            // Set space on both sides of the indicator.
-            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
-                    LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
-            lp.setMargins(indicatorSideMarginPx, 0, indicatorSideMarginPx, 0);
-            singlePageIndicatorView.setLayoutParams(lp);
-
-            if (i == mCurrentSelectedPosition) {
-                singlePageIndicatorView.setSelected(true);
-            }
-
-            addView(singlePageIndicatorView);
-        }
-    }
-
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteExploreViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteExploreViewHolder.java
deleted file mode 100644
index 19781cb..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteExploreViewHolder.java
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.suggestions;
-
-import android.content.Context;
-import android.support.annotation.Nullable;
-import android.support.v4.view.PagerAdapter;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.chromium.chrome.R;
-
-import java.util.List;
-
-/**
- * A view holder for the Explore UI.
- */
-public class SiteExploreViewHolder extends SiteSectionViewHolder {
-    private final int mMaxTileColumns;
-    private SiteExploreViewPager mSiteExploreViewPager;
-    private SiteExploreViewHolder.ExploreSectionsAdapter mAdapter;
-
-    public SiteExploreViewHolder(ViewGroup view, int maxTileColumns) {
-        super(view);
-        mMaxTileColumns = maxTileColumns;
-        mSiteExploreViewPager = itemView.findViewById(R.id.site_explore_pager);
-
-        mAdapter = new ExploreSectionsAdapter(itemView.getContext());
-        mSiteExploreViewPager.setAdapter(mAdapter);
-    }
-
-    @Override
-    public void refreshData() {
-        mAdapter.updateTiles(mTileGroup.getTileSections());
-    }
-
-    @Nullable
-    @Override
-    protected TileView findTileView(SiteSuggestion data) {
-        return mAdapter.findTileView(data);
-    }
-
-    /**
-     * Adapter for the Explore UI view holder.
-     */
-    public class ExploreSectionsAdapter extends PagerAdapter {
-        private final Context mContext;
-        /**
-         * We use the category {@link TileSectionType} as key. The value is the layout used for
-         * that category in the {@link SiteExploreViewPager}. At any one time there will be at most
-         * three layouts stored in this array - the one that is currently shown on the screen and
-         * the two on either side of it.
-         */
-        private SparseArray<TileGridLayout> mTileSectionLayouts;
-
-        /**
-         * The latest tile sections which came with an update from
-         * {@link #updateTiles(SparseArray)}. The key is the section id and the value is the
-         * list of tiles within this section. See {@link TileSectionType}.
-         */
-        private SparseArray<List<Tile>> mLatestTileSections;
-
-        public ExploreSectionsAdapter(Context context) {
-            mContext = context;
-            mTileSectionLayouts = new SparseArray<TileGridLayout>();
-        }
-
-        @Override
-        public View instantiateItem(ViewGroup container, int position) {
-            List<Tile> tileSectionList = mLatestTileSections.valueAt(position);
-            if (tileSectionList == null) return null;
-
-            @TileSectionType
-            int sectionType = mTileGroup.getTileSections().keyAt(position);
-            TileGridLayout layout = mTileSectionLayouts.get(sectionType);
-            if (layout == null) {
-                layout = new TileGridLayout(mContext, null);
-
-                layout.setMaxRows(1);
-                layout.setMaxColumns(mMaxTileColumns);
-                mTileRenderer.renderTileSection(
-                        tileSectionList, layout, mTileGroup.getTileSetupDelegate());
-                mTileSectionLayouts.put(sectionType, layout);
-            }
-
-            if (sectionType == TileSectionType.PERSONALIZED) {
-                mTileGroup.notifyTilesRendered();
-            }
-
-            container.addView(layout);
-            return layout;
-        }
-
-        @Override
-        public void destroyItem(ViewGroup container, int position, Object object) {
-            container.removeView((View) object);
-            mTileSectionLayouts.remove(mTileSectionLayouts.keyAt(position));
-        }
-
-        @Override
-        public int getCount() {
-            return mLatestTileSections == null ? 0 : mLatestTileSections.size();
-        }
-
-        @Override
-        public String getPageTitle(int position) {
-            @TileSectionType
-            int sectionType = (mLatestTileSections.keyAt(position));
-            int stringRes;
-            switch (sectionType) {
-                case TileSectionType.PERSONALIZED:
-                    stringRes = R.string.ntp_sites_exploration_category_personalized_title;
-                    break;
-                case TileSectionType.SOCIAL:
-                    stringRes = R.string.ntp_sites_exploration_category_social_title;
-                    break;
-                case TileSectionType.ENTERTAINMENT:
-                    stringRes = R.string.ntp_sites_exploration_category_entertainment_title;
-                    break;
-                case TileSectionType.NEWS:
-                    stringRes = R.string.ntp_sites_exploration_category_news_title;
-                    break;
-                case TileSectionType.ECOMMERCE:
-                    stringRes = R.string.ntp_sites_exploration_category_ecommerce_title;
-                    break;
-                case TileSectionType.TOOLS:
-                    stringRes = R.string.ntp_sites_exploration_category_tools_title;
-                    break;
-                case TileSectionType.TRAVEL:
-                    stringRes = R.string.ntp_sites_exploration_category_travel_title;
-                    break;
-                case TileSectionType.UNKNOWN:
-                default:
-                    stringRes = R.string.ntp_sites_exploration_category_other_title;
-                    break;
-            }
-
-            return mContext.getResources().getString(stringRes);
-        }
-
-        @Override
-        public boolean isViewFromObject(View view, Object object) {
-            return view == object;
-        }
-
-        @Nullable
-        public TileView findTileView(SiteSuggestion suggestion) {
-            TileGridLayout layout = mTileSectionLayouts.get(suggestion.sectionType);
-            if (layout == null) return null;
-            return layout.getTileView(suggestion);
-        }
-
-        /**
-         * Updates the data set for the adapter. We use this method instead of directly reading
-         * data from the {@link TileGroup} because this allows us to update the tiles directly
-         * and prevents inconsistencies with the data.
-         *
-         * @param freshTileSections The new information for the tile sections.
-         */
-        public void updateTiles(SparseArray<List<Tile>> freshTileSections) {
-            mLatestTileSections = freshTileSections;
-
-            // Get the category IDs of the section layouts which are already rendered.
-            int[] layoutCategoryIds = new int[mTileSectionLayouts.size()];
-            for (int i = 0; i < mTileSectionLayouts.size(); i++) {
-                layoutCategoryIds[i] = mTileSectionLayouts.keyAt(i);
-            }
-
-            for (@TileSectionType int layoutCategoryId : layoutCategoryIds) {
-                if (freshTileSections.get(layoutCategoryId) == null) {
-                    // Remove the section layout from the view pager because it is not in the
-                    // freshly fetched sections.
-                    mSiteExploreViewPager.removeView(mTileSectionLayouts.get(layoutCategoryId));
-                    mTileSectionLayouts.remove(layoutCategoryId);
-                    continue;
-                }
-                mTileRenderer.renderTileSection(freshTileSections.get(layoutCategoryId),
-                        mTileSectionLayouts.get(layoutCategoryId),
-                        mTileGroup.getTileSetupDelegate());
-            }
-            notifyDataSetChanged();
-        }
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteExploreViewPager.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteExploreViewPager.java
deleted file mode 100644
index bcabdbba..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteExploreViewPager.java
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.suggestions;
-
-import android.content.Context;
-import android.support.v4.view.ViewPager;
-import android.util.AttributeSet;
-import android.view.View;
-
-/**
- * View Pager for the Site Explore UI. This is needed in order to correctly calculate the height
- * of this section on {@link #onMeasure(int, int)}.
- */
-public class SiteExploreViewPager extends ViewPager {
-    public SiteExploreViewPager(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        // We need to override this method to support the wrap_content behaviour that is not handled
-        // by the base implementation.
-
-        // We need to call super to let the ViewPager initialize its children pages first. This will
-        // call ViewPagerAdapter.initializeItem(), which will add the pages. However, this
-        // does not measure the heights of the children. That's why we need to measure the
-        // children's heights explicitly after that.
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-        int neededHeight = 0;
-
-        // Get the required height from the view pager's children. ViewPager decors (e.g. TabLayout)
-        // and ViewPager pages are both ViewPager children. The decors come first. We add up the
-        // heights of all decors and the height of the first page to get the required height for the
-        // view pager. We assume that all pages have the same height.
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            child.measure(
-                    widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-
-            neededHeight += child.getMeasuredHeight();
-
-            // Break the loop when we see the first page (non decor view).
-            if (!((ViewPager.LayoutParams) child.getLayoutParams()).isDecor) break;
-        }
-
-        // Take into account vertical padding.
-        neededHeight += getPaddingTop() + getPaddingBottom();
-
-        // Create a new measure specification with the newly calculated height.
-        heightMeasureSpec = MeasureSpec.makeMeasureSpec(neededHeight, MeasureSpec.EXACTLY);
-
-        // TODO(galinap): Restrict view pager's width to tile_grid_layout_max_width in NTP.
-
-        // Super method has to be called again so the new specs are treated as exact measurements.
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSection.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSection.java
index 42bc315..9223e908 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSection.java
@@ -49,9 +49,7 @@
     }
 
     public static SiteSectionViewHolder createViewHolder(ViewGroup view, UiConfig uiConfig) {
-        return SuggestionsConfig.useSitesExplorationUi()
-                ? new SiteExploreViewHolder(view, MAX_TILE_COLUMNS)
-                : new TileGridViewHolder(view, getMaxTileRows(), MAX_TILE_COLUMNS, uiConfig);
+        return new TileGridViewHolder(view, getMaxTileRows(), MAX_TILE_COLUMNS, uiConfig);
     }
 
     public SiteSection(SuggestionsUiDelegate uiDelegate, ContextMenuManager contextMenuManager,
@@ -127,9 +125,6 @@
 
     @LayoutRes
     private static int getLayout() {
-        if (SuggestionsConfig.useSitesExplorationUi()) {
-            return R.layout.suggestions_site_explore;
-        }
         if (FeatureUtilities.isChromeHomeEnabled()) {
             return R.layout.suggestions_site_tile_grid_modern;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java
index 02b1c3b..54bda01 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java
@@ -44,13 +44,6 @@
     }
 
     /**
-     * @return Whether to use the Sites exploration UI to display the site suggestions.
-     */
-    public static boolean useSitesExplorationUi() {
-        return ChromeFeatureList.isEnabled(ChromeFeatureList.SITE_EXPLORATION_UI);
-    }
-
-    /**
      * @param resources The resources to fetch the color from.
      * @return The background color for the suggestions sheet content.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeHomeSurveyController.java b/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeHomeSurveyController.java
index d27c8e4..a911350 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeHomeSurveyController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeHomeSurveyController.java
@@ -32,12 +32,13 @@
  * Class that controls if and when to show surveys related to the Chrome Home experiment.
  */
 public class ChromeHomeSurveyController {
-    static final String SURVEY_INFO_BAR_DISPLAYED = "chrome_home_survey_info_bar_displayed";
-    static final long ONE_WEEK_IN_MILLIS = 604800000L;
+    public static final String SURVEY_INFO_BAR_DISPLAYED = "chrome_home_survey_info_bar_displayed";
+    public static final String PARAM_NAME = "survey_override_site_id";
 
-    private static final String PARAM_NAME = "survey_override_site_id";
     private static final String TRIAL_NAME = "ChromeHome";
 
+    static final long ONE_WEEK_IN_MILLIS = 604800000L;
+
     private TabModelSelector mTabModelSelector;
 
     private ChromeHomeSurveyController() {
@@ -80,10 +81,10 @@
     }
 
     private boolean doesUserQualifyForSurvey() {
-        if (!isUMAEnabled()) return false;
         if (CommandLine.getInstance().hasSwitch(ChromeSwitches.CHROME_HOME_FORCE_ENABLE_SURVEY)) {
             return true;
         }
+        if (!isUMAEnabled()) return false;
         if (AccessibilityUtil.isAccessibilityEnabled()) return false;
         if (hasInfoBarBeenDisplayed()) return false;
         if (!FeatureUtilities.isChromeHomeEnabled()) return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
index 98aba2b2..b8f21c4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
@@ -1188,7 +1188,11 @@
     }
 
     private void onStateLoaded() {
-        if (mObserver != null) mObserver.onStateLoaded();
+        if (mObserver != null) {
+            // mergeState() starts an AsyncTask to call this and this calls
+            // onTabStateInitialized which should be called from the UI thread.
+            ThreadUtils.runOnUiThread( () -> mObserver.onStateLoaded() );
+        }
     }
 
     private void loadNextTab() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
index 5227372..0080ce9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
@@ -14,7 +14,6 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
-import org.chromium.base.PathUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.blink_public.platform.WebDisplayMode;
 import org.chromium.chrome.browser.ShortcutHelper;
@@ -34,9 +33,6 @@
 public class WebappDataStorage {
     private static final String TAG = "WebappDataStorage";
 
-    /** Path of subdirectory within cache directory which contains data for pending updates. */
-    static final String UPDATE_DIRECTORY_PATH = "webapk/update";
-
     static final String SHARED_PREFS_FILE_PREFIX = "webapp_";
     static final String KEY_SPLASH_ICON = "splash_icon";
     static final String KEY_LAST_USED = "last_used";
@@ -501,9 +497,7 @@
      * SharedPreferences.
      */
     String createAndSetUpdateRequestFilePath(WebApkInfo info) {
-        String filePath =
-                new File(new File(PathUtils.getCacheDirectory(), UPDATE_DIRECTORY_PATH), info.id())
-                        .getPath();
+        String filePath = WebappDirectoryManager.getWebApkUpdateFilePathForStorage(this).getPath();
         mPreferences.edit().putString(KEY_PENDING_UPDATE_FILE_PATH, filePath).apply();
         return filePath;
     }
@@ -534,6 +528,14 @@
         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
+    /**
+     * Returns whether a check for whether the Web Manifest needs to be updated has occurred in the
+     * last {@link numMillis} milliseconds.
+     */
+    boolean wasCheckForUpdatesDoneInLastMs(long numMillis) {
+        return (sClock.currentTimeMillis() - getLastCheckForWebManifestUpdateTime()) < numMillis;
+    }
+
     /** Returns whether we should check for update. */
     boolean shouldCheckForUpdate() {
         long checkUpdatesInterval =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDirectoryManager.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDirectoryManager.java
index 6accda76..c915453 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDirectoryManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDirectoryManager.java
@@ -19,8 +19,10 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.FileUtils;
 import org.chromium.base.Log;
+import org.chromium.base.PathUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.document.DocumentUtils;
+import org.chromium.chrome.browser.metrics.WebApkUma;
 
 import java.io.File;
 import java.util.HashSet;
@@ -35,11 +37,16 @@
  * which each WebappActivity using a directory named either for its Webapp's ID in Document mode,
  * or the index of the WebappActivity if it is a subclass of the WebappManagedActivity class (which
  * are used in pre-L devices to allow multiple WebappActivities launching).
+ *
+ * Also records metrics about files in the "WebAPK update" directory.
  */
 public class WebappDirectoryManager {
     protected static final String WEBAPP_DIRECTORY_NAME = "WebappActivity";
     private static final String TAG = "WebappDirectoryManag";
 
+    /** Path of subdirectory within cache directory which contains data for pending updates. */
+    private static final String UPDATE_DIRECTORY_PATH = "webapk/update";
+
     /** Whether or not the class has already started trying to clean up obsolete directories. */
     private static final AtomicBoolean sMustCleanUpOldDirectories = new AtomicBoolean(true);
 
@@ -62,6 +69,8 @@
         mCleanupTask = new AsyncTask<Void, Void, Void>() {
             @Override
             protected final Void doInBackground(Void... params) {
+                recordNumberOfStaleWebApkUpdateRequestFiles();
+
                 Set<File> directoriesToDelete = new HashSet<File>();
                 directoriesToDelete.add(getWebappDirectory(context, currentWebappId));
 
@@ -136,6 +145,29 @@
         }
     }
 
+    /** Records to UMA the count of old "WebAPK update request" files. */
+    private void recordNumberOfStaleWebApkUpdateRequestFiles() {
+        File updateDirectory = getWebApkUpdateDirectory();
+        int count = 0;
+        File[] children = updateDirectory.listFiles();
+        if (children != null) {
+            for (File child : children) {
+                WebappDataStorage storage =
+                        WebappRegistry.getInstance().getWebappDataStorage(child.getName());
+                if (storage == null) {
+                    ++count;
+                    continue;
+                }
+
+                if (!storage.wasCheckForUpdatesDoneInLastMs(TimeUnit.DAYS.toMillis(1L))) {
+                    ++count;
+                }
+            }
+        }
+
+        WebApkUma.recordNumberOfStaleWebApkUpdateRequestFiles(count);
+    }
+
     /**
      * Returns the directory for a web app, creating it if necessary.
      * @param webappId ID for the web app.  Used as a subdirectory name.
@@ -163,6 +195,16 @@
         return context.getDir(WEBAPP_DIRECTORY_NAME, Context.MODE_PRIVATE);
     }
 
+    /** Returns the directory for "WebAPK update" files. Does not create the directory. */
+    static final File getWebApkUpdateDirectory() {
+        return new File(PathUtils.getCacheDirectory(), UPDATE_DIRECTORY_PATH);
+    }
+
+    /** Returns the path for the "WebAPK update" file for the given {@link WebappDataStorage}. */
+    static final File getWebApkUpdateFilePathForStorage(WebappDataStorage storage) {
+        return new File(getWebApkUpdateDirectory(), storage.getId());
+    }
+
     /** Returns a Set of Intents for all Chrome tasks currently known by the ActivityManager. */
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     protected Set<Intent> getBaseIntentsForAllTasks() {
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 3532fb62..d13c64c5 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -547,30 +547,6 @@
       <message name="IDS_SAFE_BROWSING_SUMMARY" desc="Summary for safe browsing.">
         Protect you and your device from dangerous sites
       </message>
-      <message name="IDS_NTP_SITES_EXPLORATION_CATEGORY_PERSONALIZED_TITLE" desc="In the Sites Explore UI, title of the Personalized category.">
-        Personalized
-      </message>
-      <message name="IDS_NTP_SITES_EXPLORATION_CATEGORY_NEWS_TITLE" desc="In the Sites Explore UI, title of the News category.">
-        News
-      </message>
-      <message name="IDS_NTP_SITES_EXPLORATION_CATEGORY_SOCIAL_TITLE" desc="In the Sites Explore UI, title of the Social category.">
-        Social
-      </message>
-      <message name="IDS_NTP_SITES_EXPLORATION_CATEGORY_ENTERTAINMENT_TITLE" desc="In the Sites Explore UI, title of the Entertainment category.">
-        Entertainment
-      </message>
-      <message name="IDS_NTP_SITES_EXPLORATION_CATEGORY_ECOMMERCE_TITLE" desc="In the Sites Explore UI, title of the Ecommerce category.">
-        E-commerce
-      </message>
-      <message name="IDS_NTP_SITES_EXPLORATION_CATEGORY_TOOLS_TITLE" desc="In the Sites Explore UI, title of the Tools category.">
-        Tools
-      </message>
-      <message name="IDS_NTP_SITES_EXPLORATION_CATEGORY_TRAVEL_TITLE" desc="In the Sites Explore UI, title of the Travel category.">
-        Travel
-      </message>
-      <message name="IDS_NTP_SITES_EXPLORATION_CATEGORY_OTHER_TITLE" desc="In the Sites Explore UI, title of the Unknown category.">
-        Other
-      </message>
       <message name="IDS_NETWORK_PREDICTIONS_TITLE" desc="Title of a setting in Chrome settings. Followed by a body that describes what pages are downloaded. If setting is turned on, Chrome will download certain pages to the user’s phone automatically for offline reading. “Download” is a verb, imperative. ">
         Automatically download pages
       </message>
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index ca6c1938..3a9f6d2 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1066,8 +1066,6 @@
   "java/src/org/chromium/chrome/browser/suggestions/ImageFetcher.java",
   "java/src/org/chromium/chrome/browser/suggestions/MostVisitedSites.java",
   "java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java",
-  "java/src/org/chromium/chrome/browser/suggestions/SiteExploreViewHolder.java",
-  "java/src/org/chromium/chrome/browser/suggestions/SiteExploreViewPager.java",
   "java/src/org/chromium/chrome/browser/suggestions/SiteSection.java",
   "java/src/org/chromium/chrome/browser/suggestions/SiteSectionViewHolder.java",
   "java/src/org/chromium/chrome/browser/suggestions/SiteSuggestion.java",
@@ -1087,7 +1085,6 @@
   "java/src/org/chromium/chrome/browser/suggestions/TileRenderer.java",
   "java/src/org/chromium/chrome/browser/suggestions/TileView.java",
   "java/src/org/chromium/chrome/browser/suggestions/NavigationRecorder.java",
-  "java/src/org/chromium/chrome/browser/suggestions/SiteExplorePageIndicatorView.java",
   "java/src/org/chromium/chrome/browser/suggestions/SuggestionsDependencyFactory.java",
   "java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegate.java",
   "java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java",
@@ -1924,6 +1921,7 @@
   "junit/src/org/chromium/chrome/browser/survey/ChromeHomeSurveyControllerTest.java",
   "junit/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreUnitTest.java",
   "junit/src/org/chromium/chrome/browser/tabstate/TabStateUnitTest.java",
+  "junit/src/org/chromium/chrome/browser/webapps/MockWebappDataStorageClockRule.java",
   "junit/src/org/chromium/chrome/browser/webapps/WebappDataStorageTest.java",
   "junit/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java",
   "junit/src/org/chromium/chrome/browser/webapps/WebappRegistryTest.java",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/MockWebappDataStorageClockRule.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/MockWebappDataStorageClockRule.java
new file mode 100644
index 0000000..7964b3a2
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/MockWebappDataStorageClockRule.java
@@ -0,0 +1,47 @@
+// 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.
+
+package org.chromium.chrome.browser.webapps;
+
+import org.junit.rules.ExternalResource;
+
+/** Test rule to set clock WebappDataStorage uses for getting the current time. */
+class MockWebappDataStorageClockRule extends ExternalResource {
+    private static class MockClock extends WebappDataStorage.Clock {
+        /**
+         * Not zero so that callers of {@link currentTimeMillis()} substracting from the current
+         * time get reasonable behavior.
+         */
+        private long mCurrentTime = 10000000000L;
+
+        public void advance(long millis) {
+            mCurrentTime += millis;
+        }
+
+        @Override
+        public long currentTimeMillis() {
+            return mCurrentTime;
+        }
+    }
+
+    private MockClock mClock = new MockClock();
+
+    public void advance(long millis) {
+        mClock.advance(millis);
+    }
+
+    public long currentTimeMillis() {
+        return mClock.currentTimeMillis();
+    }
+
+    @Override
+    protected void before() throws Throwable {
+        WebappDataStorage.setClockForTests(mClock);
+    }
+
+    @Override
+    protected void after() {
+        WebappDataStorage.setClockForTests(new WebappDataStorage.Clock());
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
index 1238c421..93e0f10 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
@@ -57,6 +57,9 @@
     @Rule
     public DisableHistogramsRule mDisableHistogramsRule = new DisableHistogramsRule();
 
+    @Rule
+    public MockWebappDataStorageClockRule mClockRule = new MockWebappDataStorageClockRule();
+
     private static final String WEBAPK_PACKAGE_NAME = "org.chromium.webapk.test_package";
     private static final String UNBOUND_WEBAPK_PACKAGE_NAME = "com.webapk.test_package";
 
@@ -79,21 +82,6 @@
     /** Different name than the one used in {@link defaultManifestData()}. */
     private static final String DIFFERENT_NAME = "Different Name";
 
-    /** {@link WebappDataStorage#Clock} subclass which enables time to be manually advanced. */
-    private static class MockClock extends WebappDataStorage.Clock {
-        // 0 has a special meaning: {@link WebappDataStorage#TIMESTAMP_INVALID}.
-        private long mTimeMillis = 1;
-
-        public void advance(long millis) {
-            mTimeMillis += millis;
-        }
-
-        @Override
-        public long currentTimeMillis() {
-            return mTimeMillis;
-        }
-    }
-
     /** Mock {@link WebApkUpdateDataFetcher}. */
     private static class TestWebApkUpdateDataFetcher extends WebApkUpdateDataFetcher {
         private boolean mStarted;
@@ -203,8 +191,6 @@
         public long backgroundColor;
     }
 
-    private MockClock mClock;
-
     private static String getWebApkId(String packageName) {
         return WebApkConstants.WEBAPK_ID_PREFIX + packageName;
     }
@@ -370,7 +356,7 @@
     private boolean checkUpdateNeededForFetchedManifest(
             ManifestData androidManifestData, ManifestData fetchedManifestData) {
         registerWebApk(WEBAPK_PACKAGE_NAME, androidManifestData, CURRENT_SHELL_APK_VERSION);
-        mClock.advance(WebappDataStorage.UPDATE_INTERVAL);
+        mClockRule.advance(WebappDataStorage.UPDATE_INTERVAL);
 
         TestWebApkUpdateManager updateManager =
                 new TestWebApkUpdateManager(getStorage(WEBAPK_PACKAGE_NAME));
@@ -388,8 +374,6 @@
         CommandLine.init(null);
 
         registerWebApk(WEBAPK_PACKAGE_NAME, defaultManifestData(), CURRENT_SHELL_APK_VERSION);
-        mClock = new MockClock();
-        WebappDataStorage.setClockForTests(mClock);
 
         WebappRegistry.getInstance().register(getWebApkId(WEBAPK_PACKAGE_NAME),
                 new WebappRegistry.FetchWebappDataStorageCallback() {
@@ -410,7 +394,7 @@
      */
     @Test
     public void testCheckOnNextLaunchIfClosePriorToFirstPageLoad() {
-        mClock.advance(WebappDataStorage.UPDATE_INTERVAL);
+        mClockRule.advance(WebappDataStorage.UPDATE_INTERVAL);
         {
             TestWebApkUpdateManager updateManager =
                     new TestWebApkUpdateManager(getStorage(WEBAPK_PACKAGE_NAME));
@@ -446,8 +430,8 @@
      */
     @Test
     public void testUpdateNotNeeded() {
-        long initialTime = mClock.currentTimeMillis();
-        mClock.advance(WebappDataStorage.UPDATE_INTERVAL);
+        long initialTime = mClockRule.currentTimeMillis();
+        mClockRule.advance(WebappDataStorage.UPDATE_INTERVAL);
 
         TestWebApkUpdateManager updateManager =
                 new TestWebApkUpdateManager(getStorage(WEBAPK_PACKAGE_NAME));
@@ -471,7 +455,7 @@
     public void testMarkUpdateAsSucceededIfUpdateNoLongerNeeded() {
         WebappDataStorage storage = getStorage(WEBAPK_PACKAGE_NAME);
         storage.updateDidLastWebApkUpdateRequestSucceed(false);
-        mClock.advance(WebappDataStorage.RETRY_UPDATE_DURATION);
+        mClockRule.advance(WebappDataStorage.RETRY_UPDATE_DURATION);
 
         TestWebApkUpdateManager updateManager =
                 new TestWebApkUpdateManager(getStorage(WEBAPK_PACKAGE_NAME));
@@ -482,7 +466,7 @@
 
         assertTrue(storage.getDidLastWebApkUpdateRequestSucceed());
         assertEquals(
-                mClock.currentTimeMillis(), storage.getLastWebApkUpdateRequestCompletionTime());
+                mClockRule.currentTimeMillis(), storage.getLastWebApkUpdateRequestCompletionTime());
     }
 
     /**
@@ -491,7 +475,7 @@
      */
     @Test
     public void testMarkUpdateAsFailedIfClosePriorToUpdateCompleting() {
-        mClock.advance(WebappDataStorage.UPDATE_INTERVAL);
+        mClockRule.advance(WebappDataStorage.UPDATE_INTERVAL);
 
         TestWebApkUpdateManager updateManager =
                 new TestWebApkUpdateManager(getStorage(WEBAPK_PACKAGE_NAME));
@@ -506,7 +490,7 @@
         WebappDataStorage storage = getStorage(WEBAPK_PACKAGE_NAME);
         assertFalse(storage.getDidLastWebApkUpdateRequestSucceed());
         assertEquals(
-                mClock.currentTimeMillis(), storage.getLastWebApkUpdateRequestCompletionTime());
+                mClockRule.currentTimeMillis(), storage.getLastWebApkUpdateRequestCompletionTime());
     }
 
     /**
@@ -515,7 +499,7 @@
      */
     @Test
     public void testPendingUpdateFileDeletedAfterUpdateCompletion() {
-        mClock.advance(WebappDataStorage.UPDATE_INTERVAL);
+        mClockRule.advance(WebappDataStorage.UPDATE_INTERVAL);
 
         WebappDataStorage storage = getStorage(WEBAPK_PACKAGE_NAME);
         TestWebApkUpdateManager updateManager = new TestWebApkUpdateManager(storage);
@@ -540,7 +524,7 @@
      */
     @Test
     public void testFileDeletedIfStoreWebApkUpdateRequestToFileFails() {
-        mClock.advance(WebappDataStorage.UPDATE_INTERVAL);
+        mClockRule.advance(WebappDataStorage.UPDATE_INTERVAL);
 
         WebappDataStorage storage = getStorage(WEBAPK_PACKAGE_NAME);
         TestWebApkUpdateManager updateManager = new TestWebApkUpdateManager(storage);
@@ -571,7 +555,7 @@
     @Test
     public void testShellApkOutOfDateNoWebManifest() {
         registerWebApk(WEBAPK_PACKAGE_NAME, defaultManifestData(), CURRENT_SHELL_APK_VERSION - 1);
-        mClock.advance(WebappDataStorage.UPDATE_INTERVAL);
+        mClockRule.advance(WebappDataStorage.UPDATE_INTERVAL);
 
         TestWebApkUpdateManager updateManager =
                 new TestWebApkUpdateManager(getStorage(WEBAPK_PACKAGE_NAME));
@@ -594,7 +578,7 @@
     @Test
     public void testShellApkOutOfDateStillHasWebManifest() {
         registerWebApk(WEBAPK_PACKAGE_NAME, defaultManifestData(), CURRENT_SHELL_APK_VERSION - 1);
-        mClock.advance(WebappDataStorage.UPDATE_INTERVAL);
+        mClockRule.advance(WebappDataStorage.UPDATE_INTERVAL);
 
         TestWebApkUpdateManager updateManager =
                 new TestWebApkUpdateManager(getStorage(WEBAPK_PACKAGE_NAME));
@@ -618,7 +602,7 @@
      */
     @Test
     public void testStartUrlRedirectsToPageWithUpdatedWebManifest() {
-        mClock.advance(WebappDataStorage.UPDATE_INTERVAL);
+        mClockRule.advance(WebappDataStorage.UPDATE_INTERVAL);
 
         TestWebApkUpdateManager updateManager =
                 new TestWebApkUpdateManager(getStorage(WEBAPK_PACKAGE_NAME));
@@ -654,7 +638,7 @@
      */
     @Test
     public void testStartUrlRedirectsToPageWithUnchangedWebManifest() {
-        mClock.advance(WebappDataStorage.UPDATE_INTERVAL);
+        mClockRule.advance(WebappDataStorage.UPDATE_INTERVAL);
 
         TestWebApkUpdateManager updateManager =
                 new TestWebApkUpdateManager(getStorage(WEBAPK_PACKAGE_NAME));
@@ -684,7 +668,7 @@
         ManifestData androidManifestData = defaultManifestData();
 
         registerWebApk(UNBOUND_WEBAPK_PACKAGE_NAME, androidManifestData, CURRENT_SHELL_APK_VERSION);
-        mClock.advance(WebappDataStorage.UPDATE_INTERVAL);
+        mClockRule.advance(WebappDataStorage.UPDATE_INTERVAL);
 
         TestWebApkUpdateManager updateManager =
                 new TestWebApkUpdateManager(getStorage(UNBOUND_WEBAPK_PACKAGE_NAME));
@@ -856,13 +840,13 @@
         assertTrue(updateManager.updateRequested());
         tryCompletingUpdate(updateManager, WebApkInstallResult.FAILURE);
 
-        mClock.advance(1);
+        mClockRule.advance(1);
         updateIfNeeded(updateManager);
         assertFalse(updateManager.updateCheckStarted());
 
         // A previous update request was made for the current ShellAPK version. A WebAPK update
         // should be requested after the regular delay.
-        mClock.advance(WebappDataStorage.UPDATE_INTERVAL - 1);
+        mClockRule.advance(WebappDataStorage.UPDATE_INTERVAL - 1);
         updateIfNeeded(updateManager);
         assertTrue(updateManager.updateCheckStarted());
         onGotManifestData(updateManager, defaultManifestData());
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappDataStorageTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappDataStorageTest.java
index b719405..164a94a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappDataStorageTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappDataStorageTest.java
@@ -15,6 +15,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RuntimeEnvironment;
@@ -25,7 +26,6 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.blink_public.platform.WebDisplayMode;
 import org.chromium.chrome.browser.ShortcutHelper;
-import org.chromium.chrome.browser.webapps.WebappDataStorage.Clock;
 import org.chromium.testing.local.BackgroundShadowAsyncTask;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 
@@ -38,6 +38,8 @@
 @RunWith(LocalRobolectricTestRunner.class)
 @Config(manifest = Config.NONE, shadows = {BackgroundShadowAsyncTask.class})
 public class WebappDataStorageTest {
+    @Rule
+    public MockWebappDataStorageClockRule mClockRule = new MockWebappDataStorageClockRule();
 
     private SharedPreferences mSharedPreferences;
     private boolean mCallbackCalled;
@@ -56,27 +58,6 @@
         }
     }
 
-    private static class TestClock extends WebappDataStorage.Clock {
-        private long mCurrentTime;
-
-        public TestClock(long currentTime) {
-            updateTime(currentTime);
-        }
-
-        public void advance(long millis) {
-            mCurrentTime += millis;
-        }
-
-        public void updateTime(long currentTime) {
-            mCurrentTime = currentTime;
-        }
-
-        @Override
-        public long currentTimeMillis() {
-            return mCurrentTime;
-        }
-    }
-
     @Before
     public void setUp() throws Exception {
         ContextUtils.initApplicationContextForTests(RuntimeEnvironment.application);
@@ -92,7 +73,6 @@
     @After
     public void tearDown() {
         mSharedPreferences.edit().clear().apply();
-        WebappDataStorage.setClockForTests(new Clock());
     }
 
     @Test
@@ -181,9 +161,6 @@
     @Test
     @Feature({"Webapp"})
     public void testWasLaunchedRecently() throws Exception {
-        final TestClock clock = new TestClock(System.currentTimeMillis());
-        WebappDataStorage.setClockForTests(clock);
-
         // Opening a data storage doesn't count as a launch.
         WebappDataStorage storage = WebappDataStorage.open("test");
         assertTrue(!storage.wasUsedRecently());
@@ -320,14 +297,13 @@
     public void testCheckUpdateMoreFrequentlyIfUpdateFails() {
         assertTrue(WebappDataStorage.UPDATE_INTERVAL > WebappDataStorage.RETRY_UPDATE_DURATION);
 
-        final TestClock clock = new TestClock(System.currentTimeMillis());
-        WebappDataStorage storage = getStorage(clock);
+        WebappDataStorage storage = getStorage();
 
         storage.updateTimeOfLastWebApkUpdateRequestCompletion();
         storage.updateDidLastWebApkUpdateRequestSucceed(true);
 
         assertFalse(storage.shouldCheckForUpdate());
-        clock.advance(WebappDataStorage.RETRY_UPDATE_DURATION);
+        mClockRule.advance(WebappDataStorage.RETRY_UPDATE_DURATION);
         assertFalse(storage.shouldCheckForUpdate());
 
         // Advance all of the time stamps.
@@ -336,7 +312,7 @@
         storage.updateDidLastWebApkUpdateRequestSucceed(false);
 
         assertFalse(storage.shouldCheckForUpdate());
-        clock.advance(WebappDataStorage.RETRY_UPDATE_DURATION);
+        mClockRule.advance(WebappDataStorage.RETRY_UPDATE_DURATION);
         assertTrue(storage.shouldCheckForUpdate());
 
         // Verifies that {@link WebappDataStorage#shouldCheckForUpdate()} returns true because the
@@ -354,13 +330,13 @@
     public void testRegularCheckIntervalIfNoPriorWebApkUpdate() {
         assertTrue(WebappDataStorage.UPDATE_INTERVAL > WebappDataStorage.RETRY_UPDATE_DURATION);
 
-        final TestClock clock = new TestClock(System.currentTimeMillis());
-        WebappDataStorage storage = getStorage(clock);
+        WebappDataStorage storage = getStorage();
 
         assertFalse(storage.shouldCheckForUpdate());
-        clock.advance(WebappDataStorage.RETRY_UPDATE_DURATION);
+        mClockRule.advance(WebappDataStorage.RETRY_UPDATE_DURATION);
         assertFalse(storage.shouldCheckForUpdate());
-        clock.advance(WebappDataStorage.UPDATE_INTERVAL - WebappDataStorage.RETRY_UPDATE_DURATION);
+        mClockRule.advance(
+                WebappDataStorage.UPDATE_INTERVAL - WebappDataStorage.RETRY_UPDATE_DURATION);
         assertTrue(storage.shouldCheckForUpdate());
     }
 
@@ -373,20 +349,18 @@
     public void testRelaxedUpdates() {
         assertTrue(WebappDataStorage.RELAXED_UPDATE_INTERVAL > WebappDataStorage.UPDATE_INTERVAL);
 
-        final TestClock clock = new TestClock(System.currentTimeMillis());
-        WebappDataStorage storage = getStorage(clock);
+        WebappDataStorage storage = getStorage();
 
         storage.setRelaxedUpdates(true);
 
-        clock.advance(WebappDataStorage.UPDATE_INTERVAL);
+        mClockRule.advance(WebappDataStorage.UPDATE_INTERVAL);
         assertFalse(storage.shouldCheckForUpdate());
-        clock.advance(
+        mClockRule.advance(
                 WebappDataStorage.RELAXED_UPDATE_INTERVAL - WebappDataStorage.UPDATE_INTERVAL);
         assertTrue(storage.shouldCheckForUpdate());
     }
 
-    private WebappDataStorage getStorage(TestClock clock) {
-        WebappDataStorage.setClockForTests(clock);
+    private WebappDataStorage getStorage() {
         WebappDataStorage storage = WebappDataStorage.open("test");
 
         // Done when WebAPK is registered in {@link WebApkActivity}.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java
index 26b9ff4..6b5b49d 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java
@@ -12,15 +12,20 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
 import org.robolectric.shadows.ShadowLooper;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.FileUtils;
+import org.chromium.base.PathUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.metrics.test.ShadowRecordHistogram;
 import org.chromium.base.test.util.Feature;
 import org.chromium.testing.local.CustomShadowAsyncTask;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
@@ -29,13 +34,18 @@
 import java.io.File;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Tests that directories for WebappActivities are managed correctly.
  */
 @RunWith(LocalRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, shadows = {CustomShadowAsyncTask.class})
+@Config(manifest = Config.NONE,
+        shadows = {CustomShadowAsyncTask.class, ShadowRecordHistogram.class})
 public class WebappDirectoryManagerTest {
+    @Rule
+    public MockWebappDataStorageClockRule mClockRule = new MockWebappDataStorageClockRule();
+
     private static final String WEBAPP_ID_1 = "webapp_1";
     private static final String WEBAPP_ID_2 = "webapp_2";
     private static final String WEBAPP_ID_3 = "webapp_3";
@@ -52,32 +62,47 @@
         }
     }
 
+    /** Deletes directory and all of its children. Recreates empty directory in its place. */
+    private void deleteDirectoryAndRecreate(File f) {
+        FileUtils.recursivelyDeleteFile(f);
+        Assert.assertTrue(f.mkdirs());
+    }
+
     private Context mContext;
     private TestWebappDirectoryManager mWebappDirectoryManager;
 
     @Before
     public void setUp() throws Exception {
-        ThreadUtils.setThreadAssertsDisabledForTesting(true);
-        RecordHistogram.setDisabledForTests(true);
         mContext = RuntimeEnvironment.application;
+        ContextUtils.initApplicationContextForTests(mContext);
+        ThreadUtils.setThreadAssertsDisabledForTesting(true);
+        PathUtils.setPrivateDataDirectorySuffix("chrome");
         mWebappDirectoryManager = new TestWebappDirectoryManager();
         mWebappDirectoryManager.resetForTesting();
 
         // Set up directories.
-        File baseDirectory = mContext.getDataDir();
-        FileUtils.recursivelyDeleteFile(baseDirectory);
-        Assert.assertTrue(baseDirectory.mkdirs());
+        deleteDirectoryAndRecreate(mContext.getDataDir());
         FileUtils.recursivelyDeleteFile(mWebappDirectoryManager.getBaseWebappDirectory(mContext));
+        deleteDirectoryAndRecreate(mContext.getCodeCacheDir());
     }
 
     @After
     public void tearDown() throws Exception {
         FileUtils.recursivelyDeleteFile(mContext.getDataDir());
+        FileUtils.recursivelyDeleteFile(mContext.getCodeCacheDir());
         FileUtils.recursivelyDeleteFile(mWebappDirectoryManager.getBaseWebappDirectory(mContext));
-        RecordHistogram.setDisabledForTests(false);
         ThreadUtils.setThreadAssertsDisabledForTesting(false);
     }
 
+    public void registerWebapp(String webappId) {
+        WebappRegistry.getInstance().register(
+                webappId, new WebappRegistry.FetchWebappDataStorageCallback() {
+                    @Override
+                    public void onWebappDataStorageRetrieved(WebappDataStorage storage) {}
+                });
+        ShadowApplication.getInstance().runBackgroundTasks();
+    }
+
     @Test
     @Feature({"Webapps"})
     public void testDeletesOwnDirectory() throws Exception {
@@ -181,6 +206,68 @@
         Assert.assertTrue(nonWebappDirectory.exists());
     }
 
+    /**
+     * Test that WebApk.Update.NumStaleUpdateRequestFiles counts "update request" files for WebAPKs
+     * which have been uninstalled.
+     */
+    @Test
+    @Feature({"Webapps"})
+    public void testCountsUpdateFilesForUninstalledWebApks() throws Exception {
+        File directory1 = new File(WebappDirectoryManager.getWebApkUpdateDirectory(), WEBAPK_ID_1);
+        directory1.mkdirs();
+        File directory2 = new File(WebappDirectoryManager.getWebApkUpdateDirectory(), WEBAPK_ID_2);
+        directory2.mkdirs();
+
+        // No entry for WEBAPK_ID_1 and WEBAPK_ID_2 in WebappRegistry because the WebAPKs have been
+        // uninstalled.
+
+        runCleanup();
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        "WebApk.Update.NumStaleUpdateRequestFiles", 2));
+    }
+
+    /**
+     * Test that WebApk.Update.NumStaleUpdateRequestFiles counts "update request" files for WebAPKs
+     * for which an update was requested a long time ago.
+     */
+    @Test
+    @Feature({"Webapps"})
+    public void testCountsOldWebApkUpdateFiles() throws Exception {
+        File directory = new File(mWebappDirectoryManager.getWebApkUpdateDirectory(), WEBAPK_ID_1);
+        directory.mkdirs();
+        registerWebapp(WEBAPK_ID_1);
+        WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataStorage(WEBAPK_ID_1);
+        storage.updateTimeOfLastCheckForUpdatedWebManifest();
+        mClockRule.advance(TimeUnit.DAYS.toMillis(30));
+
+        runCleanup();
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        "WebApk.Update.NumStaleUpdateRequestFiles", 1));
+    }
+
+    /**
+     * Test that WebApk.Update.NumStaleUpdateRequestFiles does not count "update request" files for
+     * WebAPKs for which an update was recently requested. There is a 1-23 hour delay between
+     * a WebAPK update being scheduled to the WebAPK being updated.
+     */
+    @Test
+    @Feature({"Webapps"})
+    public void testDoesNotCountFilesForNewlyScheduledUpdates() throws Exception {
+        File directory = new File(mWebappDirectoryManager.getWebApkUpdateDirectory(), WEBAPK_ID_1);
+        directory.mkdirs();
+        registerWebapp(WEBAPK_ID_1);
+        WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataStorage(WEBAPK_ID_1);
+        storage.updateTimeOfLastCheckForUpdatedWebManifest();
+        mClockRule.advance(1);
+
+        runCleanup();
+        Assert.assertEquals(0,
+                RecordHistogram.getHistogramValueCountForTesting(
+                        "WebApk.Update.NumStaleUpdateRequestFiles", 1));
+    }
+
     private void runCleanup() throws Exception {
         mWebappDirectoryManager.cleanUpDirectories(mContext, WEBAPP_ID_1);
         ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
diff --git a/chrome/app/md_extensions_strings.grdp b/chrome/app/md_extensions_strings.grdp
index 995be14d..19c08e1 100644
--- a/chrome/app/md_extensions_strings.grdp
+++ b/chrome/app/md_extensions_strings.grdp
@@ -199,6 +199,41 @@
   <message name="IDS_MD_EXTENSIONS_TYPE_A_SHORTCUT" desc="The prompt to the user to enter a keyboard shortcut in order to assign it to an extension.">
     Type a shortcut
   </message>
+<if expr="is_macosx">
+  <message name="IDS_MD_EXTENSIONS_SHORTCUT_INSTRUCTIONS" desc="Instructions explaining that shortcuts must start with either the Control, Alt, or Command key.">
+    Shortcuts must start with Ctrl, Alt, or Command
+  </message>
+  <message name="IDS_MD_EXTENSIONS_INCLUDE_START_MODIFIER" desc="Error message explaining that shortcuts must start with either the Control, Alt, or Command key.">
+    Include Ctrl, Alt, or Command
+  </message>
+</if>
+<if expr="chromeos">
+  <message name="IDS_MD_EXTENSIONS_SHORTCUT_INSTRUCTIONS" desc="Instructions explaining that shortcuts must start with either the Control, Alt, or Search key.">
+    Shortcuts must start with Ctrl, Alt, or Search
+  </message>
+  <message name="IDS_MD_EXTENSIONS_INCLUDE_START_MODIFIER" desc="Error message explaining that shortcuts must start with either the Control, Alt, or Search key.">
+    Include Ctrl, Alt, or Search
+  </message>
+</if>
+<if expr="is_macosx or chromeos">
+  <message name="IDS_MD_EXTENSIONS_TOO_MANY_MODIFIERS" desc="Error message explaining not to use so many modifiers in a shortcut.">
+    Invalid combination
+  </message>
+</if>
+<if expr="not is_macosx and not chromeos">
+  <message name="IDS_MD_EXTENSIONS_SHORTCUT_INSTRUCTIONS" desc="Instructions explaining that shortcuts must start with either the Control key or the Alt key.">
+    Shortcuts must start with either Ctrl or Alt
+  </message>
+  <message name="IDS_MD_EXTENSIONS_INCLUDE_START_MODIFIER" desc="Error message explaining that shortcuts must start with either the Control key or the Alt key.">
+    Include either Ctrl or Alt
+  </message>
+  <message name="IDS_MD_EXTENSIONS_TOO_MANY_MODIFIERS" desc="Error message explaining not to use both Ctrl and Alt in a shortcut.">
+    Either, not both Ctrl and Alt
+  </message>
+</if>
+<message name="IDS_MD_EXTENSIONS_NEED_CHARACTER" desc="Error message explaining that a shortcut needs a character. This is only shown if a valid modifier is already entered.">
+  Need a character
+</message>
 <if expr="chromeos">
   <!-- Extensions Kiosk apps -->
   <message name="IDS_MD_EXTENSIONS_MANAGE_KIOSK_APP" desc="Label of the button to bring up kiosk management overlay on chrome extensions page.">
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc b/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc
index 3317fc2..784385e 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc
@@ -398,15 +398,9 @@
     return;  // the |url| has been handled.
   }
 
-  // Otherwise, retrieve icons of the activities. First, swap |handler| elements
-  // to ensure Chrome is visible in the UI by default. Since this function is
-  // for handling external protocols, Chrome is rarely in the list, but if the
-  // |url| is intent: with fallback or geo:, for example, it may be.
-  std::pair<size_t, size_t> indices;
-  if (ArcNavigationThrottle::IsSwapElementsNeeded(handlers, &indices))
-    std::swap(handlers[indices.first], handlers[indices.second]);
-
-  // Then request the icons.
+  // Otherwise, retrieve icons of the activities. Since this function is for
+  // handling external protocols, Chrome is rarely in the list, but if the |url|
+  // is intent: with fallback or geo:, for example, it may be.
   std::vector<ArcIntentHelperBridge::ActivityName> activities;
   for (const auto& handler : handlers) {
     activities.emplace_back(handler->package_name, handler->activity_name);
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.cc b/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.cc
index 288169a3..5832439 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.cc
@@ -432,26 +432,6 @@
 }
 
 // static
-bool ArcNavigationThrottle::IsSwapElementsNeeded(
-    const std::vector<mojom::IntentHandlerInfoPtr>& handlers,
-    std::pair<size_t, size_t>* out_indices) {
-  size_t chrome_app_index = 0;
-  for (size_t i = 0; i < handlers.size(); ++i) {
-    if (ArcIntentHelperBridge::IsIntentHelperPackage(
-            handlers[i]->package_name)) {
-      chrome_app_index = i;
-      break;
-    }
-  }
-  if (chrome_app_index < ArcNavigationThrottle::kMaxAppResults)
-    return false;
-
-  *out_indices = std::make_pair(ArcNavigationThrottle::kMaxAppResults - 1,
-                                chrome_app_index);
-  return true;
-}
-
-// static
 void ArcNavigationThrottle::AsyncShowIntentPickerBubble(const Browser* browser,
                                                         const GURL& url) {
   arc::ArcServiceManager* arc_service_manager = arc::ArcServiceManager::Get();
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.h b/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.h
index c983a88..c1b4608 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.h
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.h
@@ -111,14 +111,6 @@
   static bool IsAppAvailable(
       const std::vector<mojom::IntentHandlerInfoPtr>& handlers);
 
-  // Swaps Chrome app with any app in row |kMaxAppResults-1| iff its index is
-  // bigger, thus ensuring the user can always see Chrome without scrolling.
-  // When swap is needed, fills |out_indices| and returns true. If |handlers|
-  // do not have Chrome, returns false.
-  static bool IsSwapElementsNeeded(
-      const std::vector<mojom::IntentHandlerInfoPtr>& handlers,
-      std::pair<size_t, size_t>* out_indices);
-
   static bool IsAppAvailableForTesting(
       const std::vector<mojom::IntentHandlerInfoPtr>& handlers);
   static size_t FindPreferredAppForTesting(
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle_unittest.cc b/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle_unittest.cc
index ac6fe71..f216b058 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle_unittest.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle_unittest.cc
@@ -229,55 +229,4 @@
                 ArcNavigationThrottle::CloseReason::PREFERRED_ACTIVITY_FOUND));
 }
 
-TEST(ArcNavigationThrottleTest, TestIsSwapElementsNeeded) {
-  std::pair<size_t, size_t> indices;
-  for (size_t i = 1; i <= ArcNavigationThrottle::kMaxAppResults; ++i) {
-    // When Chrome is the first element, swap is unnecessary.
-    std::vector<mojom::IntentHandlerInfoPtr> handlers = CreateArray(i, 0);
-    EXPECT_FALSE(
-        ArcNavigationThrottle::IsSwapElementsNeeded(handlers, &indices))
-        << i;
-
-    // When Chrome is within the first |kMaxAppResults| elements, swap is
-    // unnecessary.
-    handlers = CreateArray(i, i - 1);
-    EXPECT_FALSE(
-        ArcNavigationThrottle::IsSwapElementsNeeded(handlers, &indices))
-        << i;
-  }
-
-  for (size_t i = ArcNavigationThrottle::kMaxAppResults + 1;
-       i < ArcNavigationThrottle::kMaxAppResults * 2; ++i) {
-    // When Chrome is within the first |kMaxAppResults| elements, swap is
-    // unnecessary.
-    std::vector<mojom::IntentHandlerInfoPtr> handlers = CreateArray(i, 0);
-    EXPECT_FALSE(
-        ArcNavigationThrottle::IsSwapElementsNeeded(handlers, &indices))
-        << i;
-
-    // When Chrome is the |kMaxAppResults|-th element, swap is unnecessary.
-    handlers = CreateArray(i, ArcNavigationThrottle::kMaxAppResults - 1);
-    EXPECT_FALSE(
-        ArcNavigationThrottle::IsSwapElementsNeeded(handlers, &indices))
-        << i;
-
-    // When Chrome is not within the first |kMaxAppResults| elements, swap is
-    // necessary.
-    handlers = CreateArray(i, i - 1);
-    indices.first = indices.second = 0;
-    EXPECT_TRUE(ArcNavigationThrottle::IsSwapElementsNeeded(handlers, &indices))
-        << i;
-    EXPECT_EQ(ArcNavigationThrottle::kMaxAppResults - 1u, indices.first) << i;
-    EXPECT_EQ(i - 1, indices.second) << i;
-  }
-
-  for (size_t i = 0; i <= ArcNavigationThrottle::kMaxAppResults * 2; ++i) {
-    // When Chrome does not exist in |handlers|, swap is unnecessary.
-    std::vector<mojom::IntentHandlerInfoPtr> handlers = CreateArray(i, i);
-    EXPECT_FALSE(
-        ArcNavigationThrottle::IsSwapElementsNeeded(handlers, &indices))
-        << i;
-  }
-}
-
 }  // namespace arc
diff --git a/chrome/browser/media/webrtc/webrtc_text_log_handler.cc b/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
index eacf2ee6..e30c4fd0 100644
--- a/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
+++ b/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
@@ -46,6 +46,7 @@
 using content::BrowserThread;
 
 namespace {
+
 std::string FormatMetaDataAsLogMessage(const MetaDataMap& meta_data) {
   std::string message;
   for (auto& kv : meta_data) {
@@ -90,6 +91,14 @@
   return address.ToString();
 #endif
 }
+
+net::NetworkInterfaceList GetNetworkInterfaceList() {
+  net::NetworkInterfaceList network_list;
+  net::GetNetworkList(&network_list,
+                      net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES);
+  return network_list;
+}
+
 }  // namespace
 
 WebRtcLogBuffer::WebRtcLogBuffer()
@@ -197,9 +206,10 @@
   if (!meta_data_)
     meta_data_.reset(new MetaDataMap());
 
-  base::PostTaskWithTraits(
+  base::PostTaskWithTraitsAndReplyWithResult(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
-      base::BindOnce(&WebRtcTextLogHandler::LogInitialInfoOnFileThread, this,
+      base::BindOnce(&GetNetworkInterfaceList),
+      base::BindOnce(&WebRtcTextLogHandler::LogInitialInfoOnIOThread, this,
                      callback));
   return true;
 }
@@ -377,21 +387,9 @@
       base::BindOnce(callback, success, error_message_with_state));
 }
 
-void WebRtcTextLogHandler::LogInitialInfoOnFileThread(
-    const GenericDoneCallback& callback) {
-  net::NetworkInterfaceList network_list;
-  net::GetNetworkList(&network_list,
-                      net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES);
-
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::BindOnce(&WebRtcTextLogHandler::LogInitialInfoOnIOThread, this,
-                     network_list, callback));
-}
-
 void WebRtcTextLogHandler::LogInitialInfoOnIOThread(
-    const net::NetworkInterfaceList& network_list,
-    const GenericDoneCallback& callback) {
+    const GenericDoneCallback& callback,
+    const net::NetworkInterfaceList& network_list) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (logging_state_ != STARTING) {
     FireGenericDoneCallback(callback, false, "Logging cancelled.");
diff --git a/chrome/browser/media/webrtc/webrtc_text_log_handler.h b/chrome/browser/media/webrtc/webrtc_text_log_handler.h
index f7ff559..6969780 100644
--- a/chrome/browser/media/webrtc/webrtc_text_log_handler.h
+++ b/chrome/browser/media/webrtc/webrtc_text_log_handler.h
@@ -138,9 +138,8 @@
 
   void LogToCircularBuffer(const std::string& message);
 
-  void LogInitialInfoOnFileThread(const GenericDoneCallback& callback);
-  void LogInitialInfoOnIOThread(const net::NetworkInterfaceList& network_list,
-                                const GenericDoneCallback& callback);
+  void LogInitialInfoOnIOThread(const GenericDoneCallback& callback,
+                                const net::NetworkInterfaceList& network_list);
   void EnableBrowserProcessLoggingOnUIThread();
   void DisableBrowserProcessLoggingOnUIThread();
 
diff --git a/chrome/browser/resources/md_extensions/keyboard_shortcuts.html b/chrome/browser/resources/md_extensions/keyboard_shortcuts.html
index 1e38e2a..077a9f2 100644
--- a/chrome/browser/resources/md_extensions/keyboard_shortcuts.html
+++ b/chrome/browser/resources/md_extensions/keyboard_shortcuts.html
@@ -14,26 +14,36 @@
   <template>
     <style include="md-select cr-shared-style">
       :host {
+        --card-max-width: 928px;
+        --card-min-width: 600px;
         height: 100%;
       }
 
+      #instructions,
+      .shortcut-card {
+        margin: 0 auto 16px auto;
+        max-width: var(--card-max-width);
+        min-width: var(--card-min-width);
+        width: 90%;
+      }
+
+      #instructions {
+        @apply --cr-title-text;
+      }
+
+      .shortcut-card {
+        @apply --cr-primary-text;
+        @apply --shadow-elevation-2dp;
+        background-color: white;
+        padding-bottom: 8px;
+      }
+
       #container {
         height: 100%;
         overflow: overlay;
         padding-top: 24px;
       }
 
-      .shortcut-card {
-        @apply(--cr-primary-text);
-        @apply(--shadow-elevation-2dp);
-        background-color: white;
-        margin: 0 auto 16px auto;
-        max-width: 928px;
-        min-width: 600px;
-        padding-bottom: 8px;
-        width: 90%;
-      }
-
       .command-entry {
         align-items: center;
         display: flex;
@@ -65,7 +75,7 @@
         display: flex;
         margin-bottom: 9px;
         padding: 16px var(--cr-section-padding);
-        @apply(--cr-title-text);
+        @apply --cr-title-text;
       }
 
       .icon {
@@ -82,6 +92,7 @@
       }
     </style>
     <div id="container">
+      <div id="instructions">$i18n{shortcutInstructions}</div>
       <template is="dom-repeat" items="[[calculateShownItems_(items.*)]]">
         <div class="shortcut-card">
           <div class="card-title">
diff --git a/chrome/browser/resources/md_extensions/shortcut_input.html b/chrome/browser/resources/md_extensions/shortcut_input.html
index 4fce312..ad5c9bb 100644
--- a/chrome/browser/resources/md_extensions/shortcut_input.html
+++ b/chrome/browser/resources/md_extensions/shortcut_input.html
@@ -25,7 +25,7 @@
           margin-bottom: 0px;
           margin-top: 2px;  /* Offset underline spacing. */
           padding: 0;
-          @apply(--cr-primary-text);
+          @apply --cr-primary-text;
         };
       }
 
@@ -38,8 +38,12 @@
     </style>
     <div id="main">
       <paper-input id="input" placeholder="$i18n{shortcutTypeAShortcut}"
-        value="[[computeText_(capturing_, shortcut, pendingShortcut_)]]"
-        no-label-float>
+          error-message="[[getErrorString_(error_,
+              '$i18nPolymer{shortcutIncludeStartModifier}',
+              '$i18nPolymer{shortcutTooManyModifiers}',
+              '$i18nPolymer{shortcutNeedCharacter}')]]"
+          value="[[computeText_(capturing_, shortcut, pendingShortcut_)]]"
+          no-label-float>
       </paper-input>
       <button id="clear" is="paper-icon-button-light"
           class="icon-clear no-overlap" on-tap="onClearTap_"
diff --git a/chrome/browser/resources/md_extensions/shortcut_input.js b/chrome/browser/resources/md_extensions/shortcut_input.js
index 6622e67..d70ebd02 100644
--- a/chrome/browser/resources/md_extensions/shortcut_input.js
+++ b/chrome/browser/resources/md_extensions/shortcut_input.js
@@ -5,6 +5,14 @@
 cr.define('extensions', function() {
   'use strict';
 
+  /** @enum {number} */
+  const ShortcutError = {
+    NO_ERROR: 0,
+    INCLUDE_START_MODIFIER: 1,
+    TOO_MANY_MODIFIERS: 2,
+    NEED_CHARACTER: 3,
+  };
+
   // The UI to display and manage keyboard shortcuts set for extension commands.
   const ShortcutInput = Polymer({
     is: 'extensions-shortcut-input',
@@ -36,6 +44,12 @@
         value: false,
       },
 
+      /** @private {!ShortcutError} */
+      error_: {
+        type: Number,
+        value: 0,
+      },
+
       /** @private */
       pendingShortcut_: {
         type: String,
@@ -67,7 +81,9 @@
         return;
       this.pendingShortcut_ = '';
       this.capturing_ = false;
-      this.$['input'].blur();
+      const input = this.$.input;
+      input.blur();
+      input.invalid = false;
       this.delegate.setShortcutHandlingSuspended(false);
     },
 
@@ -110,6 +126,23 @@
     },
 
     /**
+     * @param {!ShortcutError} error
+     * @param {string} includeStartModifier
+     * @param {string} tooManyModifiers
+     * @param {string} needCharacter
+     * @return {string} UI string.
+     * @private
+     */
+    getErrorString_: function(
+        error, includeStartModifier, tooManyModifiers, needCharacter) {
+      if (error == ShortcutError.TOO_MANY_MODIFIERS)
+        return tooManyModifiers;
+      if (error == ShortcutError.NEED_CHARACTER)
+        return needCharacter;
+      return includeStartModifier;
+    },
+
+    /**
      * @param {!KeyboardEvent} e
      * @private
      */
@@ -123,17 +156,27 @@
       // We don't allow both Ctrl and Alt in the same keybinding.
       // TODO(devlin): This really should go in extensions.hasValidModifiers,
       // but that requires updating the existing page as well.
-      if ((e.ctrlKey && e.altKey) || !extensions.hasValidModifiers(e)) {
-        this.pendingShortcut_ = 'invalid';
+      if (e.ctrlKey && e.altKey) {
+        this.error_ = ShortcutError.TOO_MANY_MODIFIERS;
+        this.$.input.invalid = true;
         return;
       }
-
-      this.pendingShortcut_ = extensions.keystrokeToString(e);
-
-      if (extensions.isValidKeyCode(e.keyCode)) {
-        this.commitPending_();
-        this.endCapture_();
+      if (!extensions.hasValidModifiers(e)) {
+        this.pendingShortcut_ = '';
+        this.error_ = ShortcutError.INCLUDE_START_MODIFIER;
+        this.$.input.invalid = true;
+        return;
       }
+      this.pendingShortcut_ = extensions.keystrokeToString(e);
+      if (!extensions.isValidKeyCode(e.keyCode)) {
+        this.error_ = ShortcutError.NEED_CHARACTER;
+        this.$.input.invalid = true;
+        return;
+      }
+      this.$.input.invalid = false;
+
+      this.commitPending_();
+      this.endCapture_();
     },
 
     /** @private */
diff --git a/chrome/browser/resources/net_internals/events_view.js b/chrome/browser/resources/net_internals/events_view.js
index 679fdbc..60cd5a8 100644
--- a/chrome/browser/resources/net_internals/events_view.js
+++ b/chrome/browser/resources/net_internals/events_view.js
@@ -144,13 +144,6 @@
     },
 
     /**
-     * Updates text in the details view when privacy stripping is toggled.
-     */
-    onPrivacyStrippingChanged: function() {
-      this.invalidateDetailsView_();
-    },
-
-    /**
      * Updates text in the details view when time display mode is toggled.
      */
     onUseRelativeTimesChanged: function() {
diff --git a/chrome/browser/resources/net_internals/log_util.js b/chrome/browser/resources/net_internals/log_util.js
index f690352a..b616f2e 100644
--- a/chrome/browser/resources/net_internals/log_util.js
+++ b/chrome/browser/resources/net_internals/log_util.js
@@ -9,8 +9,7 @@
    * Creates a new log dump.  |events| is a list of all events, |polledData| is
    * an object containing the results of each poll, |tabData| is an object
    * containing data for individual tabs, |date| is the time the dump was
-   * created, as a formatted string, and |privacyStripping| is whether or not
-   * private information should be removed from the generated dump.
+   * created, as a formatted string.
    *
    * Returns the new log dump as an object.  Resulting object may have a null
    * |numericDate|.
@@ -32,11 +31,7 @@
    * tabs not present on the OS the log is from.
    */
   function createLogDump(
-      userComments, constants, events, polledData, tabData, numericDate,
-      privacyStripping) {
-    if (privacyStripping)
-      events = events.map(stripPrivacyInfo);
-
+      userComments, constants, events, polledData, tabData, numericDate) {
     var logDump = {
       'userComments': userComments,
       'constants': constants,
@@ -57,12 +52,11 @@
    * Creates a full log dump using |polledData| and the return value of each
    * tab's saveState function and passes it to |callback|.
    */
-  function onUpdateAllCompleted(
-      userComments, callback, privacyStripping, polledData) {
+  function onUpdateAllCompleted(userComments, callback, polledData) {
     var logDump = createLogDump(
         userComments, Constants,
         EventsTracker.getInstance().getAllCapturedEvents(), polledData,
-        getTabData_(), timeutil.getCurrentTime(), privacyStripping);
+        getTabData_(), timeutil.getCurrentTime());
     callback(JSON.stringify(logDump));
   }
 
@@ -71,9 +65,9 @@
    * loaded.  Once a log dump has been created, |callback| is passed the dumped
    * text as a string.
    */
-  function createLogDumpAsync(userComments, callback, privacyStripping) {
-    g_browser.updateAllInfo(onUpdateAllCompleted.bind(
-        null, userComments, callback, privacyStripping));
+  function createLogDumpAsync(userComments, callback) {
+    g_browser.updateAllInfo(
+        onUpdateAllCompleted.bind(null, userComments, callback));
   }
 
   /**
diff --git a/chrome/browser/resources/net_internals/log_view_painter.js b/chrome/browser/resources/net_internals/log_view_painter.js
index edb063be..205fcfa 100644
--- a/chrome/browser/resources/net_internals/log_view_painter.js
+++ b/chrome/browser/resources/net_internals/log_view_painter.js
@@ -6,7 +6,6 @@
 
 var createLogEntryTablePrinter;
 var proxySettingsToString;
-var stripPrivacyInfo;
 
 // Start of anonymous namespace.
 (function() {
@@ -22,8 +21,7 @@
  * Creates a TablePrinter for use by the above two functions.  baseTime is
  * the time relative to which other times are displayed.
  */
-createLogEntryTablePrinter = function(
-    logEntries, privacyStripping, baseTime, logCreationTime) {
+createLogEntryTablePrinter = function(logEntries, baseTime, logCreationTime) {
   var entries = LogGroupEntry.createArrayFrom(logEntries);
   var tablePrinter = new TablePrinter();
   var parameterOutputter = new ParameterOutputter(tablePrinter);
@@ -66,7 +64,7 @@
     if (typeof entry.orig.params == 'object') {
       // Those 5 skipped cells are: two for "t=", and three for "st=".
       tablePrinter.setNewRowCellIndent(5 + entry.getDepth());
-      writeParameters(entry.orig, privacyStripping, parameterOutputter);
+      writeParameters(entry.orig, parameterOutputter);
 
       tablePrinter.setNewRowCellIndent(0);
     }
@@ -240,15 +238,10 @@
  * Certain event types have custom pretty printers. Everything else will
  * default to a JSON-like format.
  */
-function writeParameters(entry, privacyStripping, out) {
-  if (privacyStripping) {
-    // If privacy stripping is enabled, remove data as needed.
-    entry = stripPrivacyInfo(entry);
-  } else {
-    // If headers are in an object, convert them to an array for better
-    // display.
-    entry = reformatHeaders(entry);
-  }
+function writeParameters(entry, out) {
+  // If headers are in an object, convert them to an array for better
+  // display.
+  entry = reformatHeaders(entry);
 
   // Use any parameter writer available for this event type.
   var paramsWriter = getParameterWriterForEventType(entry.type);
@@ -442,131 +435,6 @@
 }
 
 /**
- * Removes a cookie or unencrypted login information from a single HTTP header
- * line, if present, and returns the modified line.  Otherwise, just returns
- * the original line.
- *
- * Note: this logic should be kept in sync with
- * net::ElideHeaderValueForNetLog in net/http/http_log_util.cc.
- */
-function stripCookieOrLoginInfo(line) {
-  var patterns = [
-    // Cookie patterns
-    /^set-cookie: /i, /^set-cookie2: /i, /^cookie: /i,
-
-    // Unencrypted authentication patterns
-    /^authorization: \S*\s*/i, /^proxy-authorization: \S*\s*/i
-  ];
-
-  // Prefix will hold the first part of the string that contains no private
-  // information.  If null, no part of the string contains private
-  // information.
-  var prefix = null;
-  for (var i = 0; i < patterns.length; i++) {
-    var match = patterns[i].exec(line);
-    if (match != null) {
-      prefix = match[0];
-      break;
-    }
-  }
-
-  // Look for authentication information from data received from the server in
-  // multi-round Negotiate authentication.
-  if (prefix === null) {
-    var challengePatterns =
-        [/^www-authenticate: (\S*)\s*/i, /^proxy-authenticate: (\S*)\s*/i];
-    for (var i = 0; i < challengePatterns.length; i++) {
-      var match = challengePatterns[i].exec(line);
-      if (!match)
-        continue;
-
-      // If there's no data after the scheme name, do nothing.
-      if (match[0].length == line.length)
-        break;
-
-      // Ignore lines with commas, as they may contain lists of schemes, and
-      // the information we want to hide is Base64 encoded, so has no commas.
-      if (line.indexOf(',') >= 0)
-        break;
-
-      // Ignore Basic and Digest authentication challenges, as they contain
-      // public information.
-      if (/^basic$/i.test(match[1]) || /^digest$/i.test(match[1]))
-        break;
-
-      prefix = match[0];
-      break;
-    }
-  }
-
-  if (prefix) {
-    var suffix = line.slice(prefix.length);
-    // If private information has already been removed, keep the line as-is.
-    // This is often the case when viewing a loaded log.
-    if (suffix.search(/^\[[0-9]+ bytes were stripped\]$/) == -1) {
-      return prefix + '[' + suffix.length + ' bytes were stripped]';
-    }
-  }
-
-  return line;
-}
-
-/**
- * Remove debug data from HTTP/2 GOAWAY frame due to privacy considerations,
- * see
- * https://httpwg.github.io/specs/rfc7540.html#GOAWAY.
- *
- * Note: this logic should be kept in sync with
- * net::ElideGoAwayDebugDataForNetLog in net/http/http_log_util.cc.
- */
-function stripGoAwayDebugData(value) {
-  return '[' + value.length + ' bytes were stripped]';
-}
-
-/**
- * If |entry| has headers, returns a copy of |entry| with all cookie and
- * unencrypted login text removed.  Otherwise, returns original |entry|
- * object.
- * This is needed so that JSON log dumps can be made without affecting the
- * source data.  Converts headers stored in objects to arrays.
- */
-stripPrivacyInfo = function(entry) {
-  if (!entry.params) {
-    return entry;
-  }
-
-  if (entry.type == EventType.HTTP2_SESSION_GOAWAY &&
-      entry.params.debug_data != undefined) {
-    // Duplicate the top level object, and |entry.params|.  All other fields
-    // are
-    // just pointers to the original values, as they won't be modified, other
-    // than |entry.params.debug_data|.
-    entry = shallowCloneObject(entry);
-    entry.params = shallowCloneObject(entry.params);
-    entry.params.debug_data = stripGoAwayDebugData(entry.params.debug_data);
-    return entry;
-  }
-
-  if (entry.params.headers === undefined ||
-      !(entry.params.headers instanceof Object)) {
-    return entry;
-  }
-
-  // Make sure entry's headers are in an array.
-  entry = reformatHeaders(entry);
-
-  // Duplicate the top level object, and |entry.params|.  All other fields are
-  // just pointers to the original values, as they won't be modified, other
-  // than
-  // |entry.params.headers|.
-  entry = shallowCloneObject(entry);
-  entry.params = shallowCloneObject(entry.params);
-
-  entry.params.headers = entry.params.headers.map(stripCookieOrLoginInfo);
-  return entry;
-};
-
-/**
  * Outputs the request header parameters of |entry| to |out|.
  */
 function writeParamsForRequestHeaders(entry, out, consumedParams) {
diff --git a/chrome/browser/resources/net_internals/main.js b/chrome/browser/resources/net_internals/main.js
index 6b286ea8..ca6ce6d 100644
--- a/chrome/browser/resources/net_internals/main.js
+++ b/chrome/browser/resources/net_internals/main.js
@@ -125,10 +125,8 @@
       this.stopCapturing();
       if (opt_fileName != undefined) {
         // If there's a file name, a log file was loaded, so swap out the status
-        // bar to indicate we're no longer capturing events.  Also disable
-        // hiding cookies, so if the log dump has them, they'll be displayed.
+        // bar to indicate we're no longer capturing events.
         this.topBarView_.switchToSubView('loaded').setFileName(opt_fileName);
-        SourceTracker.getInstance().setPrivacyStripping(false);
       } else {
         // Otherwise, the "Stop Capturing" button was presumably pressed.
         // Don't disable hiding cookies, so created log dumps won't have them,
diff --git a/chrome/browser/resources/net_internals/source_entry.js b/chrome/browser/resources/net_internals/source_entry.js
index bb1db6fc..100d72e 100644
--- a/chrome/browser/resources/net_internals/source_entry.js
+++ b/chrome/browser/resources/net_internals/source_entry.js
@@ -335,7 +335,7 @@
      */
     createTablePrinter: function() {
       return createLogEntryTablePrinter(
-          this.entries_, SourceTracker.getInstance().getPrivacyStripping(),
+          this.entries_,
           SourceTracker.getInstance().getUseRelativeTimes() ?
               timeutil.getBaseTime() :
               0,
diff --git a/chrome/browser/resources/net_internals/source_tracker.js b/chrome/browser/resources/net_internals/source_tracker.js
index 9e870db..9dce848 100644
--- a/chrome/browser/resources/net_internals/source_tracker.js
+++ b/chrome/browser/resources/net_internals/source_tracker.js
@@ -18,11 +18,6 @@
     // Observers that only want to receive lists of updated SourceEntries.
     this.sourceEntryObservers_ = [];
 
-    // True when cookies and authentication information should be removed from
-    // displayed events.  When true, such information should be hidden from
-    // all pages.
-    this.privacyStripping_ = true;
-
     // True when times should be displayed as milliseconds since the first
     // event, as opposed to milliseconds since January 1, 1970.
     this.useRelativeTimes_ = true;
@@ -135,26 +130,6 @@
     },
 
     /**
-     * Sets the value of |privacyStripping_| and informs log observers
-     * of the change.
-     */
-    setPrivacyStripping: function(privacyStripping) {
-      this.privacyStripping_ = privacyStripping;
-      for (var i = 0; i < this.sourceEntryObservers_.length; ++i) {
-        if (this.sourceEntryObservers_[i].onPrivacyStrippingChanged)
-          this.sourceEntryObservers_[i].onPrivacyStrippingChanged();
-      }
-    },
-
-    /**
-     * Returns whether or not cookies and authentication information should be
-     * displayed for events that contain them.
-     */
-    getPrivacyStripping: function() {
-      return this.privacyStripping_;
-    },
-
-    /**
      * Sets the value of |useRelativeTimes_| and informs log observers
      * of the change.
      */
@@ -176,12 +151,10 @@
 
     /**
      * Adds a listener of SourceEntries. |observer| will be called back when
-     * SourceEntries are added or modified, source entries are deleted, or
-     * privacy stripping changes:
+     * SourceEntries are added or modified or source entries are deleted.
      *
      *   observer.onSourceEntriesUpdated(sourceEntries)
      *   observer.onAllSourceEntriesDeleted()
-     *   observer.onPrivacyStrippingChanged()
      */
     addSourceEntryObserver: function(observer) {
       this.sourceEntryObservers_.push(observer);
diff --git a/chrome/browser/resources/offline_pages/offline_internals.css b/chrome/browser/resources/offline_pages/offline_internals.css
index 534ae985..d8ad7a5 100644
--- a/chrome/browser/resources/offline_pages/offline_internals.css
+++ b/chrome/browser/resources/offline_pages/offline_internals.css
@@ -47,6 +47,10 @@
   background-color: lavender;
 }
 
+dialog {
+  border: none;
+}
+
 #current-status {
   font-size: 15px;
 }
@@ -55,3 +59,10 @@
   font-family: monospace;
   white-space: pre-wrap;
 }
+
+#dump-box {
+  box-sizing: border-box;
+  display: block;
+  resize: none;
+  width: 100%;
+}
diff --git a/chrome/browser/resources/offline_pages/offline_internals.html b/chrome/browser/resources/offline_pages/offline_internals.html
index 2590edb..7ba272d 100644
--- a/chrome/browser/resources/offline_pages/offline_internals.html
+++ b/chrome/browser/resources/offline_pages/offline_internals.html
@@ -19,8 +19,15 @@
     <div>
       <span id="current-status"></span>
       <button id="refresh">Refresh page</button>
-      <button id="download">Dump</button>
+      <button id="dump">Dump</button>
     </div>
+    <dialog id="dump">
+      <textarea id="dump-box" name="json-box" rows="10" cols="40" readonly>
+      </textarea>
+      <button id="copy-to-clipboard">Copy</button>
+      <button id="close-dump">Close</button>
+      <span id="dump-info"></span>
+    </dialog>
 
     <h2>Event Logs</h2>
     <div>
diff --git a/chrome/browser/resources/offline_pages/offline_internals.js b/chrome/browser/resources/offline_pages/offline_internals.js
index 2605b0b..65762808 100644
--- a/chrome/browser/resources/offline_pages/offline_internals.js
+++ b/chrome/browser/resources/offline_pages/offline_internals.js
@@ -173,13 +173,26 @@
    * Downloads all the stored page and request queue information into a file.
    * TODO(chili): Create a CSV writer that can abstract out the line joining.
    */
-  function download() {
+  function dumpAsJson() {
     var json = JSON.stringify(
         {offlinePages: offlinePages, savePageRequests: savePageRequests}, null,
         2);
 
-    window.open(
-        'data:application/json,' + encodeURIComponent(json), 'dump.json');
+    $('dump-box').value = json;
+    $('dump-info').textContent = '';
+    $('dump').showModal();
+    $('dump-box').select();
+  }
+
+  function closeDump() {
+    $('dump').close();
+    $('dump-box').value = '';
+  }
+
+  function copyDump() {
+    $('dump-box').select();
+    document.execCommand('copy');
+    $('dump-info').textContent = 'Copied to clipboard!';
   }
 
   /**
@@ -260,22 +273,19 @@
     }
 
     var incognito = loadTimeData.getBoolean('isIncognito');
-    $('delete-all-pages').disabled = incognito;
-    $('delete-selected-pages').disabled = incognito;
-    $('delete-all-requests').disabled = incognito;
-    $('delete-selected-requests').disabled = incognito;
-    $('log-model-on').disabled = incognito;
-    $('log-model-off').disabled = incognito;
-    $('log-request-on').disabled = incognito;
-    $('log-request-off').disabled = incognito;
-    $('refresh').disabled = incognito;
+    ['delete-all-pages', 'delete-selected-pages', 'delete-all-requests',
+     'delete-selected-requests', 'log-model-on', 'log-model-off',
+     'log-request-on', 'log-request-off', 'refresh']
+        .forEach(el => $(el).disabled = incognito);
 
     $('delete-all-pages').onclick = deleteAllPages;
     $('delete-selected-pages').onclick = deleteSelectedPages;
     $('delete-all-requests').onclick = deleteAllRequests;
     $('delete-selected-requests').onclick = deleteSelectedRequests;
     $('refresh').onclick = refreshAll;
-    $('download').onclick = download;
+    $('dump').onclick = dumpAsJson;
+    $('close-dump').onclick = closeDump;
+    $('copy-to-clipboard').onclick = copyDump;
     $('log-model-on').onclick = togglePageModelLog.bind(this, true);
     $('log-model-off').onclick = togglePageModelLog.bind(this, false);
     $('log-request-on').onclick = toggleRequestQueueLog.bind(this, true);
diff --git a/chrome/browser/resources/settings/device_page/stylus.html b/chrome/browser/resources/settings/device_page/stylus.html
index 4c50c212..ac5e133 100644
--- a/chrome/browser/resources/settings/device_page/stylus.html
+++ b/chrome/browser/resources/settings/device_page/stylus.html
@@ -29,13 +29,15 @@
       }
     </style>
 
-    <settings-toggle-button class="continuation"
+    <settings-toggle-button id="enableStylusToolsToggle"
+        class="continuation"
         pref="{{prefs.settings.enable_stylus_tools}}"
         label="$i18n{stylusEnableStylusTools}">
     </settings-toggle-button>
 
     <template is="dom-if" if="[[hasInternalStylus_]]">
       <settings-toggle-button
+          id ="launchPaletteOnEjectEventToggle"
           pref="{{prefs.settings.launch_palette_on_eject_event}}"
           label="$i18n{stylusAutoOpenStylusTools}"
           disabled="[[!prefs.settings.enable_stylus_tools.value]]">
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/OWNERS b/chrome/browser/safe_browsing/chrome_cleaner/OWNERS
index 51897aa..e54e7edd 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/OWNERS
+++ b/chrome/browser/safe_browsing/chrome_cleaner/OWNERS
@@ -1,4 +1,5 @@
 csharp@chromium.org
+joenotcharles@chromium.org
 robertshield@chromium.org
 
 # COMPONENT: UI>Browser>Preferences>Protector
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc
index 83d9170e..4d18784 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc
@@ -160,12 +160,11 @@
   // committed navigation.
   if (navigation_handle->IsRendererInitiated() && current_frame_host &&
       current_frame_host->GetLastCommittedURL().is_valid()) {
-    nav_event->source_url =
-        SafeBrowsingNavigationObserverManager::ClearEmptyRef(
-            current_frame_host->GetLastCommittedURL());
+    nav_event->source_url = SafeBrowsingNavigationObserverManager::ClearURLRef(
+        current_frame_host->GetLastCommittedURL());
   }
   nav_event->original_request_url =
-      SafeBrowsingNavigationObserverManager::ClearEmptyRef(
+      SafeBrowsingNavigationObserverManager::ClearURLRef(
           navigation_handle->GetURL());
 
   nav_event->source_tab_id =
@@ -175,7 +174,7 @@
     nav_event->source_main_frame_url = nav_event->source_url;
   } else {
     nav_event->source_main_frame_url =
-        SafeBrowsingNavigationObserverManager::ClearEmptyRef(
+        SafeBrowsingNavigationObserverManager::ClearURLRef(
             navigation_handle->GetWebContents()->GetLastCommittedURL());
   }
   navigation_handle_map_[navigation_handle] = std::move(nav_event);
@@ -190,7 +189,7 @@
   }
   NavigationEvent* nav_event = navigation_handle_map_[navigation_handle].get();
   nav_event->server_redirect_urls.push_back(
-      SafeBrowsingNavigationObserverManager::ClearEmptyRef(
+      SafeBrowsingNavigationObserverManager::ClearURLRef(
           navigation_handle->GetURL()));
   nav_event->last_updated = base::Time::Now();
 }
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
index 5342323..876a2a3 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
@@ -75,6 +75,9 @@
 const char kLandingReferrerURL[] =
     "/safe_browsing/download_protection/navigation_observer/"
     "landing_referrer.html";
+const char kLandingReferrerURLWithQuery[] =
+    "/safe_browsing/download_protection/navigation_observer/"
+    "landing_referrer.html?bar=foo";
 const char kPageBeforeLandingReferrerURL[] =
     "/safe_browsing/download_protection/navigation_observer/"
     "page_before_landing_referrer.html";
@@ -385,6 +388,14 @@
     }
   }
 
+  void IdentifyReferrerChainForWebContents(content::WebContents* web_contents,
+                                           ReferrerChain* referrer_chain) {
+    observer_manager_->IdentifyReferrerChainByWebContents(
+        web_contents,
+        2,  // kDownloadAttributionUserGestureLimit
+        referrer_chain);
+  }
+
   // Identify referrer chain of a PPAPI download and populate |referrer_chain|.
   void IdentifyReferrerChainForPPAPIDownload(
       const GURL& initiating_frame_url,
@@ -2024,6 +2035,56 @@
                            referrer_chain.Get(0));
 }
 
+// Verify referrer chain when there are URL fragments.
+IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest,
+                       DownloadAttributionWithURLFragment) {
+  GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL);
+  // Clicks on link and navigates to ".../page_before_landing_referrer.html".
+  ClickTestLink("attribution_should_ignore_url_fragments", 1, initial_url);
+  GURL expected_page_before_landing_referrer_url =
+      embedded_test_server()->GetURL(kPageBeforeLandingReferrerURL);
+  // Clicks on link and navigates to ".../landing_referrer.html?bar=foo#baz".
+  ClickTestLink("link_to_landing_referrer_with_query_and_fragment", 1,
+                expected_page_before_landing_referrer_url);
+  GURL expected_landing_referrer_url_with_query =
+      embedded_test_server()->GetURL(kLandingReferrerURLWithQuery);
+  // Clicks on link and navigates to ".../landing.html#".
+  ClickTestLink("link_to_landing_with_empty_fragment", 1,
+                expected_landing_referrer_url_with_query);
+  GURL expected_landing_url = embedded_test_server()->GetURL(kLandingURL);
+
+  std::string test_server_ip(embedded_test_server()->host_port_pair().host());
+  auto* nav_list = navigation_event_list();
+  ASSERT_EQ(4U, nav_list->Size());
+
+  ReferrerChain referrer_chain;
+  SimulateUserGesture();
+  IdentifyReferrerChainForWebContents(
+      browser()->tab_strip_model()->GetActiveWebContents(), &referrer_chain);
+  ASSERT_EQ(2, referrer_chain.size());
+
+  // Verify url fragment is cleared in referrer chain.
+  VerifyReferrerChainEntry(expected_landing_url,              // url
+                           GURL(),                            // main_frame_url
+                           ReferrerChainEntry::LANDING_PAGE,  // type
+                           test_server_ip,                    // ip_address
+                           expected_landing_referrer_url_with_query,
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
+                           referrer_chain.Get(0));
+  VerifyReferrerChainEntry(
+      expected_landing_referrer_url_with_query,  // url
+      GURL(),                                    // main_frame_url
+      ReferrerChainEntry::LANDING_REFERRER,      // type
+      test_server_ip,                            // ip_address
+      GURL(),  // referrer_url is empty since this beyonds 2 clicks.
+      GURL(),  // referrer_main_frame_url is empty for the same reason.
+      false,   // is_retargeting
+      std::vector<GURL>(),  // server redirects
+      referrer_chain.Get(1));
+}
+
 IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest,
                        VerifySanitizeReferrerChain) {
   GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL);
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
index dbbbcd4..c4b717a1 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
@@ -175,7 +175,7 @@
 
 void NavigationEventList::RecordNavigationEvent(
     std::unique_ptr<NavigationEvent> nav_event) {
-  // Skip page refresh.
+  // Skip page refresh and in-page navigation.
   if (nav_event->source_url == nav_event->GetDestinationUrl() &&
       nav_event->source_tab_id == nav_event->target_tab_id)
     return;
@@ -206,8 +206,8 @@
 }
 
 // static
-GURL SafeBrowsingNavigationObserverManager::ClearEmptyRef(const GURL& url) {
-  if (url.has_ref() && url.ref().empty()) {
+GURL SafeBrowsingNavigationObserverManager::ClearURLRef(const GURL& url) {
+  if (url.has_ref()) {
     url::Replacements<char> replacements;
     replacements.ClearRef();
     return url.ReplaceComponents(replacements);
@@ -341,7 +341,7 @@
     return INVALID_URL;
 
   NavigationEvent* nav_event = navigation_event_list_.FindNavigationEvent(
-      event_url, GURL(), event_tab_id);
+      ClearURLRef(event_url), GURL(), event_tab_id);
   if (!nav_event) {
     // We cannot find a single navigation event related to this event.
     return NAVIGATION_EVENT_NOT_FOUND;
@@ -364,12 +364,13 @@
     content::WebContents* web_contents,
     int user_gesture_count_limit,
     ReferrerChain* out_referrer_chain) {
-  if (!web_contents || !web_contents->GetLastCommittedURL().is_valid())
+  GURL last_committed_url = web_contents->GetLastCommittedURL();
+  if (!web_contents || !last_committed_url.is_valid())
     return INVALID_URL;
   bool has_user_gesture = HasUserGesture(web_contents);
   int tab_id = SessionTabHelper::IdForTab(web_contents);
   return IdentifyReferrerChainByHostingPage(
-      web_contents->GetLastCommittedURL(), GURL(), tab_id, has_user_gesture,
+      ClearURLRef(last_committed_url), GURL(), tab_id, has_user_gesture,
       user_gesture_count_limit, out_referrer_chain);
 }
 
@@ -385,7 +386,8 @@
     return INVALID_URL;
 
   NavigationEvent* nav_event = navigation_event_list_.FindNavigationEvent(
-      initiating_frame_url, initiating_main_frame_url, tab_id);
+      ClearURLRef(initiating_frame_url), ClearURLRef(initiating_main_frame_url),
+      tab_id);
   if (!nav_event) {
     // We cannot find a single navigation event related to this hosting page.
     return NAVIGATION_EVENT_NOT_FOUND;
@@ -434,18 +436,17 @@
   // Remove the "#" at the end of URL, since it does not point to any actual
   // page fragment ID.
   GURL cleaned_target_url =
-      SafeBrowsingNavigationObserverManager::ClearEmptyRef(target_url);
+      SafeBrowsingNavigationObserverManager::ClearURLRef(target_url);
 
   std::unique_ptr<NavigationEvent> nav_event =
       base::MakeUnique<NavigationEvent>();
   if (rfh) {
-    nav_event->source_url =
-        SafeBrowsingNavigationObserverManager::ClearEmptyRef(
-            rfh->GetLastCommittedURL());
+    nav_event->source_url = SafeBrowsingNavigationObserverManager::ClearURLRef(
+        rfh->GetLastCommittedURL());
   }
   nav_event->source_tab_id = SessionTabHelper::IdForTab(source_web_contents);
   nav_event->source_main_frame_url =
-      SafeBrowsingNavigationObserverManager::ClearEmptyRef(
+      SafeBrowsingNavigationObserverManager::ClearURLRef(
           source_web_contents->GetLastCommittedURL());
   nav_event->original_request_url = cleaned_target_url;
   nav_event->target_tab_id = SessionTabHelper::IdForTab(target_web_contents);
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h
index 55b2d85..15a6c6f 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h
@@ -111,11 +111,12 @@
   // kUserGestureTTLInSecond.
   static bool IsUserGestureExpired(const base::Time& timestamp);
 
-  // Helper function to strip empty ref fragment from a URL. Many pages
-  // end up with a "#" at the end of their URLs due to navigation triggered by
+  // Helper function to strip ref fragment from a URL. Many pages end up with a
+  // fragment (e.g. http://bar.com/index.html#foo) at the end due to in-page
+  // navigation or a single "#" at the end due to navigation triggered by
   // href="#" and javascript onclick function. We don't want to have separate
   // entries for these cases in the maps.
-  static GURL ClearEmptyRef(const GURL& url);
+  static GURL ClearURLRef(const GURL& url);
 
   // Checks if we should enable observing navigations for safe browsing purpose.
   // Return true if the safe browsing safe browsing service is enabled and
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index 13cb822..8dc7685c 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -180,13 +180,12 @@
 // The order must match as the index is used in determining the raw id.
 bool InputScalesValid(const base::StringPiece& input,
                       const std::vector<ui::ScaleFactor>& expected) {
-  size_t scales_size = static_cast<size_t>(input.size() / sizeof(float));
-  if (scales_size != expected.size())
+  if (input.size() != expected.size() * sizeof(float))
     return false;
-  std::unique_ptr<float[]> scales(new float[scales_size]);
+  std::unique_ptr<float[]> scales(new float[expected.size()]);
   // Do a memcpy to avoid misaligned memory access.
   memcpy(scales.get(), input.data(), input.size());
-  for (size_t index = 0; index < scales_size; ++index) {
+  for (size_t index = 0; index < expected.size(); ++index) {
     if (scales[index] != ui::GetScaleForScaleFactor(expected[index]))
       return false;
   }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 02e655cd..25186eb 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -74,8 +74,6 @@
     "autofill/popup_view_common.h",
     "blocked_content/blocked_window_params.cc",
     "blocked_content/blocked_window_params.h",
-    "blocked_content/console_logger.cc",
-    "blocked_content/console_logger.h",
     "blocked_content/popup_blocker_tab_helper.cc",
     "blocked_content/popup_blocker_tab_helper.h",
     "blocked_content/popup_opener_tab_helper.cc",
diff --git a/chrome/browser/ui/blocked_content/console_logger.cc b/chrome/browser/ui/blocked_content/console_logger.cc
deleted file mode 100644
index 4bb56a54..0000000
--- a/chrome/browser/ui/blocked_content/console_logger.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/blocked_content/console_logger.h"
-
-#include "base/logging.h"
-#include "content/public/browser/render_frame_host.h"
-
-ConsoleLogger::ConsoleLogger() = default;
-ConsoleLogger::~ConsoleLogger() = default;
-
-void ConsoleLogger::LogInFrame(content::RenderFrameHost* render_frame_host,
-                               content::ConsoleMessageLevel level,
-                               const std::string& message) {
-  DCHECK(render_frame_host);
-  render_frame_host->AddMessageToConsole(level, message);
-}
diff --git a/chrome/browser/ui/blocked_content/console_logger.h b/chrome/browser/ui/blocked_content/console_logger.h
deleted file mode 100644
index 810b638..0000000
--- a/chrome/browser/ui/blocked_content/console_logger.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_BLOCKED_CONTENT_CONSOLE_LOGGER_H_
-#define CHROME_BROWSER_UI_BLOCKED_CONTENT_CONSOLE_LOGGER_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "content/public/common/console_message_level.h"
-
-namespace content {
-class RenderFrameHost;
-}
-
-// This simple class just forwards console logging to the associated
-// RenderFrameHost, to send down to the renderer. It exists for unit tests to
-// mock out, allowing unit tests to expect console messages without having to
-// write a full browser test.
-class ConsoleLogger {
- public:
-  ConsoleLogger();
-  virtual ~ConsoleLogger();
-
-  virtual void LogInFrame(content::RenderFrameHost* render_frame_host,
-                          content::ConsoleMessageLevel level,
-                          const std::string& message);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ConsoleLogger);
-};
-
-#endif  // CHROME_BROWSER_UI_BLOCKED_CONTENT_CONSOLE_LOGGER_H_
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
index f3df144..cb3b678 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/subresource_filter/chrome_subresource_filter_client.h"
 #include "chrome/browser/ui/blocked_content/blocked_window_params.h"
-#include "chrome/browser/ui/blocked_content/console_logger.h"
 #include "chrome/browser/ui/blocked_content/popup_tracker.h"
 #include "chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.h"
 #include "chrome/browser/ui/browser_navigator.h"
@@ -55,9 +54,7 @@
 PopupBlockerTabHelper::PopupBlockerTabHelper(content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
       safe_browsing_triggered_popup_blocker_(
-          SafeBrowsingTriggeredPopupBlocker::MaybeCreate(
-              web_contents,
-              base::MakeUnique<ConsoleLogger>())) {}
+          SafeBrowsingTriggeredPopupBlocker::MaybeCreate(web_contents)) {}
 
 PopupBlockerTabHelper::~PopupBlockerTabHelper() {
 }
diff --git a/chrome/browser/ui/blocked_content/popup_opener_tab_helper_unittest.cc b/chrome/browser/ui/blocked_content/popup_opener_tab_helper_unittest.cc
index b9171d52..ae03b91 100644
--- a/chrome/browser/ui/blocked_content/popup_opener_tab_helper_unittest.cc
+++ b/chrome/browser/ui/blocked_content/popup_opener_tab_helper_unittest.cc
@@ -567,3 +567,21 @@
   EXPECT_EQ(first_url.host(), sample);
   EXPECT_EQ(rappor::UMA_RAPPOR_TYPE, type);
 }
+
+TEST_F(BlockTabUnderTest, LogsToConsole) {
+  EXPECT_TRUE(NavigateAndCommitWithoutGesture(GURL("https://first.test/")));
+  SimulatePopup();
+  const GURL blocked_url("https://example.test/");
+
+  const auto& messages =
+      content::RenderFrameHostTester::For(main_rfh())->GetConsoleMessages();
+
+  EXPECT_EQ(0u, messages.size());
+  EXPECT_FALSE(NavigateAndCommitWithoutGesture(blocked_url));
+  ExpectUIShown(true);
+
+  EXPECT_EQ(1u, messages.size());
+  std::string expected_message = base::StringPrintf(kBlockTabUnderFormatMessage,
+                                                    blocked_url.spec().c_str());
+  EXPECT_EQ(expected_message, messages.front());
+}
diff --git a/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.cc b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.cc
index c04ee92c..58d53904 100644
--- a/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.cc
+++ b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.cc
@@ -9,11 +9,11 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
-#include "chrome/browser/ui/blocked_content/console_logger.h"
 #include "components/safe_browsing/db/util.h"
 #include "components/safe_browsing/db/v4_protocol_manager_util.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/page_navigator.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/console_message_level.h"
 #include "third_party/WebKit/public/web/WebTriggeringEventInfo.h"
@@ -47,8 +47,7 @@
 // static
 std::unique_ptr<SafeBrowsingTriggeredPopupBlocker>
 SafeBrowsingTriggeredPopupBlocker::MaybeCreate(
-    content::WebContents* web_contents,
-    std::unique_ptr<ConsoleLogger> logger) {
+    content::WebContents* web_contents) {
   if (!base::FeatureList::IsEnabled(kAbusiveExperienceEnforce))
     return nullptr;
 
@@ -57,8 +56,8 @@
           web_contents);
   if (!observer_manager)
     return nullptr;
-  return base::WrapUnique(new SafeBrowsingTriggeredPopupBlocker(
-      web_contents, observer_manager, std::move(logger)));
+  return base::WrapUnique(
+      new SafeBrowsingTriggeredPopupBlocker(web_contents, observer_manager));
 }
 
 SafeBrowsingTriggeredPopupBlocker::~SafeBrowsingTriggeredPopupBlocker() =
@@ -81,20 +80,17 @@
   if (should_block) {
     LogAction(Action::kBlocked);
     current_page_data_->inc_num_popups_blocked();
-    logger_->LogInFrame(web_contents()->GetMainFrame(),
-                        content::CONSOLE_MESSAGE_LEVEL_ERROR,
-                        kAbusiveEnforceMessage);
+    web_contents()->GetMainFrame()->AddMessageToConsole(
+        content::CONSOLE_MESSAGE_LEVEL_ERROR, kAbusiveEnforceMessage);
   }
   return should_block;
 }
 
 SafeBrowsingTriggeredPopupBlocker::SafeBrowsingTriggeredPopupBlocker(
     content::WebContents* web_contents,
-    subresource_filter::SubresourceFilterObserverManager* observer_manager,
-    std::unique_ptr<ConsoleLogger> logger)
+    subresource_filter::SubresourceFilterObserverManager* observer_manager)
     : content::WebContentsObserver(web_contents),
       scoped_observer_(this),
-      logger_(std::move(logger)),
       current_page_data_(base::MakeUnique<PageData>()),
       ignore_sublists_(
           base::GetFieldTrialParamByFeatureAsBool(kAbusiveExperienceEnforce,
@@ -128,9 +124,8 @@
     current_page_data_->set_is_triggered(true);
     LogAction(Action::kEnforcedSite);
   } else if (level == SubresourceFilterLevel::WARN) {
-    logger_->LogInFrame(web_contents()->GetMainFrame(),
-                        content::CONSOLE_MESSAGE_LEVEL_WARNING,
-                        kAbusiveWarnMessage);
+    web_contents()->GetMainFrame()->AddMessageToConsole(
+        content::CONSOLE_MESSAGE_LEVEL_WARNING, kAbusiveWarnMessage);
     LogAction(Action::kWarningSite);
   }
   LogAction(Action::kNavigation);
diff --git a/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.h b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.h
index c6f10db..cd4d4c5 100644
--- a/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.h
+++ b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.h
@@ -21,7 +21,6 @@
 class WebContents;
 }  // namespace content
 
-class ConsoleLogger;
 
 extern const base::Feature kAbusiveExperienceEnforce;
 
@@ -68,20 +67,18 @@
   };
 
   static std::unique_ptr<SafeBrowsingTriggeredPopupBlocker> MaybeCreate(
-      content::WebContents* web_contents,
-      std::unique_ptr<ConsoleLogger> logger);
+      content::WebContents* web_contents);
   ~SafeBrowsingTriggeredPopupBlocker() override;
 
   bool ShouldApplyStrongPopupBlocker(
       const content::OpenURLParams* open_url_params);
 
  private:
-  // The |web_contents|, |observer_manager|, and |logger| are expected to be
+  // The |web_contents| and |observer_manager| are expected to be
   // non-nullptr.
   SafeBrowsingTriggeredPopupBlocker(
       content::WebContents* web_contents,
-      subresource_filter::SubresourceFilterObserverManager* observer_manager,
-      std::unique_ptr<ConsoleLogger> logger);
+      subresource_filter::SubresourceFilterObserverManager* observer_manager);
 
   // content::WebContentsObserver:
   void DidFinishNavigation(
@@ -128,9 +125,6 @@
       level_for_next_committed_navigation_;
 
   // Should never be nullptr.
-  std::unique_ptr<ConsoleLogger> logger_;
-
-  // Should never be nullptr.
   std::unique_ptr<PageData> current_page_data_;
 
   // Whether to ignore the threat pattern type. Useful for flexibility because
diff --git a/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
index ec07e55..27f1890 100644
--- a/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
+++ b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
@@ -16,12 +16,12 @@
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
 #include "chrome/browser/subresource_filter/chrome_subresource_filter_client.h"
-#include "chrome/browser/ui/blocked_content/console_logger.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "components/safe_browsing/db/v4_protocol_manager_util.h"
 #include "components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h"
 #include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/web/WebTriggeringEventInfo.h"
 #include "ui/base/page_transition_types.h"
@@ -31,24 +31,6 @@
 const char kNumBlockedHistogram[] =
     "ContentSettings.Popups.StrongBlocker.NumBlocked";
 
-class TestConsoleLogger : public ConsoleLogger {
- public:
-  TestConsoleLogger() {}
-  ~TestConsoleLogger() override {}
-
-  void LogInFrame(content::RenderFrameHost* render_frame_host,
-                  content::ConsoleMessageLevel level,
-                  const std::string& message) override {
-    messages_.push_back(message);
-  }
-
-  const std::vector<std::string>& messages() { return messages_; }
-
- private:
-  std::vector<std::string> messages_;
-  DISALLOW_COPY_AND_ASSIGN(TestConsoleLogger);
-};
-
 class SafeBrowsingTriggeredPopupBlockerTest
     : public ChromeRenderViewHostTestHarness {
  public:
@@ -79,11 +61,8 @@
     ChromeSubresourceFilterClient::CreateForWebContents(web_contents());
 
     scoped_feature_list_ = DefaultFeatureList();
-
-    auto console_logger = base::MakeUnique<TestConsoleLogger>();
-    console_logger_ = console_logger.get();
-    popup_blocker_ = SafeBrowsingTriggeredPopupBlocker::MaybeCreate(
-        web_contents(), std::move(console_logger));
+    popup_blocker_ =
+        SafeBrowsingTriggeredPopupBlocker::MaybeCreate(web_contents());
   }
 
   void TearDown() override {
@@ -140,16 +119,17 @@
     MarkUrlAsAbusiveWithLevel(url, safe_browsing::SubresourceFilterLevel::WARN);
   }
 
-  TestConsoleLogger* console_logger() { return console_logger_; }
+  const std::vector<std::string>& GetMainFrameConsoleMessages() {
+    content::RenderFrameHostTester* rfh_tester =
+        content::RenderFrameHostTester::For(main_rfh());
+    return rfh_tester->GetConsoleMessages();
+  }
 
  private:
   std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
   scoped_refptr<FakeSafeBrowsingDatabaseManager> fake_safe_browsing_database_;
   std::unique_ptr<SafeBrowsingTriggeredPopupBlocker> popup_blocker_;
 
-  // Owned by the popup blocker.
-  TestConsoleLogger* console_logger_ = nullptr;
-
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingTriggeredPopupBlockerTest);
 };
 
@@ -185,11 +165,11 @@
   const GURL url("https://example.test/");
   MarkUrlAsAbusiveEnforce(url);
   NavigateAndCommit(url);
-  EXPECT_TRUE(console_logger()->messages().empty());
+  EXPECT_TRUE(GetMainFrameConsoleMessages().empty());
 
   EXPECT_TRUE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
-  EXPECT_EQ(1u, console_logger()->messages().size());
-  EXPECT_EQ(console_logger()->messages().front(), kAbusiveEnforceMessage);
+  EXPECT_EQ(1u, GetMainFrameConsoleMessages().size());
+  EXPECT_EQ(GetMainFrameConsoleMessages().front(), kAbusiveEnforceMessage);
 }
 
 TEST_F(SafeBrowsingTriggeredPopupBlockerTest,
@@ -216,15 +196,15 @@
   const GURL url("https://example.test/");
   NavigateAndCommit(url);
   EXPECT_FALSE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
-  EXPECT_TRUE(console_logger()->messages().empty());
+  EXPECT_TRUE(GetMainFrameConsoleMessages().empty());
 }
 
 TEST_F(SafeBrowsingTriggeredPopupBlockerTest, NoFeature_NoCreating) {
-  EXPECT_NE(nullptr, SafeBrowsingTriggeredPopupBlocker::MaybeCreate(
-                         web_contents(), base::MakeUnique<ConsoleLogger>()));
+  EXPECT_NE(nullptr,
+            SafeBrowsingTriggeredPopupBlocker::MaybeCreate(web_contents()));
   ResetFeatureAndGet();
-  EXPECT_EQ(nullptr, SafeBrowsingTriggeredPopupBlocker::MaybeCreate(
-                         web_contents(), base::MakeUnique<ConsoleLogger>()));
+  EXPECT_EQ(nullptr,
+            SafeBrowsingTriggeredPopupBlocker::MaybeCreate(web_contents()));
 }
 
 TEST_F(SafeBrowsingTriggeredPopupBlockerTest, OnlyBlockOnMatchingUrls) {
@@ -368,8 +348,8 @@
   NavigateAndCommit(url);
 
   // Warning should come at navigation commit time, not at popup time.
-  EXPECT_EQ(1u, console_logger()->messages().size());
-  EXPECT_EQ(console_logger()->messages().front(), kAbusiveWarnMessage);
+  EXPECT_EQ(1u, GetMainFrameConsoleMessages().size());
+  EXPECT_EQ(GetMainFrameConsoleMessages().front(), kAbusiveWarnMessage);
 
   EXPECT_FALSE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
 }
diff --git a/chrome/browser/ui/cocoa/first_run_dialog.mm b/chrome/browser/ui/cocoa/first_run_dialog.mm
index 3696d85..ca7732aa4 100644
--- a/chrome/browser/ui/cocoa/first_run_dialog.mm
+++ b/chrome/browser/ui/cocoa/first_run_dialog.mm
@@ -4,6 +4,7 @@
 
 #import "chrome/browser/ui/cocoa/first_run_dialog.h"
 
+#include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/mac/bundle_locations.h"
 #import "base/mac/scoped_nsobject.h"
@@ -19,6 +20,7 @@
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/shell_integration.h"
 #include "chrome/browser/ui/cocoa/first_run_dialog_controller.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "components/search_engines/template_url_service.h"
 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
@@ -94,17 +96,23 @@
   return !first_run::IsMetricsReportingOptIn();
 }
 
+bool IsFirstRunEnabledForBuildType() {
+#if defined(GOOGLE_CHROME_BUILD)
+  return true;
+#else
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kForceUnofficialFirstRun);
+#endif
+}
+
 }  // namespace
 
 namespace first_run {
 
 bool ShowFirstRunDialog(Profile* profile) {
   bool dialog_shown = false;
-#if defined(GOOGLE_CHROME_BUILD)
-  dialog_shown = ShowFirstRunModal(profile);
-#else
-  (void)ShowFirstRunModal;  // Placate compiler.
-#endif
+  if (IsFirstRunEnabledForBuildType())
+    dialog_shown = ShowFirstRunModal(profile);
   // Set preference to show first run bubble and welcome page.
   // Only display the bubble if there is a default search provider.
   TemplateURLService* search_engines_model =
diff --git a/chrome/browser/ui/cocoa/first_run_dialog_controller.mm b/chrome/browser/ui/cocoa/first_run_dialog_controller.mm
index d95f601..0226e41 100644
--- a/chrome/browser/ui/cocoa/first_run_dialog_controller.mm
+++ b/chrome/browser/ui/cocoa/first_run_dialog_controller.mm
@@ -23,10 +23,10 @@
                                  l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
 }
 
-void MoveViewsDown(NSArray* views, CGFloat distance) {
+void MoveViewsVertically(NSArray* views, CGFloat distance) {
   for (NSView* view : views) {
     NSRect frame = view.frame;
-    frame.origin.y -= distance;
+    frame.origin.y += distance;
     [view setFrame:frame];
   }
 }
@@ -124,18 +124,35 @@
   [self.view addSubview:bottomSeparator];
   [self.view addSubview:startChromeButton];
 
-  // Now that the content view is constructed, fix the layout: since this view
-  // isn't using autolayout, if the widths of some of the subviews change
-  // because of localization, they need to be resized and perhaps repositioned,
-  // which is done here by |VerticallyReflowGroup()|.
-  CGFloat oldWidth = NSWidth([startChromeButton frame]);
-  cocoa_l10n_util::VerticallyReflowGroup(
-      @[ defaultBrowserCheckbox_, statsCheckbox_ ]);
+  // Now that the content view is constructed, fix the layout. The first step is
+  // to reflow the browser and stats checkbox texts, which can be quite lengthy
+  // in some locales. They may wrap onto additional lines, and in doing so cause
+  // the rest of the dialog to need to be rearranged.
+  {
+    CGFloat delta = cocoa_l10n_util::VerticallyReflowGroup(
+        @[ defaultBrowserCheckbox_, statsCheckbox_ ]);
+    if (delta) {
+      // If reflowing the checkboxes produced a height delta, move the
+      // checkboxes and the items above them in the content view upward, then
+      // grow the content view to match. This has the effect of moving
+      // everything visually-below the checkboxes downwards and expanding the
+      // window, leaving the vertical space the checkboxes need for their text.
+      MoveViewsVertically(
+          @[ defaultBrowserCheckbox_, statsCheckbox_, topSeparator, topBox ],
+          delta);
+      NSRect frame = [self.view frame];
+      frame.size.height += delta;
+      [self.view setAutoresizesSubviews:NO];
+      [self.view setFrame:frame];
+      [self.view setAutoresizesSubviews:YES];
+    }
+  }
 
   // The "Start Chrome" button needs to be sized to fit the localized string
   // inside it, but it should still be at the right-most edge of the dialog, so
   // any width added or subtracted by |sizeToFit| is added to its x coord, which
   // keeps its right edge where it was.
+  CGFloat oldWidth = NSWidth([startChromeButton frame]);
   [startChromeButton sizeToFit];
   NSRect frame = [startChromeButton frame];
   frame.origin.x += oldWidth - NSWidth([startChromeButton frame]);
@@ -146,7 +163,7 @@
   // view, and resize the content view itself so there isn't extra space.
   if (!defaultBrowserCheckboxVisible_) {
     CGFloat delta = NSHeight([defaultBrowserCheckbox_ frame]);
-    MoveViewsDown(@[ topBox, topSeparator ], delta);
+    MoveViewsVertically(@[ topBox, topSeparator ], -delta);
     NSRect frame = [self.view frame];
     frame.size.height -= delta;
     [self.view setAutoresizesSubviews:NO];
diff --git a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
index 332d7d5..9e48fe1 100644
--- a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
@@ -9,6 +9,7 @@
 #include "ash/public/cpp/window_properties.h"
 #include "ash/public/cpp/window_state_type.h"
 #include "ash/public/interfaces/window_pin_type.mojom.h"
+#include "ash/public/interfaces/window_properties.mojom.h"
 #include "ash/public/interfaces/window_state_type.mojom.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
@@ -79,6 +80,10 @@
     converter->RegisterPrimitiveProperty(
         ash::kWindowPinTypeKey, ash::mojom::kWindowPinType_Property,
         base::Bind(&ash::IsValidWindowPinType));
+    converter->RegisterPrimitiveProperty(
+        ash::kWindowPositionManagedTypeKey,
+        ash::mojom::kWindowPositionManaged_Property,
+        aura::PropertyConverter::CreateAcceptAnyValueCallback());
     converter->RegisterStringProperty(
         ash::kShelfIDKey, ui::mojom::WindowManager::kShelfID_Property);
 
diff --git a/chrome/browser/ui/views/frame/browser_frame_ash.cc b/chrome/browser/ui/views/frame/browser_frame_ash.cc
index cd39767..61ff458 100644
--- a/chrome/browser/ui/views/frame/browser_frame_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_ash.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/public/cpp/window_properties.h"
 #include "ash/shell.h"
 #include "ash/wm/window_properties.h"
 #include "ash/wm/window_state.h"
@@ -153,8 +154,6 @@
 void BrowserFrameAsh::SetWindowAutoManaged() {
   // For browser window in Chrome OS, we should only enable the auto window
   // management logic for tabbed browser.
-  if (!browser_view_->browser()->is_type_popup()) {
-    ash::wm::GetWindowState(GetNativeWindow())
-        ->set_window_position_managed(true);
-  }
+  if (!browser_view_->browser()->is_type_popup())
+    GetNativeWindow()->SetProperty(ash::kWindowPositionManagedTypeKey, true);
 }
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index b2b56a26..f8ca9841 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -64,6 +64,7 @@
 #if defined(OS_CHROMEOS)
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
+#include "ash/public/cpp/window_properties.h"
 #include "ash/shell.h"
 #include "ash/wm/cursor_manager_test_api.h"
 #include "ash/wm/root_window_finder.h"
@@ -766,7 +767,7 @@
 
 #if defined(OS_CHROMEOS)
 bool IsWindowPositionManaged(aura::Window* window) {
-  return ash::wm::GetWindowState(window)->window_position_managed();
+  return window->GetProperty(ash::kWindowPositionManagedTypeKey);
 }
 bool HasUserChangedWindowPositionOrSize(aura::Window* window) {
   return ash::wm::GetWindowState(window)->bounds_changed_by_user();
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index 1a097d14..7a12078 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/extensions/extensions_ui.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
@@ -257,6 +258,14 @@
                              IDS_MD_EXTENSIONS_SHORTCUT_SCOPE_IN_CHROME);
   source->AddLocalizedString("shortcutTypeAShortcut",
                              IDS_MD_EXTENSIONS_TYPE_A_SHORTCUT);
+  source->AddLocalizedString("shortcutInstructions",
+                             IDS_MD_EXTENSIONS_SHORTCUT_INSTRUCTIONS);
+  source->AddLocalizedString("shortcutIncludeStartModifier",
+                             IDS_MD_EXTENSIONS_INCLUDE_START_MODIFIER);
+  source->AddLocalizedString("shortcutTooManyModifiers",
+                             IDS_MD_EXTENSIONS_TOO_MANY_MODIFIERS);
+  source->AddLocalizedString("shortcutNeedCharacter",
+                             IDS_MD_EXTENSIONS_NEED_CHARACTER);
   source->AddString(
       "suspiciousInstallHelpUrl",
       base::ASCIIToUTF16(google_util::AppendGoogleLocaleParam(
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc b/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
index 3a3df7b..c8dc9dd 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ash/public/cpp/window_properties.h"
 #include "ash/scoped_root_window_for_new_windows.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/window_positioner.h"
 #include "ash/wm/window_resizer.h"
-#include "ash/wm/window_state.h"
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/browser/ui/browser.h"
@@ -39,8 +39,8 @@
       chrome::CreateBrowserWithAuraTestWindowForParams(base::WrapUnique(window),
                                                        params);
   if (!browser->is_type_popup()) {
-    ash::wm::GetWindowState(browser->window()->GetNativeWindow())
-        ->set_window_position_managed(true);
+    browser->window()->GetNativeWindow()->SetProperty(
+        ash::kWindowPositionManagedTypeKey, true);
   }
   return browser;
 }
diff --git a/chrome/browser/vr/model/model.h b/chrome/browser/vr/model/model.h
index 07df52e6de..90fd6a2 100644
--- a/chrome/browser/vr/model/model.h
+++ b/chrome/browser/vr/model/model.h
@@ -28,6 +28,9 @@
   ControllerModel controller;
   ReticleModel reticle;
 
+  bool experimental_features_enabled = false;
+  bool incognito = false;
+
   std::vector<OmniboxSuggestion> omnibox_suggestions;
 };
 
diff --git a/chrome/browser/vr/test/ui_scene_manager_test.cc b/chrome/browser/vr/test/ui_scene_manager_test.cc
index c8a341a9..ee60365 100644
--- a/chrome/browser/vr/test/ui_scene_manager_test.cc
+++ b/chrome/browser/vr/test/ui_scene_manager_test.cc
@@ -85,6 +85,11 @@
   return IsElementFacingCamera(element);
 }
 
+void UiSceneManagerTest::SetIncognito(bool incognito) {
+  model_->incognito = incognito;
+  manager_->SetIncognito(incognito);
+}
+
 void UiSceneManagerTest::VerifyElementsVisible(
     const std::string& trace_context,
     const std::set<UiElementName>& names) const {
diff --git a/chrome/browser/vr/test/ui_scene_manager_test.h b/chrome/browser/vr/test/ui_scene_manager_test.h
index b368b17b..95d2c0c4 100644
--- a/chrome/browser/vr/test/ui_scene_manager_test.h
+++ b/chrome/browser/vr/test/ui_scene_manager_test.h
@@ -50,6 +50,8 @@
 
   bool IsVisible(UiElementName name) const;
 
+  void SetIncognito(bool incognito);
+
   // Verify that only the elements in the set are visible.
   void VerifyElementsVisible(const std::string& debug_name,
                              const std::set<UiElementName>& names) const;
diff --git a/chrome/browser/vr/ui.cc b/chrome/browser/vr/ui.cc
index b8e0340..524746f5 100644
--- a/chrome/browser/vr/ui.cc
+++ b/chrome/browser/vr/ui.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/vr/ui_scene.h"
 #include "chrome/browser/vr/ui_scene_manager.h"
 #include "chrome/browser/vr/vr_shell_renderer.h"
+#include "chrome/common/chrome_features.h"
 
 namespace vr {
 
@@ -33,6 +34,8 @@
       weak_ptr_factory_(this) {
   model_->started_for_autopresentation =
       ui_initial_state.web_vr_autopresentation_expected;
+  model_->experimental_features_enabled =
+      base::FeatureList::IsEnabled(features::kExperimentalVRFeatures);
 }
 
 Ui::~Ui() = default;
@@ -56,6 +59,7 @@
 }
 
 void Ui::SetIncognito(bool enabled) {
+  model_->incognito = enabled;
   scene_manager_->SetIncognito(enabled);
 }
 
diff --git a/chrome/browser/vr/ui_scene_manager.cc b/chrome/browser/vr/ui_scene_manager.cc
index 804255f..b009b200 100644
--- a/chrome/browser/vr/ui_scene_manager.cc
+++ b/chrome/browser/vr/ui_scene_manager.cc
@@ -48,7 +48,6 @@
 #include "chrome/browser/vr/ui_scene_constants.h"
 #include "chrome/browser/vr/vector_icons/vector_icons.h"
 #include "chrome/browser/vr/vr_gl_util.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/vector_icons/vector_icons.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -556,20 +555,23 @@
 }
 
 void UiSceneManager::CreateVoiceSearchUiGroup(Model* model) {
-  std::unique_ptr<UiElement> element;
-
-  auto voice_search_button = base::MakeUnique<Button>(
+  std::unique_ptr<UiElement> element = base::MakeUnique<Button>(
       base::Bind(&UiSceneManager::OnVoiceSearchButtonClicked,
                  base::Unretained(this)),
       base::MakeUnique<VectorIconButtonTexture>(vector_icons::kMicrophoneIcon));
-  voice_search_button_ = voice_search_button.get();
-  element = std::move(voice_search_button);
   element->set_name(kVoiceSearchButton);
   element->set_draw_phase(kPhaseForeground);
   element->SetTranslate(kVoiceSearchButtonXOffset, 0.f, 0.f);
   element->SetSize(kCloseButtonWidth, kCloseButtonHeight);
   element->set_x_anchoring(XAnchoring::XRIGHT);
-  control_elements_.push_back(element.get());
+  element->AddBinding(base::MakeUnique<Binding<bool>>(
+      base::Bind(
+          [](Model* m) {
+            return !m->incognito && m->experimental_features_enabled;
+          },
+          base::Unretained(model)),
+      base::Bind([](UiElement* e, const bool& v) { e->SetVisible(v); },
+                 element.get())));
   scene_->AddUiElement(kUrlBar, std::move(element));
 
   auto speech_recognition_prompt = base::MakeUnique<UiElement>();
@@ -1003,10 +1005,6 @@
     element->SetVisible(controls_visible);
   }
 
-  if (!base::FeatureList::IsEnabled(features::kExperimentalVRFeatures)) {
-    voice_search_button_->SetVisible(false);
-  }
-
   // Close button is a special control element that needs to be hidden when in
   // WebVR, but it needs to be visible when in cct or fullscreen.
   close_button_->SetVisible(browsing_mode && (fullscreen_ || in_cct_));
diff --git a/chrome/browser/vr/ui_scene_manager.h b/chrome/browser/vr/ui_scene_manager.h
index e6f41fd..ffb7a311 100644
--- a/chrome/browser/vr/ui_scene_manager.h
+++ b/chrome/browser/vr/ui_scene_manager.h
@@ -207,7 +207,6 @@
   Rect* ceiling_ = nullptr;
   Grid* floor_ = nullptr;
   UiElement* close_button_ = nullptr;
-  UiElement* voice_search_button_ = nullptr;
   UrlBar* url_bar_ = nullptr;
   TransientElement* webvr_url_toast_transient_parent_ = nullptr;
   WebVrUrlToast* webvr_url_toast_ = nullptr;
diff --git a/chrome/browser/vr/ui_scene_manager_unittest.cc b/chrome/browser/vr/ui_scene_manager_unittest.cc
index 269821d9..71ba2d9 100644
--- a/chrome/browser/vr/ui_scene_manager_unittest.cc
+++ b/chrome/browser/vr/ui_scene_manager_unittest.cc
@@ -196,7 +196,7 @@
   GetBackgroundColor(&fullscreen_background);
   EXPECT_NE(initial_background, fullscreen_background);
 
-  manager_->SetIncognito(true);
+  SetIncognito(true);
 
   // Make sure background has changed for incognito.
   SkColor incognito_background = SK_ColorBLACK;
@@ -204,7 +204,7 @@
   EXPECT_NE(fullscreen_background, incognito_background);
   EXPECT_NE(initial_background, incognito_background);
 
-  manager_->SetIncognito(false);
+  SetIncognito(false);
   SkColor no_longer_incognito_background = SK_ColorBLACK;
   GetBackgroundColor(&no_longer_incognito_background);
   EXPECT_EQ(fullscreen_background, no_longer_incognito_background);
@@ -214,17 +214,40 @@
   GetBackgroundColor(&no_longer_fullscreen_background);
   EXPECT_EQ(initial_background, no_longer_fullscreen_background);
 
-  manager_->SetIncognito(true);
+  SetIncognito(true);
   SkColor incognito_again_background = SK_ColorBLACK;
   GetBackgroundColor(&incognito_again_background);
   EXPECT_EQ(incognito_background, incognito_again_background);
 
-  manager_->SetIncognito(false);
+  SetIncognito(false);
   SkColor no_longer_incognito_again_background = SK_ColorBLACK;
   GetBackgroundColor(&no_longer_incognito_again_background);
   EXPECT_EQ(initial_background, no_longer_incognito_again_background);
 }
 
+TEST_F(UiSceneManagerTest, VoiceSearchHiddenInIncognito) {
+  MakeManager(kNotInCct, kNotInWebVr);
+
+  model_->experimental_features_enabled = true;
+  EXPECT_TRUE(OnBeginFrame());
+  EXPECT_TRUE(IsVisible(kVoiceSearchButton));
+
+  SetIncognito(true);
+  EXPECT_TRUE(OnBeginFrame());
+  EXPECT_FALSE(IsVisible(kVoiceSearchButton));
+
+  // If experimental VR features are disabled, then we should never show the
+  // button, regardless of whether or not we're in incognito mode.
+  model_->experimental_features_enabled = false;
+  SetIncognito(false);
+  EXPECT_TRUE(OnBeginFrame());
+  EXPECT_FALSE(IsVisible(kVoiceSearchButton));
+
+  SetIncognito(true);
+  EXPECT_TRUE(OnBeginFrame());
+  EXPECT_FALSE(IsVisible(kVoiceSearchButton));
+}
+
 TEST_F(UiSceneManagerTest, WebVrAutopresented) {
   MakeAutoPresentedManager();
 
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 4d677aea..1f2efbe 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -899,6 +899,10 @@
 // Enables Translate experimental new UX which replaces the infobar.
 const char kEnableTranslateNewUX[] = "enable-translate-new-ux";
 
+// Forces the first-run flow even on unofficial builds. Note that this still
+// requires a fresh user-data-dir.
+const char kForceUnofficialFirstRun[] = "force-unofficial-first-run";
+
 // Shows a notification when quitting Chrome with hosted apps running. Default
 // behavior is to also quit all hosted apps.
 const char kHostedAppQuitNotification[] = "enable-hosted-app-quit-notification";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index a2149a4..a8cbb0f 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -273,6 +273,7 @@
 extern const char kEnableMacViewsNativeAppWindows[];
 extern const char kEnableTranslateNewUX[];
 extern const char kEnableUserMetrics[];
+extern const char kForceUnofficialFirstRun[];
 extern const char kHostedAppQuitNotification[];
 extern const char kMetricsClientID[];
 extern const char kRelauncherProcess[];
diff --git a/chrome/test/data/safe_browsing/download_protection/navigation_observer/landing_referrer.html b/chrome/test/data/safe_browsing/download_protection/navigation_observer/landing_referrer.html
index d7f29275..494c885 100644
--- a/chrome/test/data/safe_browsing/download_protection/navigation_observer/landing_referrer.html
+++ b/chrome/test/data/safe_browsing/download_protection/navigation_observer/landing_referrer.html
@@ -13,5 +13,8 @@
     <a id="link_to_landing" href="landing.html">
       Link to landing
     </a><br>
+    <a id="link_to_landing_with_empty_fragment" href="landing.html#">
+      Link to landing with empty fragment
+    </a><br>
   </body>
 </html>
diff --git a/chrome/test/data/safe_browsing/download_protection/navigation_observer/navigation_observer_tests.html b/chrome/test/data/safe_browsing/download_protection/navigation_observer/navigation_observer_tests.html
index d8131247..6dcc73c 100644
--- a/chrome/test/data/safe_browsing/download_protection/navigation_observer/navigation_observer_tests.html
+++ b/chrome/test/data/safe_browsing/download_protection/navigation_observer/navigation_observer_tests.html
@@ -145,5 +145,9 @@
       Download via HTML5 file system API without trigger navigation
     </button><br>
 
+    <a id="attribution_should_ignore_url_fragments" href="page_before_landing_referrer.html">
+      Attribution should ignore url fragments.
+    </a><br>
+
   </body>
 </html>
diff --git a/chrome/test/data/safe_browsing/download_protection/navigation_observer/page_before_landing_referrer.html b/chrome/test/data/safe_browsing/download_protection/navigation_observer/page_before_landing_referrer.html
index 1c898f7..f52f5a0 100644
--- a/chrome/test/data/safe_browsing/download_protection/navigation_observer/page_before_landing_referrer.html
+++ b/chrome/test/data/safe_browsing/download_protection/navigation_observer/page_before_landing_referrer.html
@@ -15,5 +15,8 @@
     <a id="link_to_landing_referrer" href="landing_referrer.html">
       Link to landing referrer
     </a><br>
+    <a id="link_to_landing_referrer_with_query_and_fragment" href="landing_referrer.html?bar=foo#baz">
+      Link to landing referrer with query and fragment
+    </a><br>
   </body>
 </html>
diff --git a/chrome/test/data/webui/extensions/extension_shortcut_input_test.js b/chrome/test/data/webui/extensions/extension_shortcut_input_test.js
index 4a86e28..e360b114 100644
--- a/chrome/test/data/webui/extensions/extension_shortcut_input_test.js
+++ b/chrome/test/data/webui/extensions/extension_shortcut_input_test.js
@@ -26,7 +26,7 @@
   }
 
   /** @enum {string} */
-  var TestNames = {
+  const TestNames = {
     Basic: 'basic',
   };
 
@@ -44,12 +44,9 @@
     });
 
     test(assert(TestNames.Basic), function() {
-      var field = input.$['input'];
-      var fieldText = function() {
-        return field.value;
-      };
-      expectEquals('', fieldText());
-      var isClearVisible =
+      const field = input.$['input'];
+      expectEquals('', field.value);
+      const isClearVisible =
           extension_test_util.isVisible.bind(null, input, '#clear', false);
       expectFalse(isClearVisible());
 
@@ -60,24 +57,36 @@
             assertTrue(arg);
             input.delegate.reset();
 
-            expectEquals('', fieldText());
+            expectEquals('', field.value);
             expectFalse(isClearVisible());
 
+            // Press character.
+            MockInteractions.keyDownOn(field, 'A', []);
+            expectEquals('', field.value);
+            expectTrue(field.errorMessage.startsWith('Include'));
+            // Add shift to character.
+            MockInteractions.keyDownOn(field, 'A', ['shift']);
+            expectEquals('', field.value);
+            expectTrue(field.errorMessage.startsWith('Include'));
             // Press ctrl.
             MockInteractions.keyDownOn(field, 17, ['ctrl']);
-            expectEquals('Ctrl', fieldText());
+            expectEquals('Ctrl', field.value);
+            expectEquals('Need a character', field.errorMessage);
             // Add shift.
             MockInteractions.keyDownOn(field, 16, ['ctrl', 'shift']);
-            expectEquals('Ctrl + Shift', fieldText());
+            expectEquals('Ctrl + Shift', field.value);
+            expectEquals('Need a character', field.errorMessage);
             // Remove shift.
             MockInteractions.keyUpOn(field, 16, ['ctrl']);
-            expectEquals('Ctrl', fieldText());
+            expectEquals('Ctrl', field.value);
+            expectEquals('Need a character', field.errorMessage);
             // Add alt (ctrl + alt is invalid).
             MockInteractions.keyDownOn(field, 18, ['ctrl', 'alt']);
-            expectEquals('invalid', fieldText());
+            expectEquals('Ctrl', field.value);
             // Remove alt.
             MockInteractions.keyUpOn(field, 18, ['ctrl']);
-            expectEquals('Ctrl', fieldText());
+            expectEquals('Ctrl', field.value);
+            expectEquals('Need a character', field.errorMessage);
 
             // Add 'A'. Once a valid shortcut is typed (like Ctrl + A), it is
             // committed.
@@ -87,7 +96,7 @@
           .then((arg) => {
             input.delegate.reset();
             expectDeepEquals(['itemid', 'Command', 'Ctrl+A'], arg);
-            expectEquals('Ctrl + A', fieldText());
+            expectEquals('Ctrl + A', field.value);
             expectEquals('Ctrl+A', input.shortcut);
             expectTrue(isClearVisible());
 
diff --git a/chrome/test/data/webui/net_internals/log_util.js b/chrome/test/data/webui/net_internals/log_util.js
index 867aaae..46e36b3f 100644
--- a/chrome/test/data/webui/net_internals/log_util.js
+++ b/chrome/test/data/webui/net_internals/log_util.js
@@ -34,8 +34,6 @@
    * Starts creating the log dump.
    */
   start: function() {
-    this.initialPrivacyStripping_ =
-        SourceTracker.getInstance().getPrivacyStripping();
     log_util.createLogDumpAsync(this.userComments_,
                                 this.onLogDumpCreated.bind(this), true);
   },
@@ -46,10 +44,7 @@
    * @param {string} logDumpText Log dump, as a string.
    */
   onLogDumpCreated: function(logDumpText) {
-    expectEquals(this.initialPrivacyStripping_,
-                 SourceTracker.getInstance().getPrivacyStripping());
     expectEquals('Log loaded.', log_util.loadLogFile(logDumpText, 'log.txt'));
-    expectFalse(SourceTracker.getInstance().getPrivacyStripping());
 
     NetInternalsTest.expectStatusViewNodeVisible(LoadedStatusView.MAIN_BOX_ID);
 
@@ -123,7 +118,6 @@
    */
   onLogReceived_: function(logDumpText) {
     assertEquals('string', typeof logDumpText);
-    expectTrue(SourceTracker.getInstance().getPrivacyStripping());
 
     var expectedResult = 'Log loaded.';
 
@@ -134,7 +128,6 @@
 
     logDumpText = logDumpText.substring(0, logDumpText.length - this.truncate_);
     expectEquals(expectedResult, log_util.loadLogFile(logDumpText, 'log.txt'));
-    expectFalse(SourceTracker.getInstance().getPrivacyStripping());
 
     NetInternalsTest.expectStatusViewNodeVisible(LoadedStatusView.MAIN_BOX_ID);
 
@@ -201,11 +194,6 @@
   NetInternalsTest.checkTabLinkVisibility(tabVisibilityState, false);
 }
 
-function checkPrivacyStripping(expectedValue) {
-  expectEquals(expectedValue,
-               SourceTracker.getInstance().getPrivacyStripping());
-}
-
 /**
  * Checks the currently active view.
  * @param {string} id ID of the view that should be active.
@@ -222,7 +210,6 @@
  */
 TEST_F('NetInternalsTest', 'netInternalsLogUtilExportImport', function() {
   expectFalse(g_browser.isDisabled());
-  expectTrue(SourceTracker.getInstance().getPrivacyStripping());
   NetInternalsTest.expectStatusViewNodeVisible(CaptureStatusView.MAIN_BOX_ID);
 
   var taskQueue = new NetInternalsTest.TaskQueue(true);
@@ -269,7 +256,6 @@
       NetInternalsTest.expectStatusViewNodeVisible.bind(
           null, HaltedStatusView.MAIN_BOX_ID));
   taskQueue.addFunctionTask(checkViewsAfterLogLoaded);
-  taskQueue.addFunctionTask(checkPrivacyStripping.bind(null, true));
   taskQueue.addFunctionTask(checkActiveView.bind(null, EventsView.TAB_ID));
   taskQueue.run();
 
diff --git a/chrome/test/data/webui/net_internals/log_view_painter.js b/chrome/test/data/webui/net_internals/log_view_painter.js
index 85812af..e93916c 100644
--- a/chrome/test/data/webui/net_internals/log_view_painter.js
+++ b/chrome/test/data/webui/net_internals/log_view_painter.js
@@ -7,148 +7,6 @@
 
 // Anonymous namespace
 (function() {
-
-/**
- * Check that stripPrivacyInfo correctly removes cookies and login information.
- */
-TEST_F('NetInternalsTest', 'netInternalsLogViewPainterStripInfo', function() {
-  // Each entry in |expectations| is a list consisting of a header element
-  // before and after applying the filter.  If the second entry is null, the
-  // element should be unmodified.
-  var expectations = [
-    ['set-cookie: blah', 'set-cookie: [4 bytes were stripped]'],
-    ['set-cookie2: blah', 'set-cookie2: [4 bytes were stripped]'],
-    ['cookie: blah', 'cookie: [4 bytes were stripped]'],
-    ['authorization: NTLM blah', 'authorization: NTLM [4 bytes were stripped]'],
-
-    ['proxy-authorization: Basic blah',
-     'proxy-authorization: Basic [4 bytes were stripped]'],
-
-    ['WWW-Authenticate: Basic realm="Something, or another"', null],
-
-    ['WWW-Authenticate: Negotiate blah-token-blah',
-     'WWW-Authenticate: Negotiate [15 bytes were stripped]'],
-
-    ['WWW-Authenticate: NTLM asdllk2j3l423lk4j23l4kj',
-     'WWW-Authenticate: NTLM [23 bytes were stripped]'],
-
-    ['WWW-Authenticate: Kerberos , Negotiate asdfasdfasdfasfa', null],
-    ['WWW-Authenticate: Kerberos, Negotiate asdfasdfasdfasfa', null],
-    ['WWW-Authenticate: Digest , Negotiate asdfasdfasdfasfa', null],
-    ['WWW-Authenticate: Digest realm="Foo realm", Negotiate asdf', null],
-    ['WWW-Authenticate: Kerberos,Digest,Basic', null],
-    ['WWW-Authenticate: Digest realm="asdfasdf", nonce=5, qop="auth"', null],
-    ['WWW-Authenticate: Basic realm=foo,foo=bar , Digest ', null],
-    ['Proxy-Authenticate: Basic realm="Something, or another"', null],
-
-    ['Proxy-Authenticate: Negotiate blah-token-blah',
-     'Proxy-Authenticate: Negotiate [15 bytes were stripped]'],
-
-    ['Proxy-Authenticate: NTLM asdllk2j3l423lk4j23l4kj',
-     'Proxy-Authenticate: NTLM [23 bytes were stripped]'],
-
-    ['Proxy-Authenticate: Kerberos , Negotiate asdfasdfa', null],
-    ['Proxy-Authenticate: Kerberos, Negotiate asdfasdfa', null],
-    ['Proxy-Authenticate: Digest , Negotiate asdfasdfa', null],
-    ['Proxy-Authenticate: Digest realm="Foo realm", Negotiate asdfasdfa', null],
-    ['Proxy-Authenticate: Kerberos,Digest,Basic', null],
-    ['Proxy-Authenticate: Digest realm="asdfasdf", nonce=5, qop="auth"', null],
-    ['Proxy-Authenticate: Basic realm=foo,foo=bar , Digest ', null],
-
-    ['cookie: [4 bytes were stripped]', null],
-    ['cookie: Stuff [4 bytes were stripped]',
-     'cookie: [29 bytes were stripped]'],
-    ['cookie: [4 bytes were stripped] Stuff',
-     'cookie: [29 bytes were stripped]'],
-    ['set-cookie: [4 bytes were stripped]', null],
-    ['Proxy-Authenticate: NTLM [23 bytes were stripped]', null],
-  ];
-
-  for (var i = 0; i < expectations.length; ++i) {
-    var expectation = expectations[i];
-    // Position within params.headers where the authentication information goes.
-    for (var position = 0; position < 3; ++position) {
-      var entry = {
-        'params': {
-          'headers': [
-            'Host: clients1.google.com',
-            'Connection: keep-alive',
-            'User-Agent: Mozilla/5.0'
-          ],
-          'line': 'GET / HTTP/1.1\r\n'
-        },
-        'phase': EventPhase.PHASE_BEGIN,
-        'source': {'id': 329, 'type': EventSourceType.URL_REQUEST},
-        'time': '22468349',
-        'type': EventSourceType.URL_REQUEST
-      };
-
-      entry.params.headers[position] = expectation[0];
-      var stripped = stripPrivacyInfo(entry);
-      // The entry should be duplicated, so the original still has the deleted
-      // information.
-      expectNotEquals(stripped, entry);
-      if (expectation[1] == null) {
-        expectEquals(expectation[0], stripped.params.headers[position]);
-      } else {
-        expectEquals(expectation[1], stripped.params.headers[position]);
-      }
-    }
-  }
-
-  // Test with HTTP/2 request headers, which use an object rather than an array.
-  var spdyRequestHeadersEntry = {
-    'params': {
-      'headers': {
-        ':host': 'clients1.google.com',
-        ':method': 'GET',
-        ':path': '/cute/cat/pictures/',
-        'cookie': 'blah'
-      },
-      'line': 'GET / HTTP/1.1\r\n'
-    },
-    'phase': EventPhase.PHASE_BEGIN,
-    'source': {'id': 329, 'type': EventSourceType.URL_REQUEST},
-    'time': '22468349',
-    'type': EventSourceType.HTTP_TRANSACTION_HTTP2_SEND_REQUEST_HEADERS
-  };
-  var strippedSpdyRequestHeadersEntry =
-      stripPrivacyInfo(spdyRequestHeadersEntry);
-  expectEquals('cookie: [4 bytes were stripped]',
-               strippedSpdyRequestHeadersEntry.params.headers[3]);
-
-  testDone();
-});
-
-/**
- * Check that stripPrivacyInfo correctly removes HTTP/2 GOAWAY frame debug data.
- */
-TEST_F('NetInternalsTest', 'netInternalsLogViewPainterStripGoAway', function() {
-  var entry = {
-    'params': {
-      'active_streams': 1,
-      'debug_data': 'potentially privacy sensitive information',
-      'last_accepted_stream_id': 1,
-      'status': 0,
-      'unclaimed_streams': 0,
-    },
-    'phase': 0,
-    'source': {'id': 404, 'type': 5},
-    'time': '49236780',
-    'type': EventType.HTTP2_SESSION_GOAWAY,
-  };
-
-  var stripped = stripPrivacyInfo(entry);
-
-  // The entry should be duplicated, so the original still has the deleted
-  // information.
-  expectNotEquals(stripped, entry);
-  expectEquals('[41 bytes were stripped]',
-               stripped.params.debug_data);
-
-  testDone();
-});
-
 /**
  * Tests the formatting of log entries to fixed width text.
  */
@@ -168,7 +26,6 @@
 
     var tablePrinter =
         createLogEntryTablePrinter(testCase.logEntries,
-                                   testCase.privacyStripping,
                                    baseTime, testCase.logCreationTime);
     tablePrinter.toText(0, div);
 
@@ -193,12 +50,6 @@
   runTestCase(painterTestCheckedCert());
   runTestCase(painterTestProxyConfigOneProxyAllSchemes());
   runTestCase(painterTestProxyConfigTwoProxiesAllSchemes());
-  runTestCase(painterTestDontStripCookiesURLRequest());
-  runTestCase(painterTestStripCookiesURLRequest());
-  runTestCase(painterTestDontStripCookiesSPDYSession());
-  runTestCase(painterTestStripCookiesSPDYSession());
-  runTestCase(painterTestSpdyURLRequestDontStripCookies());
-  runTestCase(painterTestSpdyURLRequestStripCookies());
   runTestCase(painterTestExtraCustomParameter());
   runTestCase(painterTestMissingCustomParameter());
   runTestCase(painterTestInProgressURLRequest());
@@ -1736,252 +1587,6 @@
 }
 
 /**
- * Tests that cookies are NOT stripped from URLRequests when stripping is
- * disabled.
- */
-function painterTestDontStripCookiesURLRequest() {
-  var testCase = {};
-  testCase.tickOffset = '1337911098139';
-
-  testCase.logEntries = [
-    {
-      'params': {
-        'headers': [
-          'HTTP/1.1 301 Moved Permanently',
-          'Cache-Control: private',
-          'Content-Length: 23',
-          'Content-Type: text/html',
-          'Location: http://msdn.microsoft.com',
-          'Server: Microsoft-IIS/7.5',
-          'Set-Cookie: MyMagicPony',
-          'P3P: CP=\"ALL\"',
-          'X-Powered-By: ASP.NET',
-          'X-UA-Compatible: IE=EmulateIE7',
-          'Date: Tue, 05 Jun 2012 21:06:45 GMT',
-          'Connection: close'
-        ]
-      },
-      'phase': EventPhase.PHASE_NONE,
-      'source': {
-        'id': 829,
-        'type': EventSourceType.URL_REQUEST
-      },
-      'time': '1019307339',
-      'type': EventType.HTTP_TRANSACTION_READ_RESPONSE_HEADERS
-    },
-    {
-      'params': {
-        'headers': [
-          'Host: msdn.microsoft.com',
-          'Connection: keep-alive',
-          'User-Agent: Mozilla/5.0',
-          'Accept: text/html',
-          'Accept-Encoding: gzip,deflate',
-          'Accept-Language: en-US,en;q=0.8',
-          'Accept-Charset: ISO-8859-1',
-          'Cookie: MyMagicPony'
-        ],
-        'line': 'GET / HTTP/1.1\r\n'
-      },
-      'phase': EventPhase.PHASE_NONE,
-      'source': {
-        'id': 829,
-        'type': EventSourceType.URL_REQUEST
-      },
-      'time': '1019307458',
-      'type': EventType.HTTP_TRANSACTION_SEND_REQUEST_HEADERS
-    }
-  ];
-
-  testCase.expectedText =
-'t=1338930405478 [st=  0]  HTTP_TRANSACTION_READ_RESPONSE_HEADERS\n' +
-'                          --> HTTP/1.1 301 Moved Permanently\n' +
-'                              Cache-Control: private\n' +
-'                              Content-Length: 23\n' +
-'                              Content-Type: text/html\n' +
-'                              Location: http://msdn.microsoft.com\n' +
-'                              Server: Microsoft-IIS/7.5\n' +
-'                              Set-Cookie: MyMagicPony\n' +
-'                              P3P: CP="ALL"\n' +
-'                              X-Powered-By: ASP.NET\n' +
-'                              X-UA-Compatible: IE=EmulateIE7\n' +
-'                              Date: Tue, 05 Jun 2012 21:06:45 GMT\n' +
-'                              Connection: close\n' +
-'t=1338930405597 [st=119]  HTTP_TRANSACTION_SEND_REQUEST_HEADERS\n' +
-'                          --> GET / HTTP/1.1\n' +
-'                              Host: msdn.microsoft.com\n' +
-'                              Connection: keep-alive\n' +
-'                              User-Agent: Mozilla/5.0\n' +
-'                              Accept: text/html\n' +
-'                              Accept-Encoding: gzip,deflate\n' +
-'                              Accept-Language: en-US,en;q=0.8\n' +
-'                              Accept-Charset: ISO-8859-1\n' +
-'                              Cookie: MyMagicPony';
-
-  return testCase;
-}
-
-/**
- * Tests that cookies are stripped from URLRequest when stripping is enabled.
- */
-function painterTestStripCookiesURLRequest() {
-  var testCase = painterTestDontStripCookiesURLRequest();
-  testCase.privacyStripping = true;
-  testCase.expectedText =
-      testCase.expectedText.replace(/MyMagicPony/g, '[11 bytes were stripped]');
-  return testCase;
-}
-
-/**
- * Tests that cookies are NOT stripped from HTTP/2 sessions when stripping is
- * not enabled. This test data was pieced together in order to get a "cookie"
- * and "set-cookie" header.
- */
-function painterTestDontStripCookiesSPDYSession() {
-  var testCase = {};
-  testCase.tickOffset = '1337911097783';
-
-  testCase.logEntries = [
-    {
-      'params': {
-        'flags': 1,
-        'headers': [
-          ':host: mail.google.com',
-          ':method: GET',
-          ':path: /a/google.com',
-          ':scheme: https',
-          ':version: HTTP/1.1',
-          'accept: text/html',
-          'accept-charset: ISO-8859-1',
-          'accept-encoding: gzip,deflate',
-          'accept-language: en-US,en;q=0.8',
-          'cookie: MyMagicPony',
-          'user-agent: Mozilla/5.0'
-        ],
-        'stream_id': 1
-      },
-      'phase': EventPhase.PHASE_NONE,
-      'source': {
-        'id': 153,
-        'type': EventSourceType.HTTP2_SESSION
-      },
-      'time': '1012984638',
-      'type': EventType.HTTP2_SESSION_SEND_HEADERS
-    },
-    {
-      'params': {
-        'flags': 0,
-        'headers': [
-          ':status: 204 No Content',
-          ':version: HTTP/1.1',
-          'date: Tue, 05 Jun 2012 19:21:30 GMT',
-          'server: GSE',
-          'set-cookie: MyMagicPony',
-          'x-random-header: sup'
-        ],
-        'stream_id': 5
-      },
-      'phase': EventPhase.PHASE_NONE,
-      'source': {
-        'id': 153,
-        'type': EventSourceType.HTTP2_SESSION
-      },
-      'time': '1012992266',
-      'type': EventType.HTTP2_SESSION_RECV_HEADERS
-    }
-  ];
-
-  testCase.expectedText =
-    't=1338924082421 [st=   0]  HTTP2_SESSION_SEND_HEADERS\n' +
-    '                           --> flags = 1\n' +
-    '                           --> :host: mail.google.com\n' +
-    '                               :method: GET\n' +
-    '                               :path: /a/google.com\n' +
-    '                               :scheme: https\n' +
-    '                               :version: HTTP/1.1\n' +
-    '                               accept: text/html\n' +
-    '                               accept-charset: ISO-8859-1\n' +
-    '                               accept-encoding: gzip,deflate\n' +
-    '                               accept-language: en-US,en;q=0.8\n' +
-    '                               cookie: MyMagicPony\n' +
-    '                               user-agent: Mozilla/5.0\n' +
-    '                           --> stream_id = 1\n' +
-    't=1338924090049 [st=7628]  HTTP2_SESSION_RECV_HEADERS\n' +
-    '                           --> flags = 0\n' +
-    '                           --> :status: 204 No Content\n' +
-    '                               :version: HTTP/1.1\n' +
-    '                               date: Tue, 05 Jun 2012 19:21:30 GMT\n' +
-    '                               server: GSE\n' +
-    '                               set-cookie: MyMagicPony\n' +
-    '                               x-random-header: sup\n' +
-    '                           --> stream_id = 5';
-
-  return testCase;
-}
-
-/**
- * Tests that cookies are stripped from HTTP/2 sessions when stripping is
- * enabled.
- */
-function painterTestStripCookiesSPDYSession() {
-  var testCase = painterTestDontStripCookiesSPDYSession();
-  testCase.privacyStripping = true;
-  testCase.expectedText =
-      testCase.expectedText.replace(/MyMagicPony/g, '[11 bytes were stripped]');
-  return testCase;
-}
-
-/**
- * Tests that cookies are NOT stripped from HTTP/2 URL request headers when
- * stripping is not enabled. The difference from the above requests is that
- * HTTP/2 URL request headers use dictionaries rather than lists.
- */
-function painterTestSpdyURLRequestDontStripCookies() {
-  var testCase = {};
-  testCase.tickOffset = '1337911098481';
-
-  testCase.logEntries = [
-    {
-      'params': {
-          'headers': {
-            ':host': 'www.google.com',
-            ':method': 'GET',
-            ':path': '/',
-            ':scheme': 'https',
-            ':version': 'HTTP/1.1',
-            'cookie': 'MyMagicPony'},
-      },
-      'phase': EventPhase.PHASE_NONE,
-      'source': {'id': 329, 'type': EventSourceType.URL_REQUEST},
-      'time': '954124663',
-      'type': EventType.HTTP_TRANSACTION_HTTP2_SEND_REQUEST_HEADERS
-    }
-  ];
-
-  testCase.expectedText =
-'t=1338865223144 [st=0]  HTTP_TRANSACTION_HTTP2_SEND_REQUEST_HEADERS\n' +
-'                        --> :host: www.google.com\n' +
-'                            :method: GET\n' +
-'                            :path: /\n' +
-'                            :scheme: https\n' +
-'                            :version: HTTP/1.1\n' +
-'                            cookie: MyMagicPony';
-  return testCase;
-}
-
-/**
- * Tests that cookies are NOT stripped from HTTP/2 URL request headers when
- * stripping is not enabled. The difference from the above requests is that
- */
-function painterTestSpdyURLRequestStripCookies() {
-  var testCase = painterTestSpdyURLRequestDontStripCookies();
-  testCase.privacyStripping = true;
-  testCase.expectedText =
-      testCase.expectedText.replace(/MyMagicPony/g, '[11 bytes were stripped]');
-  return testCase;
-}
-
-/**
  * Tests that when there are more custom parameters than we expect for an
  * event type, they are printed out in addition to the custom formatting.
  */
diff --git a/chrome/test/data/webui/settings/device_page_tests.js b/chrome/test/data/webui/settings/device_page_tests.js
index add50ce..9d58b57 100644
--- a/chrome/test/data/webui/settings/device_page_tests.js
+++ b/chrome/test/data/webui/settings/device_page_tests.js
@@ -247,6 +247,16 @@
             value: false,
           },
         },
+        enable_stylus_tools: {
+          key: 'settings.enable_stylus_tools',
+          type: chrome.settingsPrivate.PrefType.BOOLEAN,
+          value: false,
+        },
+        launch_palette_on_eject_event: {
+          key: 'settings.launch_palette_on_eject_event',
+          type: chrome.settingsPrivate.PrefType.BOOLEAN,
+          value: false,
+        },
         restore_last_lock_screen_note: {
           key: 'settings.restore_last_lock_screen_note',
           type: chrome.settingsPrivate.PrefType.BOOLEAN,
@@ -1096,7 +1106,7 @@
       suiteSetup(function() {
         // Always show stylus settings.
         loadTimeData.overrideValues({
-          stylusAllowed: true,
+          hasInternalStylus: true,
         });
       });
 
@@ -1159,6 +1169,35 @@
         return !!element && element.offsetWidth > 0 && element.offsetHeight > 0;
       }
 
+      test('stylus tools prefs', function() {
+        // Both stylus tools prefs are intially false.
+        assertFalse(devicePage.prefs.settings.enable_stylus_tools.value);
+        assertFalse(
+            devicePage.prefs.settings.launch_palette_on_eject_event.value);
+
+        // Since both prefs are intially false, the launch palette on eject pref
+        // toggle is disabled.
+        expectTrue(isVisible(stylusPage.$$('#enableStylusToolsToggle')));
+        expectTrue(
+            isVisible(stylusPage.$$('#launchPaletteOnEjectEventToggle')));
+        expectTrue(
+            stylusPage.$$('#launchPaletteOnEjectEventToggle').disabled);
+        expectFalse(devicePage.prefs.settings.enable_stylus_tools.value);
+        expectFalse(
+            devicePage.prefs.settings.launch_palette_on_eject_event.value);
+
+        // Tapping the enable stylus tools pref causes the launch palette on
+        // eject pref toggle to not be disabled anymore.
+        MockInteractions.tap(stylusPage.$$('#enableStylusToolsToggle'));
+        expectTrue(devicePage.prefs.settings.enable_stylus_tools.value);
+        expectFalse(
+            stylusPage.$$('#launchPaletteOnEjectEventToggle').disabled);
+        MockInteractions.tap(
+            stylusPage.$$('#launchPaletteOnEjectEventToggle'));
+        expectTrue(
+            devicePage.prefs.settings.launch_palette_on_eject_event.value);
+      });
+
       test('choose first app if no preferred ones', function() {
         // Selector chooses the first value in list if there is no preferred
         // value set.
diff --git a/components/google/core/browser/google_url_tracker.h b/components/google/core/browser/google_url_tracker.h
index e98af137..1b5017d 100644
--- a/components/google/core/browser/google_url_tracker.h
+++ b/components/google/core/browser/google_url_tracker.h
@@ -81,7 +81,7 @@
   // net::URLFetcherDelegate:
   void OnURLFetchComplete(const net::URLFetcher* source) override;
 
-  // NetworkChangeNotifier::IPAddressObserver:
+  // NetworkChangeNotifier::NetworkChangeObserver:
   void OnNetworkChanged(
       net::NetworkChangeNotifier::ConnectionType type) override;
 
diff --git a/components/machine_intelligence/proto/BUILD.gn b/components/machine_intelligence/proto/BUILD.gn
index f2d9c9c..9c1d6a0 100644
--- a/components/machine_intelligence/proto/BUILD.gn
+++ b/components/machine_intelligence/proto/BUILD.gn
@@ -6,7 +6,6 @@
 
 proto_library("proto") {
   sources = [
-    "contextual_search_ranker_model.proto",
     "generic_logistic_regression_model.proto",
     "ranker_example.proto",
     "ranker_model.proto",
diff --git a/components/machine_intelligence/proto/contextual_search_ranker_model.proto b/components/machine_intelligence/proto/contextual_search_ranker_model.proto
deleted file mode 100644
index 79a793a..0000000
--- a/components/machine_intelligence/proto/contextual_search_ranker_model.proto
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// Assist Model for Contextual Search.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-import "generic_logistic_regression_model.proto";
-
-package machine_intelligence;
-
-// Defines a Contextual Search Ranker Model.
-message ContextualSearchRankerModel {
-  // A number that identifies the version of this model.
-  optional uint32 version = 1;
-
-  oneof model_revision {
-    GenericLogisticRegressionModel generic_logistic_regression_model = 2;
-  }
-}
\ No newline at end of file
diff --git a/components/machine_intelligence/proto/ranker_model.proto b/components/machine_intelligence/proto/ranker_model.proto
index 92178a3..adbfabf 100644
--- a/components/machine_intelligence/proto/ranker_model.proto
+++ b/components/machine_intelligence/proto/ranker_model.proto
@@ -9,14 +9,14 @@
 option optimize_for = LITE_RUNTIME;
 
 import "translate_ranker_model.proto";
-import "contextual_search_ranker_model.proto";
+import "generic_logistic_regression_model.proto";
 
 package machine_intelligence;
 
 // Metadata for a ranker model instance. This data describes how the ranker
 // model should be interpreted/used.
 message RankerModelMetadata {
-  // An identifier denoting the type or purpose of this model.
+  // An identifier denoting the type or purpose of this model. E.g. "Translate".
   optional string name = 1;
 
   // An identifier denoting the specific instance of this model. For example:
@@ -39,6 +39,9 @@
   // instance of the model never expires. A new download can be triggered by
   // changing the configured source URL for the model loader.
   optional int64 cache_duration_sec = 5;
+
+  // The version of the model. E.g. 20171027.
+  optional uint32 model_version = 6;
 }
 
 // Defines an envelope/wrapper for general models.
@@ -48,6 +51,6 @@
 
   oneof model {
     TranslateRankerModel translate = 2;
-    ContextualSearchRankerModel contextual_search = 3;
+    GenericLogisticRegressionModel logistic_regression = 3;
   }
 }
diff --git a/components/omnibox/browser/history_url_provider.cc b/components/omnibox/browser/history_url_provider.cc
index bc9a43c..96e91400 100644
--- a/components/omnibox/browser/history_url_provider.cc
+++ b/components/omnibox/browser/history_url_provider.cc
@@ -71,7 +71,11 @@
     return a.url_info.visit_count() > b.url_info.visit_count();
 
   // URLs that have been visited more recently are better.
-  return a.url_info.last_visit() > b.url_info.last_visit();
+  if (a.url_info.last_visit() != b.url_info.last_visit())
+    return a.url_info.last_visit() > b.url_info.last_visit();
+
+  // Use alphabetical order on the url spec as a tie-breaker.
+  return a.url_info.url().spec() > b.url_info.url().spec();
 }
 
 // Sorts and dedups the given list of matches.
diff --git a/components/omnibox/browser/history_url_provider_unittest.cc b/components/omnibox/browser/history_url_provider_unittest.cc
index c83fad1..a07a29a1 100644
--- a/components/omnibox/browser/history_url_provider_unittest.cc
+++ b/components/omnibox/browser/history_url_provider_unittest.cc
@@ -870,19 +870,15 @@
   EXPECT_LE(1400, matches_[0].relevance);
   EXPECT_LT(matches_[0].relevance, 1410);
 
-  const UrlAndLegalDefault expected3[] = {
-    { "http://intra/one", true },
-    { "http://intra/three", true },
-    { "http://intra/two", true }
-  };
+  const UrlAndLegalDefault expected3[] = {{"http://intra/three", true},
+                                          {"http://intra/one", true},
+                                          {"http://intra/two", true}};
   RunTest(ASCIIToUTF16("intra"), std::string(), false, expected3,
           arraysize(expected3));
 
-  const UrlAndLegalDefault expected4[] = {
-    { "http://intra/one", true },
-    { "http://intra/three", true },
-    { "http://intra/two", true }
-  };
+  const UrlAndLegalDefault expected4[] = {{"http://intra/three", true},
+                                          {"http://intra/one", true},
+                                          {"http://intra/two", true}};
   RunTest(ASCIIToUTF16("intra/"), std::string(), false, expected4,
           arraysize(expected4));
 
@@ -1263,9 +1259,9 @@
   ExpectFormattedFullMatch("WWW.hij", L"www.hij.com/\x2026\x0000", 0, 7);
 
   // Verify that matching in the subdomain-only preserves the subdomain.
-  ExpectFormattedFullMatch("ww", L"www.abc.def.com/\x2026\x0000", 0, 2);
-  ExpectFormattedFullMatch("https://ww",
-                           L"https://www.abc.def.com/\x2026\x0000", 0, 10);
+  ExpectFormattedFullMatch("ww", L"www.hij.com/\x2026\x0000", 0, 2);
+  ExpectFormattedFullMatch("https://ww", L"https://www.hij.com/\x2026\x0000", 0,
+                           10);
 
   // Test individual feature flags as a sanity check.
   feature_list.reset(new base::test::ScopedFeatureList);
diff --git a/components/omnibox/browser/url_prefix.cc b/components/omnibox/browser/url_prefix.cc
index 763036f..d4b2137 100644
--- a/components/omnibox/browser/url_prefix.cc
+++ b/components/omnibox/browser/url_prefix.cc
@@ -53,11 +53,11 @@
   CR_DEFINE_STATIC_LOCAL(URLPrefixes, prefixes, ());
   if (prefixes.empty()) {
     // Keep this list in descending number of components.
-    prefixes.push_back(URLPrefix(base::ASCIIToUTF16("https://www."), 2));
     prefixes.push_back(URLPrefix(base::ASCIIToUTF16("http://www."), 2));
+    prefixes.push_back(URLPrefix(base::ASCIIToUTF16("https://www."), 2));
     prefixes.push_back(URLPrefix(base::ASCIIToUTF16("ftp://www."), 2));
-    prefixes.push_back(URLPrefix(base::ASCIIToUTF16("https://"), 1));
     prefixes.push_back(URLPrefix(base::ASCIIToUTF16("http://"), 1));
+    prefixes.push_back(URLPrefix(base::ASCIIToUTF16("https://"), 1));
     prefixes.push_back(URLPrefix(base::ASCIIToUTF16("ftp://"), 1));
     prefixes.push_back(URLPrefix(base::string16(), 0));
   }
diff --git a/content/browser/blob_storage/blob_registry_wrapper.cc b/content/browser/blob_storage/blob_registry_wrapper.cc
index 9057879..03b2708 100644
--- a/content/browser/blob_storage/blob_registry_wrapper.cc
+++ b/content/browser/blob_storage/blob_registry_wrapper.cc
@@ -8,6 +8,7 @@
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/public/common/content_features.h"
 #include "storage/browser/blob/blob_registry_impl.h"
+#include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/fileapi/file_system_context.h"
 
 namespace content {
@@ -72,7 +73,8 @@
     scoped_refptr<storage::FileSystemContext> file_system_context) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   blob_registry_ = std::make_unique<storage::BlobRegistryImpl>(
-      blob_storage_context->context(), std::move(file_system_context));
+      blob_storage_context->context()->AsWeakPtr(),
+      std::move(file_system_context));
 }
 
 }  // namespace content
diff --git a/content/network/OWNERS b/content/network/OWNERS
index 3f8c53e..7e6f7eb 100644
--- a/content/network/OWNERS
+++ b/content/network/OWNERS
@@ -1,10 +1,10 @@
 ananta@chromium.org
-asanka@chromium.org
 jam@chromium.org
 kinuko@chromium.org
 mmenke@chromium.org
 rdsmith@chromium.org
 scottmg@chromium.org
+xunjieli@chromium.org
 yhirano@chromium.org
 yzshen@chromium.org
 
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index 200e6722..962ea142 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -9,7 +9,6 @@
 #include <cctype>
 
 #include "base/location.h"
-#include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
@@ -152,8 +151,9 @@
 
 void RenderViewTest::RendererBlinkPlatformImplTestOverride::Initialize() {
   renderer_scheduler_ = blink::scheduler::RendererScheduler::Create();
-  blink_platform_impl_.reset(
-      new RendererBlinkPlatformImplTestOverrideImpl(renderer_scheduler_.get()));
+  blink_platform_impl_ =
+      std::make_unique<RendererBlinkPlatformImplTestOverrideImpl>(
+          renderer_scheduler_.get());
 }
 
 void RenderViewTest::RendererBlinkPlatformImplTestOverride::Shutdown() {
@@ -161,7 +161,7 @@
   blink_platform_impl_->Shutdown();
 }
 
-RenderViewTest::RenderViewTest() : view_(nullptr) {
+RenderViewTest::RenderViewTest() {
   RenderFrameImpl::InstallCreateHook(&TestRenderFrame::CreateTestRenderFrame);
 }
 
@@ -234,17 +234,18 @@
 }
 
 void RenderViewTest::SetUp() {
-  test_io_thread_.reset(new base::TestIOThread(base::TestIOThread::kAutoStart));
-  ipc_support_.reset(new mojo::edk::ScopedIPCSupport(
+  test_io_thread_ =
+      std::make_unique<base::TestIOThread>(base::TestIOThread::kAutoStart);
+  ipc_support_ = std::make_unique<mojo::edk::ScopedIPCSupport>(
       test_io_thread_->task_runner(),
-      mojo::edk::ScopedIPCSupport::ShutdownPolicy::FAST));
+      mojo::edk::ScopedIPCSupport::ShutdownPolicy::FAST);
 
   // Subclasses can set render_thread_ with their own implementation before
   // calling RenderViewTest::SetUp().
   // The render thread needs to exist before blink::Initialize. It also mirrors
   // the order on Chromium initialization.
   if (!render_thread_)
-    render_thread_.reset(new MockRenderThread());
+    render_thread_ = std::make_unique<MockRenderThread>();
   render_thread_->set_routing_id(kRouteId);
   render_thread_->set_new_window_routing_id(kNewWindowRouteId);
   render_thread_->set_new_window_main_frame_widget_routing_id(
@@ -274,15 +275,16 @@
 #endif
 
 #if defined(OS_MACOSX)
-  autorelease_pool_.reset(new base::mac::ScopedNSAutoreleasePool());
+  autorelease_pool_ = std::make_unique<base::mac::ScopedNSAutoreleasePool>();
 #endif
-  command_line_.reset(new base::CommandLine(base::CommandLine::NO_PROGRAM));
-  field_trial_list_.reset(new base::FieldTrialList(nullptr));
+  command_line_ =
+      std::make_unique<base::CommandLine>(base::CommandLine::NO_PROGRAM);
+  field_trial_list_ = std::make_unique<base::FieldTrialList>(nullptr);
   // We don't use the descriptor here anyways so it's ok to pass -1.
   base::FieldTrialList::CreateTrialsFromCommandLine(
       *command_line_, switches::kFieldTrialHandle, -1);
-  params_.reset(new MainFunctionParams(*command_line_));
-  platform_.reset(new RendererMainPlatformDelegate(*params_));
+  params_ = std::make_unique<MainFunctionParams>(*command_line_);
+  platform_ = std::make_unique<RendererMainPlatformDelegate>(*params_);
   platform_->PlatformInitialize();
 
   // Setting flags and really doing anything with WebKit is fairly fragile and
@@ -301,12 +303,13 @@
   // ResourceBundle isn't initialized (since we have to use a diferent test
   // suite implementation than for content_unittests). For browser_tests, this
   // is already initialized.
-  if (!ui::ResourceBundle::HasSharedInstance())
+  if (!ui::ResourceBundle::HasSharedInstance()) {
     ui::ResourceBundle::InitSharedInstanceWithLocale(
         "en-US", nullptr, ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES);
+  }
 
-  compositor_deps_.reset(new FakeCompositorDependencies);
-  mock_process_.reset(new MockRenderProcess);
+  compositor_deps_ = std::make_unique<FakeCompositorDependencies>();
+  mock_process_ = std::make_unique<MockRenderProcess>();
 
   mojom::CreateViewParamsPtr view_params = mojom::CreateViewParams::New();
   view_params->opener_frame_route_id = MSG_ROUTING_NONE;
@@ -328,11 +331,8 @@
   view_params->min_size = gfx::Size();
   view_params->max_size = gfx::Size();
 
-  // This needs to pass the mock render thread to the view.
-  RenderViewImpl* view =
-      RenderViewImpl::Create(compositor_deps_.get(), std::move(view_params),
-                             RenderWidget::ShowCallback());
-  view_ = view;
+  view_ = RenderViewImpl::Create(compositor_deps_.get(), std::move(view_params),
+                                 RenderWidget::ShowCallback());
 }
 
 void RenderViewTest::TearDown() {
@@ -346,6 +346,8 @@
 
   leak_detector->PrepareForLeakDetection(view_->GetWebView()->MainFrame());
 
+  // |view_| is ref-counted and deletes itself during the RunUntilIdle() call
+  // below.
   view_ = nullptr;
   mock_process_.reset();
 
@@ -357,7 +359,7 @@
   base::RunLoop().RunUntilIdle();
 
 #if defined(OS_MACOSX)
-  autorelease_pool_.reset(NULL);
+  autorelease_pool_.reset();
 #endif
 
   leak_detector->CollectGarbageAndReport();
@@ -412,27 +414,27 @@
   SendInputEvent(gesture_event);
 }
 
-const char* const kGetCoordinatesScript =
-    "(function() {"
-    "  function GetCoordinates(elem) {"
-    "    if (!elem)"
-    "      return [ 0, 0];"
-    "    var coordinates = [ elem.offsetLeft, elem.offsetTop];"
-    "    var parent_coordinates = GetCoordinates(elem.offsetParent);"
-    "    coordinates[0] += parent_coordinates[0];"
-    "    coordinates[1] += parent_coordinates[1];"
-    "    return [ Math.round(coordinates[0]),"
-    "             Math.round(coordinates[1])];"
-    "  };"
-    "  var elem = document.getElementById('$1');"
-    "  if (!elem)"
-    "    return null;"
-    "  var bounds = GetCoordinates(elem);"
-    "  bounds[2] = Math.round(elem.offsetWidth);"
-    "  bounds[3] = Math.round(elem.offsetHeight);"
-    "  return bounds;"
-    "})();";
 gfx::Rect RenderViewTest::GetElementBounds(const std::string& element_id) {
+  static constexpr char kGetCoordinatesScript[] =
+      "(function() {"
+      "  function GetCoordinates(elem) {"
+      "    if (!elem)"
+      "      return [ 0, 0];"
+      "    var coordinates = [ elem.offsetLeft, elem.offsetTop];"
+      "    var parent_coordinates = GetCoordinates(elem.offsetParent);"
+      "    coordinates[0] += parent_coordinates[0];"
+      "    coordinates[1] += parent_coordinates[1];"
+      "    return [ Math.round(coordinates[0]),"
+      "             Math.round(coordinates[1])];"
+      "  };"
+      "  var elem = document.getElementById('$1');"
+      "  if (!elem)"
+      "    return null;"
+      "  var bounds = GetCoordinates(elem);"
+      "  bounds[2] = Math.round(elem.offsetWidth);"
+      "  bounds[3] = Math.round(elem.offsetHeight);"
+      "  return bounds;"
+      "})();";
   std::vector<std::string> params;
   params.push_back(element_id);
   std::string script =
diff --git a/content/public/test/render_view_test.h b/content/public/test/render_view_test.h
index 29cb0a9..4a84e5d 100644
--- a/content/public/test/render_view_test.h
+++ b/content/public/test/render_view_test.h
@@ -190,14 +190,13 @@
   // blink::WebLeakDetectorClient implementation.
   void OnLeakDetectionComplete(const Result& result) override;
 
- protected:
   base::test::ScopedTaskEnvironment scoped_task_environment_;
 
   std::unique_ptr<FakeCompositorDependencies> compositor_deps_;
   std::unique_ptr<MockRenderProcess> mock_process_;
   // We use a naked pointer because we don't want to expose RenderViewImpl in
   // the embedder's namespace.
-  RenderView* view_;
+  RenderView* view_ = nullptr;
   RendererBlinkPlatformImplTestOverride blink_platform_impl_;
   std::unique_ptr<ContentClient> content_client_;
   std::unique_ptr<ContentBrowserClient> content_browser_client_;
diff --git a/content/public/test/test_renderer_host.h b/content/public/test/test_renderer_host.h
index dfd9aee..eb6688e 100644
--- a/content/public/test/test_renderer_host.h
+++ b/content/public/test/test_renderer_host.h
@@ -8,6 +8,8 @@
 #include <stdint.h>
 
 #include <memory>
+#include <string>
+#include <vector>
 
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
@@ -121,6 +123,10 @@
   virtual void SimulateFeaturePolicyHeader(
       blink::WebFeaturePolicyFeature feature,
       const std::vector<url::Origin>& whitelist) = 0;
+
+  // Gets all the console messages requested via
+  // RenderFrameHost::AddMessageToConsole in this frame.
+  virtual const std::vector<std::string>& GetConsoleMessages() = 0;
 };
 
 // An interface and utility for driving tests of RenderViewHost.
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index 4522b910..7bd0c7a 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -111,6 +111,12 @@
   return static_cast<MockRenderProcessHost*>(RenderFrameHostImpl::GetProcess());
 }
 
+void TestRenderFrameHost::AddMessageToConsole(ConsoleMessageLevel level,
+                                              const std::string& message) {
+  console_messages_.push_back(message);
+  RenderFrameHostImpl::AddMessageToConsole(level, message);
+}
+
 void TestRenderFrameHost::InitializeRenderFrameIfNeeded() {
   if (!render_view_host()->IsRenderViewLive()) {
     render_view_host()->GetProcess()->Init();
@@ -305,6 +311,10 @@
   OnDidSetFeaturePolicyHeader(header);
 }
 
+const std::vector<std::string>& TestRenderFrameHost::GetConsoleMessages() {
+  return console_messages_;
+}
+
 void TestRenderFrameHost::SendNavigate(int nav_entry_id,
                                        bool did_create_new_entry,
                                        const GURL& url) {
diff --git a/content/test/test_render_frame_host.h b/content/test/test_render_frame_host.h
index a81f0675..c569fbe 100644
--- a/content/test/test_render_frame_host.h
+++ b/content/test/test_render_frame_host.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include <string>
 #include <vector>
 
 #include "base/macros.h"
@@ -52,6 +53,8 @@
   // RenderFrameHostImpl overrides (same values, but in Test*/Mock* types)
   TestRenderViewHost* GetRenderViewHost() override;
   MockRenderProcessHost* GetProcess() override;
+  void AddMessageToConsole(ConsoleMessageLevel level,
+                           const std::string& message) override;
 
   // RenderFrameHostTester implementation.
   void InitializeRenderFrameIfNeeded() override;
@@ -71,6 +74,7 @@
   void SimulateFeaturePolicyHeader(
       blink::WebFeaturePolicyFeature feature,
       const std::vector<url::Origin>& whitelist) override;
+  const std::vector<std::string>& GetConsoleMessages() override;
 
   void SendNavigateWithReplacement(int nav_entry_id,
                                    bool did_create_new_entry,
@@ -186,6 +190,9 @@
 
   mojom::FrameNavigationControl* GetInternalNavigationControl();
 
+  // Keeps a running vector of messages sent to AddMessageToConsole.
+  std::vector<std::string> console_messages_;
+
   TestRenderFrameHostCreationObserver child_creation_observer_;
 
   std::string contents_mime_type_;
diff --git a/docs/updating_clang.md b/docs/updating_clang.md
index ffda35d..c6f2375 100644
--- a/docs/updating_clang.md
+++ b/docs/updating_clang.md
@@ -36,7 +36,7 @@
       -b ios-device && \
     git cl try -m tryserver.chromium.linux -b linux_chromium_chromeos_dbg_ng \
       -b linux_chromium_chromeos_asan_rel_ng -b linux_chromium_msan_rel_ng \
-      -b fuchsia -b linux_chromium_cfi_rel_ng &&
+      -b linux_chromium_cfi_rel_ng &&
         git cl try -m tryserver.blink -b linux_trusty_blink_rel
     ```
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 4fcb9b7b2..42ec9035 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -20293,12 +20293,13 @@
   SkCanvas* canvas = sk_surface_->getCanvas();
   SkMatrix original_ctm;
   cc::PlaybackParams playback_params(nullptr, original_ctm);
+  cc::PaintOp::DeserializeOptions options;
 
   int op_idx = 0;
   while (size > 4) {
     size_t skip = 0;
     cc::PaintOp* deserialized_op = cc::PaintOp::Deserialize(
-        buffer, size, &data[0], sizeof(cc::LargestPaintOp), &skip);
+        buffer, size, &data[0], sizeof(cc::LargestPaintOp), &skip, options);
     if (!deserialized_op) {
       LOG(ERROR) << "RasterCHROMIUM: bad op: " << op_idx;
       return error::kInvalidArguments;
diff --git a/gpu/ipc/client/gpu_memory_buffer_impl_shared_memory_unittest.cc b/gpu/ipc/client/gpu_memory_buffer_impl_shared_memory_unittest.cc
index 268d5f8..f92ef043 100644
--- a/gpu/ipc/client/gpu_memory_buffer_impl_shared_memory_unittest.cc
+++ b/gpu/ipc/client/gpu_memory_buffer_impl_shared_memory_unittest.cc
@@ -14,30 +14,9 @@
                               GpuMemoryBufferImplTest,
                               GpuMemoryBufferImplSharedMemory);
 
-void BufferDestroyed(bool* destroyed, const gpu::SyncToken& sync_token) {
-  *destroyed = true;
-}
-
-TEST(GpuMemoryBufferImplSharedMemoryTest, Create) {
-  const gfx::GpuMemoryBufferId kBufferId(1);
-
-  gfx::Size buffer_size(8, 8);
-  gfx::BufferUsage usage = gfx::BufferUsage::GPU_READ;
-
-  for (auto format : gfx::GetBufferFormatsForTesting()) {
-    bool destroyed = false;
-    std::unique_ptr<GpuMemoryBufferImplSharedMemory> buffer(
-        GpuMemoryBufferImplSharedMemory::Create(
-            kBufferId, buffer_size, format, usage,
-            base::Bind(&BufferDestroyed, base::Unretained(&destroyed))));
-    ASSERT_TRUE(buffer);
-    EXPECT_EQ(buffer->GetFormat(), format);
-
-    // Check if destruction callback is executed when deleting the buffer.
-    buffer.reset();
-    ASSERT_TRUE(destroyed);
-  }
-}
+INSTANTIATE_TYPED_TEST_CASE_P(GpuMemoryBufferImplSharedMemory,
+                              GpuMemoryBufferImplCreateTest,
+                              GpuMemoryBufferImplSharedMemory);
 
 }  // namespace
 }  // namespace gpu
diff --git a/gpu/ipc/client/gpu_memory_buffer_impl_test_template.h b/gpu/ipc/client/gpu_memory_buffer_impl_test_template.h
index 9723437..91cdc5d9 100644
--- a/gpu/ipc/client/gpu_memory_buffer_impl_test_template.h
+++ b/gpu/ipc/client/gpu_memory_buffer_impl_test_template.h
@@ -57,6 +57,11 @@
   }
 };
 
+// Subclass test case for tests that require a Create() method,
+// not all implementations have that.
+template <typename GpuMemoryBufferImplType>
+class GpuMemoryBufferImplCreateTest : public testing::Test {};
+
 TYPED_TEST_CASE_P(GpuMemoryBufferImplTest);
 
 TYPED_TEST_P(GpuMemoryBufferImplTest, CreateFromHandle) {
@@ -221,6 +226,36 @@
                            Map,
                            PersistentMap);
 
+TYPED_TEST_CASE_P(GpuMemoryBufferImplCreateTest);
+
+TYPED_TEST_P(GpuMemoryBufferImplCreateTest, Create) {
+  const gfx::GpuMemoryBufferId kBufferId(1);
+  const gfx::Size kBufferSize(8, 8);
+  gfx::BufferUsage usage = gfx::BufferUsage::GPU_READ;
+
+  for (auto format : gfx::GetBufferFormatsForTesting()) {
+    if (!TypeParam::IsConfigurationSupported(format, usage))
+      continue;
+    bool destroyed = false;
+    gfx::GpuMemoryBufferHandle handle;
+    std::unique_ptr<TypeParam> buffer(TypeParam::Create(
+        kBufferId, kBufferSize, format, usage,
+        base::Bind(
+            [](bool* destroyed, const gpu::SyncToken&) { *destroyed = true; },
+            base::Unretained(&destroyed))));
+    ASSERT_TRUE(buffer);
+    EXPECT_EQ(buffer->GetFormat(), format);
+
+    // Check if destruction callback is executed when deleting the buffer.
+    buffer.reset();
+    ASSERT_TRUE(destroyed);
+  }
+}
+// The GpuMemoryBufferImplCreateTest test case verifies behavior that is
+// expected from a GpuMemoryBuffer Create() implementation in order to be
+// conformant.
+REGISTER_TYPED_TEST_CASE_P(GpuMemoryBufferImplCreateTest, Create);
+
 }  // namespace gpu
 
 #endif  // GPU_IPC_CLIENT_GPU_MEMORY_BUFFER_IMPL_TEST_TEMPLATE_H_
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index a1820394..8d177ca 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -148,7 +148,6 @@
     "//ios/chrome/app/startup:startup_basic",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
-    "//ios/chrome/browser:browser_internal",
     "//ios/chrome/browser/bookmarks",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browser_state:browser_state_impl",
@@ -244,7 +243,6 @@
     "//base",
     "//components/crash/core/common",
     "//ios/chrome/app/startup:startup_basic",
-    "//ios/chrome/browser:browser_internal",
     "//ios/chrome/browser/crash_report",
     "//ios/chrome/common",
     "//ios/testing/perf:startup",
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index e5d657ef..632d935 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -16,6 +16,7 @@
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/ios/block_types.h"
+#include "base/ios/callback_counter.h"
 #import "base/mac/bind_objc_block.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/foundation_util.h"
@@ -64,7 +65,6 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state_removal_controller.h"
 #import "ios/chrome/browser/browsing_data/browsing_data_removal_controller.h"
 #include "ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.h"
-#include "ios/chrome/browser/callback_counter.h"
 #include "ios/chrome/browser/chrome_paths.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/chrome_url_util.h"
diff --git a/ios/chrome/app/startup/BUILD.gn b/ios/chrome/app/startup/BUILD.gn
index 7d1dd59..c9a4db1 100644
--- a/ios/chrome/app/startup/BUILD.gn
+++ b/ios/chrome/app/startup/BUILD.gn
@@ -54,7 +54,6 @@
     "//base",
     "//components/ntp_snippets",
     "//ios/chrome/browser",
-    "//ios/chrome/browser:browser_internal",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/first_run",
     "//ios/chrome/browser/net:net",
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 63e476f..c728be72 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -226,7 +226,6 @@
   testonly = true
   sources = [
     "app_startup_parameters_unittest.mm",
-    "callback_counter_unittest.mm",
     "chrome_browser_provider_observer_bridge_unittest.mm",
     "chrome_url_util_unittest.mm",
     "crash_loop_detection_util_unittest.mm",
@@ -237,7 +236,6 @@
   ]
   deps = [
     ":browser",
-    ":browser_internal",
     "//base",
     "//base/test:test_support",
     "//components/prefs",
@@ -254,14 +252,3 @@
     "//url",
   ]
 }
-
-source_set("browser_internal") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  sources = [
-    "callback_counter.h",
-    "callback_counter.mm",
-  ]
-  deps = [
-    "//base",
-  ]
-}
diff --git a/ios/chrome/browser/browsing_data/BUILD.gn b/ios/chrome/browser/browsing_data/BUILD.gn
index 4cd33ee..9cb5519a 100644
--- a/ios/chrome/browser/browsing_data/BUILD.gn
+++ b/ios/chrome/browser/browsing_data/BUILD.gn
@@ -95,7 +95,6 @@
     "//components/browsing_data/core",
     "//components/open_from_clipboard",
     "//components/signin/ios/browser",
-    "//ios/chrome/browser:browser_internal",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/sessions:serialisation",
     "//ios/chrome/browser/signin",
diff --git a/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm b/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm
index 0f29f4dc..a596b31 100644
--- a/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm
+++ b/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm
@@ -13,6 +13,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/containers/hash_tables.h"
+#include "base/ios/callback_counter.h"
 #include "base/logging.h"
 #import "base/mac/bind_objc_block.h"
 #include "base/memory/ref_counted.h"
@@ -21,7 +22,6 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_remover_helper.h"
 #include "ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.h"
-#include "ios/chrome/browser/callback_counter.h"
 #include "ios/chrome/browser/sessions/session_util.h"
 #include "ios/chrome/browser/signin/account_consistency_service_factory.h"
 #import "ios/chrome/browser/snapshots/snapshots_util.h"
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
index 32e9755c6..51328ef 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/strings/sys_string_conversions.h"
+#import "base/test/ios/wait_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/prefs/pref_service.h"
@@ -725,9 +726,9 @@
       performAction:grey_tap()];
 
   // Wait so that the string is copied to clipboard.
-  testing::WaitUntilConditionOrTimeout(1, ^{
-    return false;
-  });
+  // TODO(crbug.com/780064): poll for pasteboard change instead.
+  base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSecondsD(1));
+
   // Verify general pasteboard has the URL copied.
   NSString* copiedString = [UIPasteboard generalPasteboard].string;
   GREYAssert([copiedString containsString:@"www.a.fr"],
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm
index 04b7e7d..a57a729 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm
@@ -324,7 +324,7 @@
           initWithName:l10n_util::GetNSString(IDS_IOS_TAB_SWITCHER_CLOSE_TAB)
                 target:self
               selector:@selector(closeButtonPressed)];
-  [customActions addObject:customAction = nil];
+  [customActions addObject:customAction];
   return customActions;
 }
 
diff --git a/ios/chrome/test/app/BUILD.gn b/ios/chrome/test/app/BUILD.gn
index a6377f8..de373c25 100644
--- a/ios/chrome/test/app/BUILD.gn
+++ b/ios/chrome/test/app/BUILD.gn
@@ -53,7 +53,6 @@
     "//ios/chrome/app/application_delegate:application_delegate_internal",
     "//ios/chrome/app/application_delegate:test_support",
     "//ios/chrome/browser",
-    "//ios/chrome/browser:browser_internal",
     "//ios/chrome/browser/autofill",
     "//ios/chrome/browser/bookmarks",
     "//ios/chrome/browser/browser_state",
diff --git a/ios/chrome/test/app/history_test_util.mm b/ios/chrome/test/app/history_test_util.mm
index 500de21..1a0c4ad 100644
--- a/ios/chrome/test/app/history_test_util.mm
+++ b/ios/chrome/test/app/history_test_util.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/test/app/history_test_util.h"
 
+#include "base/ios/callback_counter.h"
 #import "base/mac/bind_objc_block.h"
 #import "base/test/ios/wait_util.h"
 #include "components/browsing_data/core/browsing_data_utils.h"
@@ -11,7 +12,6 @@
 #import "ios/chrome/app/main_controller_private.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.h"
-#include "ios/chrome/browser/callback_counter.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/test/app/static_html_view_test_util.mm b/ios/chrome/test/app/static_html_view_test_util.mm
index 07d2347..3b2672f 100644
--- a/ios/chrome/test/app/static_html_view_test_util.mm
+++ b/ios/chrome/test/app/static_html_view_test_util.mm
@@ -16,8 +16,12 @@
 #error "This file requires ARC support."
 #endif
 
+using testing::WaitUntilConditionOrTimeout;
+using testing::kWaitForJSCompletionTimeout;
+
 namespace chrome_test_util {
 
+namespace {
 // Synchronously returns the result of executed JavaScript.
 id ExecuteScriptInStaticController(
     StaticHtmlViewController* html_view_controller,
@@ -31,12 +35,13 @@
                         }];
 
   // If a timeout is reached, then return |result|, which should be nil;
-  testing::WaitUntilConditionOrTimeout(testing::kWaitForJSCompletionTimeout, ^{
+  bool completed = WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
     return did_finish;
   });
 
-  return result;
+  return completed ? result : nil;
 }
+}  // namespace
 
 // Returns the StaticHtmlViewController for the given |web_state|. If none is
 // found, it returns nil.
diff --git a/ios/chrome/test/app/tab_test_util.h b/ios/chrome/test/app/tab_test_util.h
index 0fa3fad..31359851 100644
--- a/ios/chrome/test/app/tab_test_util.h
+++ b/ios/chrome/test/app/tab_test_util.h
@@ -64,8 +64,8 @@
 // Evicts the tabs associated with the non-current browser mode.
 void EvictOtherTabModelTabs();
 
-// Closes all incognito tabs.
-void CloseAllIncognitoTabs();
+// Closes all incognito tabs. Return YES on success.
+BOOL CloseAllIncognitoTabs();
 
 // Returns the number of main tabs currently evicted.
 NSUInteger GetEvictedMainTabCount();
diff --git a/ios/chrome/test/app/tab_test_util.mm b/ios/chrome/test/app/tab_test_util.mm
index 476f4f8..bd72660 100644
--- a/ios/chrome/test/app/tab_test_util.mm
+++ b/ios/chrome/test/app/tab_test_util.mm
@@ -25,6 +25,8 @@
 #error "This file requires ARC support."
 #endif
 
+using testing::WaitUntilConditionOrTimeout;
+
 namespace chrome_test_util {
 
 namespace {
@@ -154,7 +156,7 @@
   otherTabModel.webUsageEnabled = YES;
 }
 
-void CloseAllIncognitoTabs() {
+BOOL CloseAllIncognitoTabs() {
   MainController* main_controller = chrome_test_util::GetMainController();
   DCHECK(main_controller);
   TabModel* tabModel = [[main_controller browserViewInformation] otrTabModel];
@@ -163,10 +165,11 @@
   if (!IsIPadIdiom()) {
     // If the OTR BVC is active, wait until it isn't (since all of the
     // tabs are now closed)
-    testing::WaitUntilConditionOrTimeout(testing::kWaitForUIElementTimeout, ^{
+    return WaitUntilConditionOrTimeout(testing::kWaitForUIElementTimeout, ^{
       return !IsIncognitoMode();
     });
   }
+  return YES;
 }
 
 NSUInteger GetEvictedMainTabCount() {
diff --git a/ios/clean/chrome/app/BUILD.gn b/ios/clean/chrome/app/BUILD.gn
index c76f8d8f..8ad002d 100644
--- a/ios/clean/chrome/app/BUILD.gn
+++ b/ios/clean/chrome/app/BUILD.gn
@@ -85,7 +85,6 @@
     "//ios/chrome/app/startup",
     "//ios/chrome/app/startup:startup_basic",
     "//ios/chrome/browser",
-    "//ios/chrome/browser:browser_internal",
     "//ios/chrome/browser/crash_report",
     "//ios/chrome/common",
     "//ios/testing/perf:startup",
diff --git a/ios/clean/chrome/app/steps/BUILD.gn b/ios/clean/chrome/app/steps/BUILD.gn
index 92053f05..3e68ad9 100644
--- a/ios/clean/chrome/app/steps/BUILD.gn
+++ b/ios/clean/chrome/app/steps/BUILD.gn
@@ -55,7 +55,6 @@
     "//ios/chrome/app/startup",
     "//ios/chrome/app/startup:startup_basic",
     "//ios/chrome/browser",
-    "//ios/chrome/browser:browser_internal",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browser_state:browser_state_impl",
     "//ios/chrome/browser/content_settings",
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index da3d3340..ed57c2a 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -269,6 +269,7 @@
     "//ios/testing:ios_test_support",
     "//ios/testing:ocmock_support",
     "//ios/web/navigation",
+    "//ios/web/net/cookies",
     "//ios/web/public",
     "//ios/web/public/test",
     "//ios/web/public/test/fakes",
@@ -288,6 +289,7 @@
   sources = [
     "net/cert_host_pair_unittest.cc",
     "net/cert_policy_unittest.cc",
+    "net/cookies/wk_cookie_util_unittest.mm",
     "net/crw_cert_verification_controller_unittest.mm",
     "net/crw_ssl_status_updater_unittest.mm",
     "net/request_group_util_unittest.mm",
diff --git a/ios/web/net/cookies/BUILD.gn b/ios/web/net/cookies/BUILD.gn
new file mode 100644
index 0000000..fd3f993
--- /dev/null
+++ b/ios/web/net/cookies/BUILD.gn
@@ -0,0 +1,20 @@
+# 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.
+
+import("//ios/build/config.gni")
+
+source_set("cookies") {
+  deps = [
+    "//ios/web/web_state/ui:wk_web_view_configuration_provider",
+  ]
+
+  sources = [
+    "wk_cookie_util.h",
+    "wk_cookie_util.mm",
+  ]
+
+  libs = [ "WebKit.framework" ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/ios/web/net/cookies/wk_cookie_util.h b/ios/web/net/cookies/wk_cookie_util.h
new file mode 100644
index 0000000..3971941
--- /dev/null
+++ b/ios/web/net/cookies/wk_cookie_util.h
@@ -0,0 +1,24 @@
+// 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 IOS_WEB_NET_COOKIES_WK_COOKIE_UTIL_H_
+#define IOS_WEB_NET_COOKIES_WK_COOKIE_UTIL_H_
+
+#include "base/mac/availability.h"
+
+@class WKHTTPCookieStore;
+
+namespace web {
+
+class BrowserState;
+
+// Returns WKHTTPCookieStore for the given BrowserState. If BrowserState is
+// OffTheRecord then the resulting WKHTTPCookieStore will be a part of
+// ephemeral WKWebsiteDataStore.
+WKHTTPCookieStore* WKCookieStoreForBrowserState(BrowserState* browser_state)
+    API_AVAILABLE(ios(11.0));
+
+}  // namespace web
+
+#endif  // IOS_WEB_NET_COOKIES_WK_COOKIE_UTIL_H_
diff --git a/ios/web/net/cookies/wk_cookie_util.mm b/ios/web/net/cookies/wk_cookie_util.mm
new file mode 100644
index 0000000..2c75accb
--- /dev/null
+++ b/ios/web/net/cookies/wk_cookie_util.mm
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/net/cookies/wk_cookie_util.h"
+
+#import <WebKit/WebKit.h>
+
+#import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace web {
+
+WKHTTPCookieStore* WKCookieStoreForBrowserState(BrowserState* browser_state) {
+  if (@available(iOS 11, *)) {
+    WKWebViewConfigurationProvider& config_provider =
+        WKWebViewConfigurationProvider::FromBrowserState(browser_state);
+    WKWebViewConfiguration* config = config_provider.GetWebViewConfiguration();
+    return config.websiteDataStore.httpCookieStore;
+  }
+  return nil;
+}
+
+}  // namespace web
diff --git a/ios/web/net/cookies/wk_cookie_util_unittest.mm b/ios/web/net/cookies/wk_cookie_util_unittest.mm
new file mode 100644
index 0000000..f9405ac
--- /dev/null
+++ b/ios/web/net/cookies/wk_cookie_util_unittest.mm
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/net/cookies/wk_cookie_util.h"
+
+#import <WebKit/WebKit.h>
+
+#import "ios/web/public/test/web_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace web {
+
+// Tests that web::WKCookieStoreForBrowserState returns valid WKHTTPCookieStore
+// object on iOS 11.
+using WKCookieUtilTest = WebTest;
+TEST_F(WKCookieUtilTest, WKCookieStoreForBrowserState) {
+  if (@available(iOS 11, *)) {
+    WKHTTPCookieStore* store = WKCookieStoreForBrowserState(GetBrowserState());
+    EXPECT_TRUE([store isKindOfClass:[WKHTTPCookieStore class]]);
+  }
+}
+
+}  // namespace web
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index 8f1bbc1..74fc603 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -24,6 +24,7 @@
 # and CrNetChromeWebView frameworks.
 ios_web_view_public_headers = [
   "public/ChromeWebView.h",
+  "public/cwv_autofill_suggestion.h",
   "public/cwv_export.h",
   "public/cwv_html_element.h",
   "public/cwv_navigation_action.h",
@@ -58,6 +59,8 @@
   "internal/app/application_context.h",
   "internal/app/web_view_io_thread.h",
   "internal/app/web_view_io_thread.mm",
+  "internal/autofill/cwv_autofill_suggestion.mm",
+  "internal/autofill/cwv_autofill_suggestion_internal.h",
   "internal/autofill/web_view_personal_data_manager_factory.cc",
   "internal/autofill/web_view_personal_data_manager_factory.h",
   "internal/content_settings/web_view_cookie_settings_factory.cc",
@@ -87,22 +90,22 @@
   "internal/pref_names.h",
   "internal/signin/ios_web_view_signin_client.h",
   "internal/signin/ios_web_view_signin_client.mm",
-  "internal/signin/web_view_account_fetcher_service_factory.cc",
   "internal/signin/web_view_account_fetcher_service_factory.h",
-  "internal/signin/web_view_account_tracker_service_factory.cc",
+  "internal/signin/web_view_account_fetcher_service_factory.mm",
   "internal/signin/web_view_account_tracker_service_factory.h",
-  "internal/signin/web_view_gaia_cookie_manager_service_factory.cc",
+  "internal/signin/web_view_account_tracker_service_factory.mm",
   "internal/signin/web_view_gaia_cookie_manager_service_factory.h",
+  "internal/signin/web_view_gaia_cookie_manager_service_factory.mm",
   "internal/signin/web_view_oauth2_token_service_factory.h",
   "internal/signin/web_view_oauth2_token_service_factory.mm",
   "internal/signin/web_view_profile_oauth2_token_service_ios_provider_impl.h",
   "internal/signin/web_view_profile_oauth2_token_service_ios_provider_impl.mm",
-  "internal/signin/web_view_signin_client_factory.cc",
   "internal/signin/web_view_signin_client_factory.h",
-  "internal/signin/web_view_signin_error_controller_factory.cc",
+  "internal/signin/web_view_signin_client_factory.mm",
   "internal/signin/web_view_signin_error_controller_factory.h",
-  "internal/signin/web_view_signin_manager_factory.cc",
+  "internal/signin/web_view_signin_error_controller_factory.mm",
   "internal/signin/web_view_signin_manager_factory.h",
+  "internal/signin/web_view_signin_manager_factory.mm",
   "internal/translate/cwv_translation_controller.mm",
   "internal/translate/cwv_translation_controller_internal.h",
   "internal/translate/cwv_translation_language_internal.h",
@@ -154,6 +157,7 @@
   "//base",
   "//components/autofill/core/browser",
   "//components/autofill/core/common",
+  "//components/autofill/ios/browser",
   "//components/content_settings/core/browser",
   "//components/flags_ui",
   "//components/infobars/core",
@@ -226,6 +230,7 @@
 test("ios_web_view_unittests") {
   testonly = true
   sources = [
+    "internal/autofill/cwv_autofill_suggestion_unittest.mm",
     "internal/cwv_html_element_unittest.mm",
     "internal/cwv_preferences_unittest.mm",
     "internal/cwv_preview_element_info_unittest.mm",
diff --git a/ios/web_view/internal/autofill/cwv_autofill_suggestion.mm b/ios/web_view/internal/autofill/cwv_autofill_suggestion.mm
new file mode 100644
index 0000000..d0013f0
--- /dev/null
+++ b/ios/web_view/internal/autofill/cwv_autofill_suggestion.mm
@@ -0,0 +1,50 @@
+// 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.
+
+#import "ios/web_view/internal/autofill/cwv_autofill_suggestion_internal.h"
+
+#include "components/autofill/core/browser/popup_item_ids.h"
+#import "components/autofill/ios/browser/form_suggestion.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation CWVAutofillSuggestion
+
+@synthesize formSuggestion = _formSuggestion;
+@synthesize formName = _formName;
+@synthesize fieldName = _fieldName;
+
+- (instancetype)initWithFormSuggestion:(FormSuggestion*)formSuggestion
+                              formName:(NSString*)formName
+                             fieldName:(NSString*)fieldName {
+  self = [super init];
+  if (self) {
+    _formSuggestion = formSuggestion;
+    _formName = [formName copy];
+    _fieldName = [fieldName copy];
+  }
+  return self;
+}
+
+#pragma mark - Public Methods
+
+- (NSString*)value {
+  return [_formSuggestion.value copy];
+}
+
+- (NSString*)displayDescription {
+  return [_formSuggestion.displayDescription copy];
+}
+
+#pragma mark - NSObject
+
+- (NSString*)debugDescription {
+  return [NSString stringWithFormat:@"%@ value: %@, displayDescription: %@",
+                                    super.debugDescription, self.value,
+                                    self.displayDescription];
+}
+
+@end
diff --git a/ios/web_view/internal/autofill/cwv_autofill_suggestion_internal.h b/ios/web_view/internal/autofill/cwv_autofill_suggestion_internal.h
new file mode 100644
index 0000000..d284657
--- /dev/null
+++ b/ios/web_view/internal/autofill/cwv_autofill_suggestion_internal.h
@@ -0,0 +1,28 @@
+// 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 IOS_WEB_VIEW_INTERNAL_AUTOFILL_CWV_AUTOFILL_SUGGESTION_INTERNAL_H_
+#define IOS_WEB_VIEW_INTERNAL_AUTOFILL_CWV_AUTOFILL_SUGGESTION_INTERNAL_H_
+
+#import "ios/web_view/public/cwv_autofill_suggestion.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class FormSuggestion;
+
+@interface CWVAutofillSuggestion ()
+
+- (instancetype)initWithFormSuggestion:(FormSuggestion*)formSuggestion
+                              formName:(NSString*)formName
+                             fieldName:(NSString*)fieldName
+    NS_DESIGNATED_INITIALIZER;
+
+// The internal autofill form suggestion.
+@property(nonatomic, readonly) FormSuggestion* formSuggestion;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif  // IOS_WEB_VIEW_INTERNAL_AUTOFILL_CWV_AUTOFILL_SUGGESTION_INTERNAL_H_
diff --git a/ios/web_view/internal/autofill/cwv_autofill_suggestion_unittest.mm b/ios/web_view/internal/autofill/cwv_autofill_suggestion_unittest.mm
new file mode 100644
index 0000000..ddc5f01
--- /dev/null
+++ b/ios/web_view/internal/autofill/cwv_autofill_suggestion_unittest.mm
@@ -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.
+
+#import "ios/web_view/internal/autofill/cwv_autofill_suggestion_internal.h"
+
+#import <Foundation/Foundation.h>
+
+#import "components/autofill/ios/browser/form_suggestion.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace ios_web_view {
+
+using CWVAutofillSuggestionTest = PlatformTest;
+
+// Tests CWVAutofillSuggestion initialization.
+TEST_F(CWVAutofillSuggestionTest, Initialization) {
+  NSString* formName = @"TestFormName";
+  NSString* fieldName = @"TestFieldName";
+  FormSuggestion* formSuggestion =
+      [FormSuggestion suggestionWithValue:@"TestValue"
+                       displayDescription:@"TestDisplayDescription"
+                                     icon:@"TestIcon"
+                               identifier:0];
+  CWVAutofillSuggestion* suggestion =
+      [[CWVAutofillSuggestion alloc] initWithFormSuggestion:formSuggestion
+                                                   formName:formName
+                                                  fieldName:fieldName];
+  EXPECT_NSEQ(formName, suggestion.formName);
+  EXPECT_NSEQ(fieldName, suggestion.fieldName);
+  EXPECT_NSEQ(formSuggestion.displayDescription, suggestion.displayDescription);
+  EXPECT_NSEQ(formSuggestion.value, suggestion.value);
+  EXPECT_EQ(formSuggestion, suggestion.formSuggestion);
+}
+
+}  // namespace ios_web_view
diff --git a/ios/web_view/internal/signin/web_view_account_fetcher_service_factory.cc b/ios/web_view/internal/signin/web_view_account_fetcher_service_factory.mm
similarity index 95%
rename from ios/web_view/internal/signin/web_view_account_fetcher_service_factory.cc
rename to ios/web_view/internal/signin/web_view_account_fetcher_service_factory.mm
index 51ccf50..ac472dd 100644
--- a/ios/web_view/internal/signin/web_view_account_fetcher_service_factory.cc
+++ b/ios/web_view/internal/signin/web_view_account_fetcher_service_factory.mm
@@ -17,6 +17,10 @@
 #include "ios/web_view/internal/signin/web_view_signin_client_factory.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace ios_web_view {
 
 WebViewAccountFetcherServiceFactory::WebViewAccountFetcherServiceFactory()
diff --git a/ios/web_view/internal/signin/web_view_account_tracker_service_factory.cc b/ios/web_view/internal/signin/web_view_account_tracker_service_factory.mm
similarity index 94%
rename from ios/web_view/internal/signin/web_view_account_tracker_service_factory.cc
rename to ios/web_view/internal/signin/web_view_account_tracker_service_factory.mm
index a65af6c0..8f5bb72 100644
--- a/ios/web_view/internal/signin/web_view_account_tracker_service_factory.cc
+++ b/ios/web_view/internal/signin/web_view_account_tracker_service_factory.mm
@@ -14,6 +14,10 @@
 #include "ios/web_view/internal/signin/web_view_signin_client_factory.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace ios_web_view {
 
 WebViewAccountTrackerServiceFactory::WebViewAccountTrackerServiceFactory()
diff --git a/ios/web_view/internal/signin/web_view_gaia_cookie_manager_service_factory.cc b/ios/web_view/internal/signin/web_view_gaia_cookie_manager_service_factory.mm
similarity index 95%
rename from ios/web_view/internal/signin/web_view_gaia_cookie_manager_service_factory.cc
rename to ios/web_view/internal/signin/web_view_gaia_cookie_manager_service_factory.mm
index ca88640b..b903a05 100644
--- a/ios/web_view/internal/signin/web_view_gaia_cookie_manager_service_factory.cc
+++ b/ios/web_view/internal/signin/web_view_gaia_cookie_manager_service_factory.mm
@@ -16,6 +16,10 @@
 #include "ios/web_view/internal/signin/web_view_signin_client_factory.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace ios_web_view {
 
 WebViewGaiaCookieManagerServiceFactory::WebViewGaiaCookieManagerServiceFactory()
diff --git a/ios/web_view/internal/signin/web_view_signin_client_factory.cc b/ios/web_view/internal/signin/web_view_signin_client_factory.mm
similarity index 95%
rename from ios/web_view/internal/signin/web_view_signin_client_factory.cc
rename to ios/web_view/internal/signin/web_view_signin_client_factory.mm
index d6073d7..609ad2c6 100644
--- a/ios/web_view/internal/signin/web_view_signin_client_factory.cc
+++ b/ios/web_view/internal/signin/web_view_signin_client_factory.mm
@@ -15,6 +15,10 @@
 #include "ios/web_view/internal/signin/web_view_signin_error_controller_factory.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace ios_web_view {
 
 // static
diff --git a/ios/web_view/internal/signin/web_view_signin_error_controller_factory.cc b/ios/web_view/internal/signin/web_view_signin_error_controller_factory.mm
similarity index 92%
rename from ios/web_view/internal/signin/web_view_signin_error_controller_factory.cc
rename to ios/web_view/internal/signin/web_view_signin_error_controller_factory.mm
index 3a888bd..a2f25c7 100644
--- a/ios/web_view/internal/signin/web_view_signin_error_controller_factory.cc
+++ b/ios/web_view/internal/signin/web_view_signin_error_controller_factory.mm
@@ -11,6 +11,10 @@
 #include "components/signin/core/browser/signin_error_controller.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace ios_web_view {
 
 // static
diff --git a/ios/web_view/internal/signin/web_view_signin_manager_factory.cc b/ios/web_view/internal/signin/web_view_signin_manager_factory.mm
similarity index 96%
rename from ios/web_view/internal/signin/web_view_signin_manager_factory.cc
rename to ios/web_view/internal/signin/web_view_signin_manager_factory.mm
index 8ddf187..6369b278 100644
--- a/ios/web_view/internal/signin/web_view_signin_manager_factory.cc
+++ b/ios/web_view/internal/signin/web_view_signin_manager_factory.mm
@@ -21,6 +21,10 @@
 #include "ios/web_view/internal/signin/web_view_signin_client_factory.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace ios_web_view {
 
 WebViewSigninManagerFactory::WebViewSigninManagerFactory()
diff --git a/ios/web_view/public/ChromeWebView.h b/ios/web_view/public/ChromeWebView.h
index 1ac3892..875c85f 100644
--- a/ios/web_view/public/ChromeWebView.h
+++ b/ios/web_view/public/ChromeWebView.h
@@ -9,6 +9,7 @@
 // ChromeWebView. Framework style imports can't be used because multiple
 // frameworks are built from ios/web_view with different output names.
 
+#import "cwv_autofill_suggestion.h"
 #import "cwv_export.h"
 #import "cwv_html_element.h"
 #import "cwv_navigation_action.h"
diff --git a/ios/web_view/test/web_view_test_util.mm b/ios/web_view/test/web_view_test_util.mm
index f3141930..cbd93a74 100644
--- a/ios/web_view/test/web_view_test_util.mm
+++ b/ios/web_view/test/web_view_test_util.mm
@@ -14,6 +14,7 @@
 #endif
 
 using testing::WaitUntilConditionOrTimeout;
+using testing::kWaitForJSCompletionTimeout;
 
 namespace ios_web_view {
 namespace test {
@@ -46,24 +47,24 @@
 }
 
 id EvaluateJavaScript(CWVWebView* web_view, NSString* script, NSError** error) {
-  __block bool did_complete = false;
+  __block bool callback_called = false;
   __block id evaluation_result = nil;
   __block id evaluation_error = nil;
   [web_view evaluateJavaScript:script
              completionHandler:^(id local_result, NSError* local_error) {
-               did_complete = true;
+               callback_called = true;
                evaluation_result = [local_result copy];
                evaluation_error = [local_error copy];
              }];
 
-  WaitUntilConditionOrTimeout(testing::kWaitForJSCompletionTimeout, ^{
-    return did_complete;
+  bool completed = WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return callback_called;
   });
 
   if (error)
     *error = evaluation_error;
 
-  return evaluation_result;
+  return completed ? evaluation_result : nil;
 }
 
 bool WaitForWebViewContainingTextOrTimeout(CWVWebView* web_view,
diff --git a/storage/browser/blob/blob_registry_impl.cc b/storage/browser/blob/blob_registry_impl.cc
index bf25ac1..5d68143 100644
--- a/storage/browser/blob/blob_registry_impl.cc
+++ b/storage/browser/blob/blob_registry_impl.cc
@@ -54,7 +54,7 @@
       const GURL& url) {
     blink::mojom::BlobURLHandlePtr ptr;
     mojo::MakeStrongBinding(
-        base::WrapUnique(new BlobURLHandleImpl(context, url)),
+        base::WrapUnique(new BlobURLHandleImpl(std::move(context), url)),
         mojo::MakeRequest(&ptr));
     return ptr;
   }
@@ -103,7 +103,7 @@
   const std::string& uuid() const { return builder_.uuid(); }
 
  private:
-  BlobStorageContext* context() const { return blob_registry_->context_; }
+  BlobStorageContext* context() const { return blob_registry_->context_.get(); }
 
   // Marks this blob as broken. If an optional |bad_message_reason| is provided,
   // this will also report a BadMessage on the binding over which the initial
@@ -115,7 +115,7 @@
     DCHECK_EQ(bad_message_reason.empty(), !BlobStatusIsBadIPC(reason));
     // The blob might no longer have any references, in which case it may no
     // longer exist. If that happens just skip calling cancel.
-    if (context()->registry().HasEntry(uuid()))
+    if (context() && context()->registry().HasEntry(uuid()))
       context()->CancelBuildingBlob(uuid(), reason);
     if (!bad_message_reason.empty())
       std::move(bad_message_callback_).Run(bad_message_reason);
@@ -199,6 +199,11 @@
 };
 
 void BlobRegistryImpl::BlobUnderConstruction::StartTransportation() {
+  if (!context()) {
+    MarkAsFinishedAndDeleteSelf();
+    return;
+  }
+
   size_t blob_count = 0;
   for (size_t i = 0; i < elements_.size(); ++i) {
     const auto& element = elements_[i];
@@ -282,6 +287,11 @@
   }
 #endif
 
+  if (!context()) {
+    MarkAsFinishedAndDeleteSelf();
+    return;
+  }
+
   if (referenced_blob_uuids_.size() == 0) {
     ResolvedAllBlobDependencies();
     return;
@@ -321,6 +331,11 @@
   DCHECK_EQ(resolved_blob_uuid_count_, referenced_blob_uuids_.size());
   DCHECK_EQ(ready_dependent_blob_count_, referenced_blob_uuids_.size());
 
+  if (!context()) {
+    MarkAsFinishedAndDeleteSelf();
+    return;
+  }
+
   auto blob_uuid_it = referenced_blob_uuids_.begin();
   for (const auto& element : elements_) {
     if (element->is_bytes()) {
@@ -378,6 +393,11 @@
 
 void BlobRegistryImpl::BlobUnderConstruction::TransportComplete(
     BlobStatus result) {
+  if (!context()) {
+    MarkAsFinishedAndDeleteSelf();
+    return;
+  }
+
   // The blob might no longer have any references, in which case it may no
   // longer exist. If that happens just skip calling Complete.
   // TODO(mek): Stop building sooner if a blob is no longer referenced.
@@ -417,9 +437,9 @@
 #endif
 
 BlobRegistryImpl::BlobRegistryImpl(
-    BlobStorageContext* context,
+    base::WeakPtr<BlobStorageContext> context,
     scoped_refptr<FileSystemContext> file_system_context)
-    : context_(context),
+    : context_(std::move(context)),
       file_system_context_(std::move(file_system_context)),
       weak_ptr_factory_(this) {}
 
@@ -438,6 +458,11 @@
     const std::string& content_disposition,
     std::vector<blink::mojom::DataElementPtr> elements,
     RegisterCallback callback) {
+  if (!context_) {
+    std::move(callback).Run();
+    return;
+  }
+
   if (uuid.empty() || context_->registry().HasEntry(uuid) ||
       base::ContainsKey(blobs_under_construction_, uuid)) {
     bindings_.ReportBadMessage("Invalid UUID passed to BlobRegistry::Register");
@@ -496,6 +521,11 @@
 void BlobRegistryImpl::GetBlobFromUUID(blink::mojom::BlobRequest blob,
                                        const std::string& uuid,
                                        GetBlobFromUUIDCallback callback) {
+  if (!context_) {
+    std::move(callback).Run();
+    return;
+  }
+
   if (uuid.empty()) {
     bindings_.ReportBadMessage(
         "Invalid UUID passed to BlobRegistry::GetBlobFromUUID");
@@ -533,9 +563,9 @@
                                            const std::string& uuid) {
   // |blob| is unused, but is passed here to be kept alive until
   // RegisterBlobURL increments the refcount of it via the uuid.
-  context_->RegisterPublicBlobURL(url, uuid);
-  std::move(callback).Run(
-      BlobURLHandleImpl::Create(context_->AsWeakPtr(), url));
+  if (context_)
+    context_->RegisterPublicBlobURL(url, uuid);
+  std::move(callback).Run(BlobURLHandleImpl::Create(context_, url));
 }
 
 }  // namespace storage
diff --git a/storage/browser/blob/blob_registry_impl.h b/storage/browser/blob/blob_registry_impl.h
index 39906911..d302f4d9 100644
--- a/storage/browser/blob/blob_registry_impl.h
+++ b/storage/browser/blob/blob_registry_impl.h
@@ -28,7 +28,7 @@
     virtual bool CanCommitURL(const GURL& url) = 0;
   };
 
-  BlobRegistryImpl(BlobStorageContext* context,
+  BlobRegistryImpl(base::WeakPtr<BlobStorageContext> context,
                    scoped_refptr<FileSystemContext> file_system_context);
   ~BlobRegistryImpl() override;
 
@@ -61,7 +61,7 @@
 
   class BlobUnderConstruction;
 
-  BlobStorageContext* context_;
+  base::WeakPtr<BlobStorageContext> context_;
   scoped_refptr<FileSystemContext> file_system_context_;
 
   mojo::BindingSet<blink::mojom::BlobRegistry, std::unique_ptr<Delegate>>
diff --git a/storage/browser/blob/blob_registry_impl_unittest.cc b/storage/browser/blob/blob_registry_impl_unittest.cc
index de044ca..6b385a2 100644
--- a/storage/browser/blob/blob_registry_impl_unittest.cc
+++ b/storage/browser/blob/blob_registry_impl_unittest.cc
@@ -105,7 +105,7 @@
         std::vector<URLRequestAutoMountHandler>(), data_dir_.GetPath(),
         FileSystemOptions(FileSystemOptions::PROFILE_MODE_INCOGNITO,
                           std::vector<std::string>(), nullptr));
-    registry_impl_ = base::MakeUnique<BlobRegistryImpl>(context_.get(),
+    registry_impl_ = base::MakeUnique<BlobRegistryImpl>(context_->AsWeakPtr(),
                                                         file_system_context_);
     auto delegate = base::MakeUnique<MockDelegate>();
     delegate_ptr_ = delegate.get();
diff --git a/third_party/WebKit/LayoutTests/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.html b/third_party/WebKit/LayoutTests/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.html
new file mode 100644
index 0000000..a6d407aa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.html
@@ -0,0 +1,6 @@
+<input id="input" value="Guy WithAVeryLongLastNameThatCouldWrap" style="width: 99px" >
+<script>
+input.focus();
+input.setSelectionRange(0,0);
+internals.setAutofilled(input, true);
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/forms/text/input-appearance-autocomplete-very-long-value.html b/third_party/WebKit/LayoutTests/fast/forms/text/input-appearance-autocomplete-very-long-value.html
new file mode 100644
index 0000000..f1febec
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/text/input-appearance-autocomplete-very-long-value.html
@@ -0,0 +1,7 @@
+<input id="input" >
+<script>
+input.focus();
+internals.setSuggestedValue(input, 'Guy WithAVeryLongLastNameThatCouldWrap');
+internals.setAutofilled(input, true);
+input.style.width = '99px';
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.html b/third_party/WebKit/LayoutTests/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.html
new file mode 100644
index 0000000..18a14ac5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.html
@@ -0,0 +1,6 @@
+<input id="input" value="hello" style="width: 99px" >
+<script>
+input.focus();
+input.setSelectionRange(0,0);
+internals.setAutofilled(input, true);
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/forms/text/input-appearance-autocomplete-with-initial-value.html b/third_party/WebKit/LayoutTests/fast/forms/text/input-appearance-autocomplete-with-initial-value.html
new file mode 100644
index 0000000..b791583
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/text/input-appearance-autocomplete-with-initial-value.html
@@ -0,0 +1,8 @@
+<input id="input" >
+<script>
+input.focus();
+input.value = "initial value";
+internals.setSuggestedValue(input, 'hello');
+internals.setAutofilled(input, true);
+input.style.width = '99px';
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/shapes/crash-allocating-very-large-raster-shape-expected.txt b/third_party/WebKit/LayoutTests/fast/shapes/crash-allocating-very-large-raster-shape-expected.txt
new file mode 100644
index 0000000..8c47c16d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/shapes/crash-allocating-very-large-raster-shape-expected.txt
@@ -0,0 +1,24 @@
+A
+B
+
+C
+
+D
+
+E
+
+F
+
+G
+
+H
+
+I
+
+KKKKKKKKKKKKKKKKKKKKKKKKK
+
+L
+
+M
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/shapes/crash-allocating-very-large-raster-shape.html b/third_party/WebKit/LayoutTests/fast/shapes/crash-allocating-very-large-raster-shape.html
new file mode 100644
index 0000000..c8161c8d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/shapes/crash-allocating-very-large-raster-shape.html
@@ -0,0 +1,44 @@
+<!-- Without the the associated fix, crashes only in Win 32 ASAN. -->
+<!-- The exact width of the column also matters. -->
+<script>
+  if (window.testRunner) {
+    testRunner.dumpAsText();
+  }
+</script>
+<style>
+  * {
+    /* Margin size is important. Just enough to crash but not enough to hit
+       the check for "too big to allocate an image"
+    */
+    margin: 41310px auto 90 auto; 
+    shape-outside: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'></svg>");
+  }
+</style>
+<body style="column-width:24em; column-gap:2em">
+  <div style="float:left;">
+    <div>A
+      <p>B
+        <p>C
+          <p>D
+            <p>E
+              <p>F
+                <p>G
+                  <p>H
+                    <p>I
+                      <p>KKKKKKKKKKKKKKKKKKKKKKKKK
+                        <p>L
+                          <p>M
+                          </p>
+                        </p>
+                      </p>
+                    </p>
+                  </p>
+                </p>
+              </p>
+            </p>
+          </p>
+        </p>
+      </p>
+    </div>
+  </div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/background-attachment-local-composited-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/background-attachment-local-composited-expected.txt
new file mode 100644
index 0000000..87edf08
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/background-attachment-local-composited-expected.txt
@@ -0,0 +1,72 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutBlockFlow DIV id='container'",
+      "position": [8, 8],
+      "bounds": [400, 400],
+      "backgroundColor": "#0000FF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "position": [8, 8],
+      "bounds": [400, 400],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "position": [8, 8],
+      "bounds": [400, 2000],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "paintInvalidations": [
+        {
+          "object": "Scrolling Contents Layer",
+          "rect": [0, 500, 400, 1500],
+          "reason": "incremental"
+        }
+      ],
+      "transform": 1
+    },
+    {
+      "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
+      "bounds": [400, 400],
+      "drawsContent": false
+    },
+    {
+      "name": "Horizontal Scrollbar Layer",
+      "position": [8, 408],
+      "bounds": [400, 0]
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [408, 8],
+      "bounds": [0, 400]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1600, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "Scrolling Contents Layer",
+      "reason": "incremental"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/background-attachment-local-equivalent-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/background-attachment-local-equivalent-expected.txt
new file mode 100644
index 0000000..87edf08
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/background-attachment-local-equivalent-expected.txt
@@ -0,0 +1,72 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutBlockFlow DIV id='container'",
+      "position": [8, 8],
+      "bounds": [400, 400],
+      "backgroundColor": "#0000FF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "position": [8, 8],
+      "bounds": [400, 400],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "position": [8, 8],
+      "bounds": [400, 2000],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "paintInvalidations": [
+        {
+          "object": "Scrolling Contents Layer",
+          "rect": [0, 500, 400, 1500],
+          "reason": "incremental"
+        }
+      ],
+      "transform": 1
+    },
+    {
+      "name": "Overflow Controls Host Layer",
+      "position": [8, 8],
+      "bounds": [400, 400],
+      "drawsContent": false
+    },
+    {
+      "name": "Horizontal Scrollbar Layer",
+      "position": [8, 408],
+      "bounds": [400, 0]
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [408, 8],
+      "bounds": [0, 400]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1600, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "Scrolling Contents Layer",
+      "reason": "incremental"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-invisible-element-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-invisible-element-expected.html
index d41a36e..7982cf0 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-invisible-element-expected.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-invisible-element-expected.html
@@ -5,6 +5,6 @@
       style="position: absolute;
              top: 300px; left: 200px;
              width: 200px; height: 200px;
-             background-color: redl "></div>
+             background-color: red"></div>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-invisible-element.html b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-invisible-element.html
index ccd2006..f4477f4 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-invisible-element.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-invisible-element.html
@@ -21,6 +21,6 @@
              position: absolute;
              top: 200px; left: 200px;
              width: 200px; height: 200px;
-             background-color: redl "></div>
+             background-color: red"></div>
 </body>
 </html>
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index ff33ff6..422f30fb 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1565,6 +1565,7 @@
     "imagebitmap/ImageBitmapTest.cpp",
     "input/EventHandlerTest.cpp",
     "input/ImeOnFocusTest.cpp",
+    "input/PointerEventManagerTest.cpp",
     "input/ScrollBoundaryBehaviorTest.cpp",
     "input/TouchActionTest.cpp",
     "input/TouchEventManagerTest.cpp",
diff --git a/third_party/WebKit/Source/core/css/html.css b/third_party/WebKit/Source/core/css/html.css
index ef11631..6e7559bc 100644
--- a/third_party/WebKit/Source/core/css/html.css
+++ b/third_party/WebKit/Source/core/css/html.css
@@ -517,6 +517,12 @@
     -webkit-user-modify: read-only !important;
 }
 
+input::-internal-input-suggested {
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    overflow: hidden;
+}
+
 input[type="password" i] {
     -webkit-text-security: disc !important;
 }
diff --git a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
index 7e20eb0..bacc76b 100644
--- a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
+++ b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
@@ -374,18 +374,7 @@
 }
 
 PointerEvent* PointerEventFactory::CreatePointerCancelEvent(
-    const WebPointerEvent& event) {
-  DCHECK_EQ(event.GetType(), WebInputEvent::Type::kPointerCancel);
-  int pointer_id = GetPointerEventId(event);
-
-  return CreatePointerCancelEvent(
-      pointer_id, event.pointer_type,
-      TimeTicks::FromSeconds(event.TimeStampSeconds()));
-}
-
-PointerEvent* PointerEventFactory::CreatePointerCancelEvent(
     const int pointer_id,
-    const WebPointerProperties::PointerType pointer_type,
     TimeTicks platfrom_time_stamp) {
   DCHECK(pointer_id_mapping_.Contains(pointer_id));
   pointer_id_mapping_.Set(
@@ -396,8 +385,8 @@
   PointerEventInit pointer_event_init;
 
   pointer_event_init.setPointerId(pointer_id);
-  pointer_event_init.setPointerType(
-      PointerTypeNameForWebPointPointerType(pointer_type));
+  pointer_event_init.setPointerType(PointerTypeNameForWebPointPointerType(
+      pointer_id_mapping_.at(pointer_id).incoming_id.GetPointerType()));
   pointer_event_init.setIsPrimary(IsPrimary(pointer_id));
 
   SetEventSpecificFields(pointer_event_init, EventTypeNames::pointercancel);
diff --git a/third_party/WebKit/Source/core/events/PointerEventFactory.h b/third_party/WebKit/Source/core/events/PointerEventFactory.h
index 0d037ed8..1f992a9 100644
--- a/third_party/WebKit/Source/core/events/PointerEventFactory.h
+++ b/third_party/WebKit/Source/core/events/PointerEventFactory.h
@@ -42,11 +42,8 @@
                        LocalFrame*,
                        DOMWindow*);
 
-  PointerEvent* CreatePointerCancelEvent(const WebPointerEvent&);
-
   PointerEvent* CreatePointerCancelEvent(
       const int pointer_id,
-      const WebPointerProperties::PointerType,
       TimeTicks platfrom_time_stamp);
 
   // For creating capture events (i.e got/lostpointercapture)
diff --git a/third_party/WebKit/Source/core/events/PointerEventFactoryTest.cpp b/third_party/WebKit/Source/core/events/PointerEventFactoryTest.cpp
index 219e2a39..883fcdf1 100644
--- a/third_party/WebKit/Source/core/events/PointerEventFactoryTest.cpp
+++ b/third_party/WebKit/Source/core/events/PointerEventFactoryTest.cpp
@@ -35,10 +35,10 @@
 class PointerEventFactoryTest : public ::testing::Test {
  protected:
   void SetUp() override;
-  PointerEvent* CreateAndCheckTouchCancel(WebPointerProperties::PointerType,
-                                          int raw_id,
-                                          int unique_id,
-                                          bool is_primary);
+  PointerEvent* CreateAndCheckPointerCancel(WebPointerProperties::PointerType,
+                                            int raw_id,
+                                            int unique_id,
+                                            bool is_primary);
   PointerEvent* CreateAndCheckTouchEvent(
       WebPointerProperties::PointerType,
       int raw_id,
@@ -53,12 +53,6 @@
       bool is_primary,
       WebInputEvent::Modifiers = WebInputEvent::kNoModifiers,
       size_t coalesced_event_count = 0);
-  PointerEvent* CreateAndCheckPointerCancelEvent(
-      WebPointerProperties::PointerType,
-      int raw_id,
-      int unique_id,
-      bool is_primary,
-      WebInputEvent::Modifiers = WebInputEvent::kNoModifiers);
   void CreateAndCheckPointerTransitionEvent(PointerEvent*, const AtomicString&);
   void CheckScrollCapablePointers(const std::set<int>& expected);
 
@@ -109,19 +103,21 @@
   time_stamp_seconds_ = platform_time_stamp;
 }
 
-PointerEvent* PointerEventFactoryTest::CreateAndCheckTouchCancel(
+PointerEvent* PointerEventFactoryTest::CreateAndCheckPointerCancel(
     WebPointerProperties::PointerType pointer_type,
     int raw_id,
     int unique_id,
     bool is_primary) {
-  TimeTicks now = TimeTicks::Now();
   PointerEvent* pointer_event = pointer_event_factory_.CreatePointerCancelEvent(
-      unique_id, pointer_type, now);
+      unique_id, TimeTicks::FromSeconds(WebInputEvent::kTimeStampForTesting));
+  EXPECT_EQ("pointercancel", pointer_event->type());
   EXPECT_EQ(unique_id, pointer_event->pointerId());
   EXPECT_EQ(is_primary, pointer_event->isPrimary());
   EXPECT_EQ(PointerTypeNameForWebPointPointerType(pointer_type),
             pointer_event->pointerType());
-  EXPECT_EQ(now, pointer_event->PlatformTimeStamp());
+  EXPECT_EQ(TimeTicks::FromSeconds(WebInputEvent::kTimeStampForTesting),
+            pointer_event->PlatformTimeStamp());
+
   return pointer_event;
 }
 
@@ -181,28 +177,6 @@
   return pointer_event;
 }
 
-PointerEvent* PointerEventFactoryTest::CreateAndCheckPointerCancelEvent(
-    WebPointerProperties::PointerType pointer_type,
-    int raw_id,
-    int unique_id,
-    bool is_primary,
-    WebInputEvent::Modifiers modifiers) {
-  PointerEvent* pointer_event = pointer_event_factory_.CreatePointerCancelEvent(
-      WebPointerEvent(WebInputEvent::Type::kPointerCancel,
-                      PointerEventFactoryTest::WebMouseEventBuilder(
-                          pointer_type, raw_id, modifiers,
-                          WebInputEvent::kTimeStampForTesting)));
-  EXPECT_EQ("pointercancel", pointer_event->type());
-  EXPECT_EQ(unique_id, pointer_event->pointerId());
-  EXPECT_EQ(is_primary, pointer_event->isPrimary());
-  EXPECT_EQ(TimeTicks::FromSeconds(WebInputEvent::kTimeStampForTesting),
-            pointer_event->PlatformTimeStamp());
-  const char* expected_pointer_type =
-      PointerTypeNameForWebPointPointerType(pointer_type);
-  EXPECT_EQ(expected_pointer_type, pointer_event->pointerType());
-  return pointer_event;
-}
-
 PointerEvent* PointerEventFactoryTest::CreateAndCheckMouseEvent(
     WebPointerProperties::PointerType pointer_type,
     int raw_id,
@@ -282,8 +256,8 @@
   EXPECT_TRUE(pointer_event_factory_.IsActive(expected_mouse_id_));
   EXPECT_TRUE(pointer_event_factory_.IsActiveButtonsState(expected_mouse_id_));
 
-  CreateAndCheckPointerCancelEvent(WebPointerProperties::PointerType::kMouse, 0,
-                                   expected_mouse_id_, true);
+  CreateAndCheckPointerCancel(WebPointerProperties::PointerType::kMouse, 0,
+                              expected_mouse_id_, true);
 
   EXPECT_TRUE(pointer_event_factory_.IsActive(expected_mouse_id_));
   EXPECT_FALSE(pointer_event_factory_.IsActiveButtonsState(expected_mouse_id_));
@@ -391,8 +365,8 @@
 
   CreateAndCheckTouchEvent(WebPointerProperties::PointerType::kTouch, 0,
                            mapped_id_start_ + 1, true);
-  CreateAndCheckTouchCancel(WebPointerProperties::PointerType::kTouch, 0,
-                            mapped_id_start_ + 1, true);
+  CreateAndCheckPointerCancel(WebPointerProperties::PointerType::kTouch, 0,
+                              mapped_id_start_ + 1, true);
 
   EXPECT_TRUE(pointer_event_factory_.IsActive(mapped_id_start_ + 1));
   EXPECT_FALSE(
@@ -507,8 +481,8 @@
                            mapped_id_start_ + 3, false);
   CreateAndCheckMouseEvent(WebPointerProperties::PointerType::kPen, 0,
                            mapped_id_start_ + 3, false);
-  CreateAndCheckTouchCancel(WebPointerProperties::PointerType::kPen, 0,
-                            mapped_id_start_ + 3, false);
+  CreateAndCheckPointerCancel(WebPointerProperties::PointerType::kPen, 0,
+                              mapped_id_start_ + 3, false);
 
   pointer_event_factory_.Clear();
 
@@ -520,10 +494,10 @@
                            mapped_id_start_, true);
   CreateAndCheckMouseEvent(WebPointerProperties::PointerType::kPen, 0,
                            mapped_id_start_ + 1, false);
-  CreateAndCheckTouchCancel(WebPointerProperties::PointerType::kPen, 1,
-                            mapped_id_start_, true);
-  CreateAndCheckTouchCancel(WebPointerProperties::PointerType::kPen, 0,
-                            mapped_id_start_ + 1, false);
+  CreateAndCheckPointerCancel(WebPointerProperties::PointerType::kPen, 1,
+                              mapped_id_start_, true);
+  CreateAndCheckPointerCancel(WebPointerProperties::PointerType::kPen, 0,
+                              mapped_id_start_ + 1, false);
 }
 
 TEST_F(PointerEventFactoryTest, OutOfRange) {
@@ -539,8 +513,8 @@
                            mapped_id_start_ + 3, false);
   CreateAndCheckMouseEvent(WebPointerProperties::PointerType::kUnknown, 2,
                            mapped_id_start_ + 2, false);
-  CreateAndCheckTouchCancel(WebPointerProperties::PointerType::kUnknown, 3,
-                            mapped_id_start_ + 3, false);
+  CreateAndCheckPointerCancel(WebPointerProperties::PointerType::kUnknown, 3,
+                              mapped_id_start_ + 3, false);
 
   pointer_event_factory_.Remove(pointer_event1->pointerId());
 
@@ -560,8 +534,8 @@
     CreateAndCheckTouchEvent(WebPointerProperties::PointerType::kMouse, i,
                              expected_mouse_id_, true);
   }
-  CreateAndCheckTouchCancel(WebPointerProperties::PointerType::kMouse, 0,
-                            expected_mouse_id_, true);
+  CreateAndCheckPointerCancel(WebPointerProperties::PointerType::kMouse, 0,
+                              expected_mouse_id_, true);
 }
 
 TEST_F(PointerEventFactoryTest, CoalescedEvents) {
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index e5409b7b..ba6e1cd 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -550,9 +550,8 @@
 }
 
 WebInputEventResult EventHandler::HandlePointerEvent(
-    const WebPointerEvent& web_pointer_event,
-    Node* target) {
-  return pointer_event_manager_->HandlePointerEvent(web_pointer_event, target);
+    const WebPointerEvent& web_pointer_event) {
+  return pointer_event_manager_->HandlePointerEvent(web_pointer_event);
 }
 
 WebInputEventResult EventHandler::HandleMousePressEvent(
diff --git a/third_party/WebKit/Source/core/input/EventHandler.h b/third_party/WebKit/Source/core/input/EventHandler.h
index b6a8ccbf..e4b61d9 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.h
+++ b/third_party/WebKit/Source/core/input/EventHandler.h
@@ -148,7 +148,7 @@
       const Vector<WebMouseEvent>& coalesced_events);
   void HandleMouseLeaveEvent(const WebMouseEvent&);
 
-  WebInputEventResult HandlePointerEvent(const WebPointerEvent&, Node* target);
+  WebInputEventResult HandlePointerEvent(const WebPointerEvent&);
 
   WebInputEventResult HandleMousePressEvent(const WebMouseEvent&);
   WebInputEventResult HandleMouseReleaseEvent(const WebMouseEvent&);
diff --git a/third_party/WebKit/Source/core/input/MouseEventManager.cpp b/third_party/WebKit/Source/core/input/MouseEventManager.cpp
index 8d4cd13..a9f15b4 100644
--- a/third_party/WebKit/Source/core/input/MouseEventManager.cpp
+++ b/third_party/WebKit/Source/core/input/MouseEventManager.cpp
@@ -913,8 +913,7 @@
     // corresponding pointer.
     if (initiator == DragInitiator::kMouse) {
       frame_->GetEventHandler().HandlePointerEvent(
-          WebPointerEvent(WebInputEvent::Type::kPointerCancel, event.Event()),
-          event.InnerNode());
+          WebPointerEvent(WebInputEvent::Type::kPointerCancel, event.Event()));
     }
     // TODO(crbug.com/708278): If the drag starts with touch the touch cancel
     // should trigger the release of pointer capture.
diff --git a/third_party/WebKit/Source/core/input/PointerEventManager.cpp b/third_party/WebKit/Source/core/input/PointerEventManager.cpp
index 8d81dbfe..4215654f 100644
--- a/third_party/WebKit/Source/core/input/PointerEventManager.cpp
+++ b/third_party/WebKit/Source/core/input/PointerEventManager.cpp
@@ -80,7 +80,7 @@
   for (auto& entry : prevent_mouse_event_for_pointer_type_)
     entry = false;
   touch_event_manager_->Clear();
-  in_canceled_state_for_pointer_type_touch_ = false;
+  scroll_capable_pointers_canceled_ = false;
   pointer_event_factory_.Clear();
   touch_ids_for_canceled_pointerdowns_.clear();
   node_under_pointer_.clear();
@@ -257,53 +257,81 @@
   }
 }
 
-void PointerEventManager::BlockTouchPointers(TimeTicks platform_time_stamp) {
-  if (in_canceled_state_for_pointer_type_touch_)
-    return;
-  in_canceled_state_for_pointer_type_touch_ = true;
+void PointerEventManager::DispatchPointerCancelEvents(
+    const WebPointerEvent& web_pointer_event) {
+  DCHECK(web_pointer_event.GetType() == WebInputEvent::Type::kPointerCancel);
 
-  Vector<int> touch_pointer_ids =
-      pointer_event_factory_.GetPointerIdsOfScrollCapablePointers();
-
-  for (int pointer_id : touch_pointer_ids) {
-    PointerEvent* pointer_event =
+  HeapVector<Member<PointerEvent>> canceled_pointer_events;
+  if (web_pointer_event.pointer_type ==
+      WebPointerProperties::PointerType::kMouse) {
+    canceled_pointer_events.push_back(
         pointer_event_factory_.CreatePointerCancelEvent(
-            pointer_id, WebPointerProperties::PointerType::kTouch,
-            platform_time_stamp);
+            PointerEventFactory::kMouseId,
+            TimeTicks::FromSeconds(web_pointer_event.TimeStampSeconds())));
+  } else {
+    // TODO(nzolghadr): Maybe canceling all the scroll capable pointers is not
+    // the best strategy here. See the github issue for more details:
+    // https://github.com/w3c/pointerevents/issues/226
 
-    DCHECK(node_under_pointer_.Contains(pointer_id));
-    EventTarget* target = node_under_pointer_.at(pointer_id).target;
+    // Cancel all scroll capable pointers if the pointer is not mouse.
+    if (!scroll_capable_pointers_canceled_) {
+      Vector<int> scroll_capable_pointer_ids =
+          pointer_event_factory_.GetPointerIdsOfScrollCapablePointers();
 
-    ProcessCaptureAndPositionOfPointerEvent(pointer_event, target);
+      for (int pointer_id : scroll_capable_pointer_ids) {
+        canceled_pointer_events.push_back(
+            pointer_event_factory_.CreatePointerCancelEvent(
+                pointer_id,
+                TimeTicks::FromSeconds(web_pointer_event.TimeStampSeconds())));
+      }
 
-    // TODO(nzolghadr): This event follows implicit TE capture. The actual
-    // target would depend on PE capturing. Perhaps need to split TE/PE event
-    // path upstream?  crbug.com/579553.
+      scroll_capable_pointers_canceled_ = true;
+    }
+  }
+
+  for (auto pointer_event : canceled_pointer_events) {
+    // If we are sending a pointercancel we have sent the pointerevent to some
+    // target before.
+    DCHECK(node_under_pointer_.Contains(pointer_event->pointerId()));
+    EventTarget* target =
+        node_under_pointer_.at(pointer_event->pointerId()).target;
+
     DispatchPointerEvent(
         GetEffectiveTargetForPointerEvent(target, pointer_event->pointerId()),
         pointer_event);
 
     ReleasePointerCapture(pointer_event->pointerId());
 
-    // Sending the leave/out events and lostpointercapture
-    // because the next touch event will have a different id. So delayed
-    // sending of lostpointercapture won't work here.
-    ProcessCaptureAndPositionOfPointerEvent(pointer_event, nullptr);
+    // Send the leave/out events and lostpointercapture if needed.
+    // Note that for mouse due to the web compat we still don't send the
+    // boundary events and for now only send lostpointercapture if needed.
+    // Sending boundary events and possibly updating hover for mouse
+    // in this case may cause some of the existing pages to break.
+    if (web_pointer_event.pointer_type ==
+        WebPointerProperties::PointerType::kMouse) {
+      ProcessPendingPointerCapture(pointer_event);
+    } else {
+      ProcessCaptureAndPositionOfPointerEvent(pointer_event, nullptr);
+    }
 
     RemovePointer(pointer_event);
   }
 }
 
 void PointerEventManager::UnblockTouchPointers() {
-  in_canceled_state_for_pointer_type_touch_ = false;
+  scroll_capable_pointers_canceled_ = false;
 }
 
 WebInputEventResult PointerEventManager::HandleTouchEvents(
     const WebTouchEvent& event,
     const Vector<WebTouchEvent>& coalesced_events) {
   if (event.GetType() == WebInputEvent::kTouchScrollStarted) {
-    BlockTouchPointers(TimeTicks::FromSeconds(event.TimeStampSeconds()));
-    return WebInputEventResult::kHandledSystem;
+    WebPointerEvent web_pointer_event_cancel;
+    web_pointer_event_cancel.SetType(WebInputEvent::Type::kPointerCancel);
+    web_pointer_event_cancel.SetTimeStampSeconds(event.TimeStampSeconds());
+    web_pointer_event_cancel.pointer_type =
+        WebPointerProperties::PointerType::kTouch;
+    return HandlePointerEvent(web_pointer_event_cancel);
   }
 
   bool new_touch_sequence = true;
@@ -333,7 +361,7 @@
   // associated with so just pick the first finger.
   std::unique_ptr<UserGestureIndicator> holder;
   if (event.GetType() == WebInputEvent::kTouchEnd &&
-      !in_canceled_state_for_pointer_type_touch_ && event.touches_length &&
+      !scroll_capable_pointers_canceled_ && event.touches_length &&
       first_pointer_event_target.target_frame) {
     holder =
         Frame::NotifyUserActivation(first_pointer_event_target.target_frame);
@@ -432,7 +460,7 @@
   // required.
   // Do not send pointer events for stationary touches or null targetFrame
   if (pointer_event_target.target_node && pointer_event_target.target_frame &&
-      !in_canceled_state_for_pointer_type_touch_) {
+      !scroll_capable_pointers_canceled_) {
     PointerEvent* pointer_event = pointer_event_factory_.Create(
         touch_point, coalesced_events,
         static_cast<WebInputEvent::Modifiers>(modifiers),
@@ -461,7 +489,7 @@
 WebInputEventResult PointerEventManager::SendTouchPointerEvent(
     EventTarget* target,
     PointerEvent* pointer_event) {
-  if (in_canceled_state_for_pointer_type_touch_)
+  if (scroll_capable_pointers_canceled_)
     return WebInputEventResult::kNotHandled;
 
   ProcessCaptureAndPositionOfPointerEvent(pointer_event, target);
@@ -489,29 +517,16 @@
 }
 
 WebInputEventResult PointerEventManager::HandlePointerEvent(
-    const WebPointerEvent& web_pointer_event,
-    Node* target) {
+    const WebPointerEvent& web_pointer_event) {
   // TODO(crbug.com/625841): This function only handles pointercancel for now.
   // But we should extend it to handle any pointerevents.
   DCHECK(web_pointer_event.GetType() == WebInputEvent::Type::kPointerCancel);
-  PointerEvent* pointer_event =
-      pointer_event_factory_.CreatePointerCancelEvent(web_pointer_event);
 
-  EventTarget* effective_target =
-      GetEffectiveTargetForPointerEvent(target, pointer_event->pointerId());
-  WebInputEventResult result =
-      DispatchPointerEvent(effective_target, pointer_event);
+  if (web_pointer_event.GetType() == WebInputEvent::Type::kPointerCancel) {
+    DispatchPointerCancelEvents(web_pointer_event);
+  }
 
-  ReleasePointerCapture(pointer_event->pointerId());
-
-  // TODO(nzolghadr): Instead of |ProcessPendingPointerCapture| maybe we
-  // should have used ProcessCaptureAndPositionOfPointerEvent but that might
-  // be sending boundary events however we probably not want that all the
-  // time.
-  ProcessPendingPointerCapture(pointer_event);
-
-  RemovePointer(pointer_event);
-  return result;
+  return WebInputEventResult::kHandledSystem;
 }
 
 WebInputEventResult PointerEventManager::SendMousePointerEvent(
diff --git a/third_party/WebKit/Source/core/input/PointerEventManager.h b/third_party/WebKit/Source/core/input/PointerEventManager.h
index ae38ff4..47051df 100644
--- a/third_party/WebKit/Source/core/input/PointerEventManager.h
+++ b/third_party/WebKit/Source/core/input/PointerEventManager.h
@@ -34,7 +34,7 @@
   // cause firing DOM pointerevents, mouseevent, and touch events accordingly.
   // TODO(crbug.com/625841): We need to get all event handling path to go
   // through this function.
-  WebInputEventResult HandlePointerEvent(const WebPointerEvent&, Node* target);
+  WebInputEventResult HandlePointerEvent(const WebPointerEvent&);
 
   // Sends the mouse pointer events and the boundary events
   // that it may cause. It also sends the compat mouse events
@@ -137,11 +137,10 @@
     Member<PointerEvent> pointer_event_;
   };
 
-  // Inhibits firing of touch-type PointerEvents until unblocked by
-  // unblockTouchPointers(). Also sends pointercancels for existing touch-type
-  // PointerEvents.  See:
-  // www.w3.org/TR/pointerevents/#declaring-candidate-regions-for-default-touch-behaviors
-  void BlockTouchPointers(TimeTicks platform_time_stamp);
+  // Sends pointercancels for existing PointerEvents. For example when browser
+  // starts dragging with mouse or when we start scrolling with scroll capable
+  // pointers pointercancel events should be dispatched.
+  void DispatchPointerCancelEvents(const WebPointerEvent&);
 
   // Enables firing of touch-type PointerEvents after they were inhibited by
   // blockTouchPointers().
@@ -212,9 +211,9 @@
   bool prevent_mouse_event_for_pointer_type_
       [static_cast<size_t>(WebPointerProperties::PointerType::kLastEntry) + 1];
 
-  // Set upon TouchScrollStarted when sending a pointercancel, prevents PE
-  // dispatches for touches until all touch-points become inactive.
-  bool in_canceled_state_for_pointer_type_touch_;
+  // Set upon scrolling starts when sending a pointercancel, prevents PE
+  // dispatches for scroll capable pointers  until all of them become inactive.
+  bool scroll_capable_pointers_canceled_;
 
   Deque<uint32_t> touch_ids_for_canceled_pointerdowns_;
 
diff --git a/third_party/WebKit/Source/core/input/PointerEventManagerTest.cpp b/third_party/WebKit/Source/core/input/PointerEventManagerTest.cpp
new file mode 100644
index 0000000..8bb5db0b
--- /dev/null
+++ b/third_party/WebKit/Source/core/input/PointerEventManagerTest.cpp
@@ -0,0 +1,124 @@
+// 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 "core/dom/Document.h"
+#include "core/dom/events/EventListener.h"
+#include "core/html/HTMLElement.h"
+#include "core/input/EventHandler.h"
+#include "core/input/PointerEventManager.h"
+#include "core/testing/sim/SimRequest.h"
+#include "core/testing/sim/SimTest.h"
+
+namespace blink {
+
+namespace {
+class CheckPointerEventListenerCallback final : public EventListener {
+ public:
+  static CheckPointerEventListenerCallback* Create() {
+    return new CheckPointerEventListenerCallback();
+  }
+
+  bool operator==(const EventListener& other) const override {
+    return this == &other;
+  }
+
+  void handleEvent(ExecutionContext*, Event* event) override {
+    const String pointer_type = ((PointerEvent*)event)->pointerType();
+    if (pointer_type == "mouse")
+      mouse_event_received_count_++;
+    else if (pointer_type == "touch")
+      touch_event_received_count_++;
+    else if (pointer_type == "pen")
+      pen_event_received_count_++;
+  }
+
+  int mouseEventCount() const { return mouse_event_received_count_; }
+  int touchEventCount() const { return touch_event_received_count_; }
+  int penEventCount() const { return pen_event_received_count_; }
+
+ private:
+  CheckPointerEventListenerCallback()
+      : EventListener(EventListener::kCPPEventListenerType) {}
+  int mouse_event_received_count_ = 0;
+  int touch_event_received_count_ = 0;
+  int pen_event_received_count_ = 0;
+};
+
+}  // namespace
+
+class PointerEventManagerTest : public SimTest {
+ protected:
+  EventHandler& EventHandler() {
+    return GetDocument().GetFrame()->GetEventHandler();
+  }
+};
+
+TEST_F(PointerEventManagerTest, PointerCancelsOfAllTypes) {
+  WebView().Resize(WebSize(400, 400));
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(
+      "<body style='padding: 0px; width: 400px; height: 400px;'>"
+      "<div draggable='true' style='width: 150px; height: 150px;'></div>"
+      "</body>");
+  CheckPointerEventListenerCallback* callback =
+      CheckPointerEventListenerCallback::Create();
+  GetDocument().body()->addEventListener(EventTypeNames::pointercancel,
+                                         callback);
+
+  WebTouchEvent event;
+  event.SetFrameScale(1);
+  WebTouchPoint point(
+      WebPointerProperties(1, WebPointerProperties::PointerType::kTouch,
+                           WebPointerProperties::Button::kLeft,
+                           WebFloatPoint(100, 100), WebFloatPoint(100, 100)));
+  point.state = WebTouchPoint::State::kStatePressed;
+  event.touches[event.touches_length++] = point;
+  event.SetType(WebInputEvent::kTouchStart);
+  EventHandler().HandleTouchEvent(event, Vector<WebTouchEvent>());
+
+  point.pointer_type = WebPointerProperties::PointerType::kPen;
+  event.touches[0] = point;
+  event.SetType(WebInputEvent::kTouchStart);
+  EventHandler().HandleTouchEvent(event, Vector<WebTouchEvent>());
+
+  WebMouseEvent mouse_down_event(
+      WebInputEvent::kMouseDown, WebFloatPoint(100, 100),
+      WebFloatPoint(100, 100), WebPointerProperties::Button::kLeft, 0, 0, 0);
+  mouse_down_event.SetFrameScale(1);
+  EventHandler().HandleMousePressEvent(mouse_down_event);
+
+  ASSERT_EQ(callback->mouseEventCount(), 0);
+  ASSERT_EQ(callback->touchEventCount(), 0);
+  ASSERT_EQ(callback->penEventCount(), 0);
+
+  point.pointer_type = WebPointerProperties::PointerType::kPen;
+  event.touches[0] = point;
+  event.SetType(WebInputEvent::kTouchScrollStarted);
+  EventHandler().HandleTouchEvent(event, Vector<WebTouchEvent>());
+  ASSERT_EQ(callback->mouseEventCount(), 0);
+  ASSERT_EQ(callback->touchEventCount(), 1);
+  ASSERT_EQ(callback->penEventCount(), 1);
+
+  point.pointer_type = WebPointerProperties::PointerType::kTouch;
+  event.touches[0] = point;
+  event.SetType(WebInputEvent::kTouchScrollStarted);
+  EventHandler().HandleTouchEvent(event, Vector<WebTouchEvent>());
+  ASSERT_EQ(callback->mouseEventCount(), 0);
+  ASSERT_EQ(callback->touchEventCount(), 1);
+  ASSERT_EQ(callback->penEventCount(), 1);
+
+  WebMouseEvent mouse_move_event(
+      WebInputEvent::kMouseMove, WebFloatPoint(200, 200),
+      WebFloatPoint(200, 200), WebPointerProperties::Button::kLeft, 0, 0, 0);
+  mouse_move_event.SetFrameScale(1);
+  EventHandler().HandleMouseMoveEvent(mouse_move_event,
+                                      Vector<WebMouseEvent>());
+
+  ASSERT_EQ(callback->mouseEventCount(), 1);
+  ASSERT_EQ(callback->touchEventCount(), 1);
+  ASSERT_EQ(callback->penEventCount(), 1);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/shapes/Shape.cpp b/third_party/WebKit/Source/core/layout/shapes/Shape.cpp
index 26c8a05c..f0c1e267c 100644
--- a/third_party/WebKit/Source/core/layout/shapes/Shape.cpp
+++ b/third_party/WebKit/Source/core/layout/shapes/Shape.cpp
@@ -256,8 +256,10 @@
                 Image::kDoNotClampImageToSourceRect, Image::kSyncDecode);
 
     WTF::ArrayBufferContents contents;
-    image_buffer->GetImageData(IntRect(IntPoint(), image_rect.Size()),
-                               contents);
+    bool image_data_exists = image_buffer->GetImageData(
+        IntRect(IntPoint(), image_rect.Size()), contents);
+    if (!image_data_exists)
+      return nullptr;
     DOMArrayBuffer* array_buffer = DOMArrayBuffer::Create(contents);
     DOMUint8ClampedArray* pixel_array = DOMUint8ClampedArray::Create(
         array_buffer, 0, array_buffer->ByteLength());
diff --git a/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp b/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp
index 8c0ea04..22c655df 100644
--- a/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp
+++ b/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp
@@ -172,9 +172,16 @@
       layout_box_, layout_box_.GetDocument(), layout_box_.StyleRef(),
       FlooredIntSize(image_size), nullptr);
 
-  return Shape::CreateRasterShape(image.get(), shape_image_threshold,
-                                  image_rect, margin_rect, writing_mode,
-                                  margin);
+  std::unique_ptr<Shape> new_shape =
+      Shape::CreateRasterShape(image.get(), shape_image_threshold, image_rect,
+                               margin_rect, writing_mode, margin);
+  if (!new_shape) {
+    layout_box_.GetDocument().AddConsoleMessage(
+        ConsoleMessage::Create(kRenderingMessageSource, kErrorMessageLevel,
+                               "The shape-outside image is too large."));
+    return Shape::CreateEmptyRasterShape(writing_mode, margin);
+  }
+  return new_shape;
 }
 
 const Shape& ShapeOutsideInfo::ComputedShape() const {
diff --git a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
index dec9af58..0c42618 100644
--- a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
@@ -227,35 +227,38 @@
 }
 
 void BoxPaintInvalidator::InvalidateScrollingContentsBackground(
-    BackgroundInvalidationType backgroundInvalidationType) {
+    BackgroundInvalidationType background_invalidation_type) {
   if (!BackgroundPaintsOntoScrollingContentsLayer())
     return;
-  if (backgroundInvalidationType == BackgroundInvalidationType::kNone)
+  if (background_invalidation_type == BackgroundInvalidationType::kNone)
     return;
 
-  // TODO(crbug.com/732611): Implement raster invalidation of background on
-  // scrolling contents layer for SPv175.
-  if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
+  PaintInvalidationReason reason;
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
+    reason = background_invalidation_type == BackgroundInvalidationType::kFull
+                 ? PaintInvalidationReason::kBackgroundOnScrollingContentsLayer
+                 : PaintInvalidationReason::kIncremental;
+  } else {
+    // For SPv1 we need this reason for both full and incremental invalidation
+    // to let ObjectPaintInvalidator::SetBackingNeedsPaintInvalidationInRect()
+    // know we are invalidating on the scrolling contents backing.
+    reason = PaintInvalidationReason::kBackgroundOnScrollingContentsLayer;
     const LayoutRect& old_layout_overflow = box_.PreviousLayoutOverflowRect();
     LayoutRect new_layout_overflow = box_.LayoutOverflowRect();
-    if (backgroundInvalidationType == BackgroundInvalidationType::kFull) {
+    if (background_invalidation_type == BackgroundInvalidationType::kFull) {
       ObjectPaintInvalidatorWithContext(box_, context_)
-          .FullyInvalidatePaint(
-              PaintInvalidationReason::kBackgroundOnScrollingContentsLayer,
-              old_layout_overflow, new_layout_overflow);
+          .FullyInvalidatePaint(reason, old_layout_overflow,
+                                new_layout_overflow);
     } else {
-      IncrementallyInvalidatePaint(
-          PaintInvalidationReason::kBackgroundOnScrollingContentsLayer,
-          old_layout_overflow, new_layout_overflow);
+      IncrementallyInvalidatePaint(reason, old_layout_overflow,
+                                   new_layout_overflow);
     }
   }
 
   context_.painting_layer->SetNeedsRepaint();
-  // Currently we use CompositedLayerMapping as the DisplayItemClient to paint
-  // background on the scrolling contents layer.
   ObjectPaintInvalidator(box_).InvalidateDisplayItemClient(
       *box_.Layer()->GetCompositedLayerMapping()->ScrollingContentsLayer(),
-      PaintInvalidationReason::kBackgroundOnScrollingContentsLayer);
+      reason);
 }
 
 PaintInvalidationReason BoxPaintInvalidator::InvalidatePaint() {
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 5776c3d8..8e5a18b 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -1683,6 +1683,7 @@
     "//components/viz/test:test_support",
     "//testing/gmock",
     "//testing/gtest:gtest",
+    "//testing/perf",
   ]
 
   deps = [
@@ -1959,6 +1960,7 @@
     "testing/BlinkPerfTestSuite.cpp",
     "testing/BlinkPerfTestSuite.h",
     "testing/RunAllPerfTests.cpp",
+    "testing/ShapingLineBreakerPerfTest.cpp",
   ]
 
   configs += [
@@ -1975,6 +1977,7 @@
     "//base/test:test_support",
     "//testing/gtest",
     "//testing/perf",
+    "//third_party:freetype_harfbuzz",
     "//third_party/WebKit/Source/platform/scheduler:perf_tests",
   ]
 }
diff --git a/third_party/WebKit/Source/platform/testing/DEPS b/third_party/WebKit/Source/platform/testing/DEPS
index 8993c42d8..34e99e32 100644
--- a/third_party/WebKit/Source/platform/testing/DEPS
+++ b/third_party/WebKit/Source/platform/testing/DEPS
@@ -14,4 +14,5 @@
     "+cc",
     "+components/viz/test",
     "+mojo/edk/embedder",
+    '+testing',
 ]
diff --git a/third_party/WebKit/Source/platform/testing/ShapingLineBreakerPerfTest.cpp b/third_party/WebKit/Source/platform/testing/ShapingLineBreakerPerfTest.cpp
new file mode 100644
index 0000000..46981fba
--- /dev/null
+++ b/third_party/WebKit/Source/platform/testing/ShapingLineBreakerPerfTest.cpp
@@ -0,0 +1,147 @@
+// 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 "platform/fonts/shaping/ShapingLineBreaker.h"
+
+#include <unicode/uscript.h>
+#include "base/time/time.h"
+#include "cc/base/lap_timer.h"
+#include "platform/fonts/Font.h"
+#include "platform/fonts/FontCache.h"
+#include "platform/fonts/FontTestUtilities.h"
+#include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
+#include "platform/fonts/shaping/ShapeResultTestInfo.h"
+#include "platform/text/TextBreakIterator.h"
+#include "platform/text/TextRun.h"
+#include "platform/wtf/Vector.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace blink {
+namespace {
+
+static const int kTimeLimitMillis = 2000;
+static const int kWarmupRuns = 5;
+static const int kTimeCheckInterval = 10;
+
+LayoutUnit ShapeText(ShapingLineBreaker* breaker,
+                     LayoutUnit available_space,
+                     unsigned string_length) {
+  unsigned break_offset = 0;
+  LayoutUnit total_width;
+  ShapingLineBreaker::Result result;
+  RefPtr<ShapeResult> shape_result;
+  while (break_offset < string_length) {
+    shape_result = breaker->ShapeLine(break_offset, available_space, &result);
+    break_offset = result.break_offset;
+    total_width += shape_result->SnappedWidth();
+  }
+  return total_width;
+}
+
+}  // anonymous namespace
+
+class ShapingLineBreakerPerfTest : public ::testing::Test {
+ public:
+  ShapingLineBreakerPerfTest()
+      : timer_(kWarmupRuns,
+               base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+               kTimeCheckInterval) {}
+
+  void SetUp() override {
+    font_description.SetComputedSize(12.0);
+    font = Font(font_description);
+    font.Update(nullptr);
+  }
+
+  void TearDown() override {}
+
+  FontCachePurgePreventer font_cache_purge_preventer;
+  FontDescription font_description;
+  Font font;
+  unsigned start_index = 0;
+  unsigned num_glyphs = 0;
+  hb_script_t script = HB_SCRIPT_INVALID;
+  cc::LapTimer timer_;
+};
+
+TEST_F(ShapingLineBreakerPerfTest, ShapeLatinText) {
+  // "My Brother's Keeper?"
+  // By William Arthur Dunkerley (John Oxenham)
+  // In the public domain.
+  String string(
+      u"\"Am I my brother's keeper?\""
+      "Yes, of a truth!"
+      "Thine asking is thine answer."
+      "That self-condemning cry of Cain"
+      "Has been the plea of every selfish soul since then,"
+      "Which hath its brother slain."
+      "God's word is plain,"
+      "And doth thy shrinking soul arraign."
+      ""
+      "Thy brother's keeper?"
+      "Yea, of a truth thou art!"
+      "For if not--who?"
+      "Are ye not both,--both thou and he"
+      "Of God's great family?"
+      "How rid thee of thy soul's responsibility?"
+      "For every ill in all the world"
+      "Each soul is sponsor and account must bear."
+      "And He, and he thy brother of despair,"
+      "Claim, of thy overmuch, their share."
+      ""
+      "Thou hast had good, and he the strangled days;"
+      "But now,--the old things pass."
+      "No longer of thy grace"
+      "Is he content to live in evil case"
+      "For the anointing of thy shining face."
+      "The old things pass.--Beware lest ye pass with them,"
+      "And your place"
+      "Become an emptiness!"
+      ""
+      "Beware!    Lest, when the \"Have-nots\" claim,"
+      "From those who have, their rightful share,"
+      "Thy borders be swept bare"
+      "As by the final flame."
+      "Better to share before than after."
+      "\"After?\" ...    For thee may be no after!"
+      "Only the howl of mocking laughter"
+      "At thy belated care.    Make no mistake!--"
+      "\"After\" will be too late."
+      "When once the \"Have-nots\" claim ...    they take."
+      "\"After!\" ...    When that full claim is made,"
+      "You and your golden gods may all lie dead."
+      ""
+      "Set now your house in order,"
+      "Ere it be too late!"
+      "For, once the storm of hate"
+      "Be loosed, no man shall stay it till"
+      "Its thirst has slaked its fill,"
+      "And you, poor victims of this last \"too late,\""
+      "Shall in the shadows mourn your lost estate.");
+  unsigned len = string.length();
+  LazyLineBreakIterator break_iterator(string, "en-US", LineBreakType::kNormal);
+  TextDirection direction = TextDirection::kLtr;
+
+  HarfBuzzShaper shaper(string.Characters16(), len);
+  RefPtr<ShapeResult> result = shaper.Shape(&font, direction);
+  ShapingLineBreaker breaker(&shaper, &font, result.get(), &break_iterator);
+
+  RefPtr<ShapeResult> line;
+  LayoutUnit available_width_px(500);
+
+  LayoutUnit expected_width = ShapeText(&breaker, available_width_px, len);
+  timer_.Reset();
+  do {
+    LayoutUnit width = ShapeText(&breaker, available_width_px, len);
+    EXPECT_EQ(expected_width, width);
+    timer_.NextLap();
+  } while (!timer_.HasTimeLimitExpired());
+
+  perf_test::PrintResult("ShapingLineBreakerPerfTest", "shape latin text", "",
+                         timer_.LapsPerSecond(), "runs/s", true);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/testing/data/third_party/Amiri/README b/third_party/WebKit/Source/platform/testing/data/third_party/Amiri/README
new file mode 100644
index 0000000..a7071c1
--- /dev/null
+++ b/third_party/WebKit/Source/platform/testing/data/third_party/Amiri/README
@@ -0,0 +1,90 @@
+Amiri is a classical Arabic typeface in Naskh style for typesetting books and other running text. Its design is a revival of the beautiful typeface pioneered in early 20th century by Bulaq Press in Cairo, also known as Amiria Press, after which the font is named.
+Read more about the project at www.amirifont.org
+Updated in July 2017 to v0.109
+
+SIL OPEN FONT LICENSE
+
+Version 1.1 - 26 February 2007
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded, 
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting — in part or in whole — any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
\ No newline at end of file
diff --git a/third_party/WebKit/Source/platform/testing/data/third_party/Amiri/amiri_arabic.woff2 b/third_party/WebKit/Source/platform/testing/data/third_party/Amiri/amiri_arabic.woff2
new file mode 100644
index 0000000..da20321
--- /dev/null
+++ b/third_party/WebKit/Source/platform/testing/data/third_party/Amiri/amiri_arabic.woff2
Binary files differ
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index 6eede7f..c3d0da1 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: 3fae8ff07c097da6d0042510bdbe5b16c67a8e12
+Revision: 6950a552bfab43f05d6644811271f8f5c3b91c20
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/client/annotation.h b/third_party/crashpad/crashpad/client/annotation.h
index 141aa12..f76ddf68 100644
--- a/third_party/crashpad/crashpad/client/annotation.h
+++ b/third_party/crashpad/crashpad/client/annotation.h
@@ -67,10 +67,10 @@
 //! are permanently referenced by a global object.
 class Annotation {
  public:
-  //! \brief The maximum length of the #name field in bytes.
+  //! \brief The maximum length of an annotation’s name, in bytes.
   static constexpr size_t kNameMaxLength = 64;
 
-  //! \brief The maximum size of the #value field in bytes.
+  //! \brief The maximum size of an annotation’s value, in bytes.
   static constexpr size_t kValueMaxSize = 2048;
 
   //! \brief The type used for \a SetSize().
diff --git a/third_party/crashpad/crashpad/client/crashpad_info.h b/third_party/crashpad/crashpad/client/crashpad_info.h
index 7ce55ed..fc391bf 100644
--- a/third_party/crashpad/crashpad/client/crashpad_info.h
+++ b/third_party/crashpad/crashpad/client/crashpad_info.h
@@ -116,15 +116,15 @@
   //! typed data and it is not limited to a dictionary form. Annotations are
   //! interpreted by Crashpad as module-level annotations.
   //!
-  //! Annotations may exist in \a annotations_list at the time that this
-  //! method is called, or they may be added, removed, or modified in \a
-  //! annotations_list after this method is called.
+  //! Annotations may exist in \a list at the time that this method is called,
+  //! or they may be added, removed, or modified in \a list after this method is
+  //! called.
   //!
-  //! \param[in] annotations_list A list of set Annotation objects that maintain
-  //!     arbitrary, typed key-value state. The CrashpadInfo object does not
-  //!     take ownership of the AnnotationsList object. It is the caller’s
-  //!     responsibility to ensure that this pointer remains valid while it is
-  //!     in effect for a CrashpadInfo object.
+  //! \param[in] list A list of set Annotation objects that maintain arbitrary,
+  //!     typed key-value state. The CrashpadInfo object does not take ownership
+  //!     of the AnnotationsList object. It is the caller’s responsibility to
+  //!     ensure that this pointer remains valid while it is in effect for a
+  //!     CrashpadInfo object.
   //!
   //! \sa annotations_list()
   //! \sa AnnotationList::Register()
diff --git a/third_party/crashpad/crashpad/handler/crashpad_handler_test.cc b/third_party/crashpad/crashpad/handler/crashpad_handler_test.cc
index 1534443..65fed90f 100644
--- a/third_party/crashpad/crashpad/handler/crashpad_handler_test.cc
+++ b/third_party/crashpad/crashpad/handler/crashpad_handler_test.cc
@@ -37,8 +37,8 @@
 constexpr DWORD kExpectedExitCode = 0x1CEB00DA;
 
 void StartAndCrashWithExtendedHandler(const base::FilePath& temp_dir) {
-  base::FilePath handler_path = TestPaths::Executable().DirName().Append(
-      FILE_PATH_LITERAL("crashpad_handler_test_extended_handler.exe"));
+  base::FilePath handler_path = TestPaths::BuildArtifact(
+      L"handler", L"extended_handler", TestPaths::FileType::kExecutable);
 
   CrashpadClient client;
   ASSERT_TRUE(client.StartHandler(handler_path,
diff --git a/third_party/crashpad/crashpad/handler/main.cc b/third_party/crashpad/crashpad/handler/main.cc
index bc4ab99b..c0a04f40 100644
--- a/third_party/crashpad/crashpad/handler/main.cc
+++ b/third_party/crashpad/crashpad/handler/main.cc
@@ -22,10 +22,13 @@
 #endif
 
 #if defined(OS_MACOSX)
+
 int main(int argc, char* argv[]) {
   return crashpad::HandlerMain(argc, argv, nullptr);
 }
+
 #elif defined(OS_WIN)
+
 namespace {
 
 int HandlerMainAdaptor(int argc, char* argv[]) {
@@ -34,7 +37,17 @@
 
 }  // namespace
 
+// The default entry point for /subsystem:windows. In Crashpad’s own build, this
+// is used by crashpad_handler.exe. It’s also used by crashpad_handler.com when
+// produced by editbin from a copy of crashpad_handler.exe.
 int APIENTRY wWinMain(HINSTANCE, HINSTANCE, wchar_t*, int) {
   return crashpad::ToolSupport::Wmain(__argc, __wargv, HandlerMainAdaptor);
 }
+
+// The default entry point for /subsystem:console. This is not currently used by
+// Crashpad’s own build, but may be used by other builds.
+int wmain(int argc, wchar_t* argv[]) {
+  return crashpad::ToolSupport::Wmain(argc, argv, HandlerMainAdaptor);
+}
+
 #endif  // OS_MACOSX
diff --git a/third_party/crashpad/crashpad/handler/win/crash_other_program.cc b/third_party/crashpad/crashpad/handler/win/crash_other_program.cc
index 93a3a07..ddad4c53 100644
--- a/third_party/crashpad/crashpad/handler/win/crash_other_program.cc
+++ b/third_party/crashpad/crashpad/handler/win/crash_other_program.cc
@@ -90,8 +90,8 @@
 
   // Launch another process that hangs.
   base::FilePath test_executable = TestPaths::Executable();
-  std::wstring child_test_executable =
-      test_executable.DirName().Append(L"hanging_program.exe").value();
+  base::FilePath child_test_executable =
+      test_executable.DirName().Append(L"hanging_program.exe");
   ChildLauncher child(child_test_executable, argv[1]);
   child.Start();
   if (testing::Test::HasFatalFailure()) {
diff --git a/third_party/crashpad/crashpad/minidump/minidump.gyp b/third_party/crashpad/crashpad/minidump/minidump.gyp
index 3135de3d..e36006c 100644
--- a/third_party/crashpad/crashpad/minidump/minidump.gyp
+++ b/third_party/crashpad/crashpad/minidump/minidump.gyp
@@ -33,6 +33,8 @@
         '..',
       ],
       'sources': [
+        'minidump_byte_array_writer.cc',
+        'minidump_byte_array_writer.h',
         'minidump_context.h',
         'minidump_context_writer.cc',
         'minidump_context_writer.h',
diff --git a/third_party/crashpad/crashpad/minidump/minidump_byte_array_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_byte_array_writer.cc
new file mode 100644
index 0000000..05b698db
--- /dev/null
+++ b/third_party/crashpad/crashpad/minidump/minidump_byte_array_writer.cc
@@ -0,0 +1,73 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "minidump/minidump_byte_array_writer.h"
+
+#include "base/logging.h"
+#include "util/file/file_writer.h"
+#include "util/numeric/safe_assignment.h"
+
+namespace crashpad {
+
+MinidumpByteArrayWriter::MinidumpByteArrayWriter()
+    : minidump_array_(new MinidumpByteArray()) {}
+
+MinidumpByteArrayWriter::~MinidumpByteArrayWriter() = default;
+
+void MinidumpByteArrayWriter::set_data(const uint8_t* data, size_t size) {
+  data_.clear();
+  data_.insert(data_.begin(), data, data + size);
+}
+
+bool MinidumpByteArrayWriter::Freeze() {
+  DCHECK_EQ(state(), kStateMutable);
+
+  if (!MinidumpWritable::Freeze()) {
+    return false;
+  }
+
+  size_t size = data_.size();
+  if (!AssignIfInRange(&minidump_array_->length, size)) {
+    LOG(ERROR) << "data size " << size << " is out of range";
+    return false;
+  }
+
+  return true;
+}
+
+size_t MinidumpByteArrayWriter::SizeOfObject() {
+  DCHECK_EQ(state(), kStateFrozen);
+
+  return sizeof(*minidump_array_) + data_.size();
+}
+
+bool MinidumpByteArrayWriter::WriteObject(FileWriterInterface* file_writer) {
+  DCHECK_EQ(state(), kStateWritable);
+
+  WritableIoVec iov;
+  iov.iov_base = minidump_array_.get();
+  iov.iov_len = sizeof(*minidump_array_);
+
+  std::vector<WritableIoVec> iovecs(1, iov);
+
+  if (!data_.empty()) {
+    iov.iov_base = data_.data();
+    iov.iov_len = data_.size();
+    iovecs.push_back(iov);
+  }
+
+  return file_writer->WriteIoVec(&iovecs);
+}
+
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/minidump/minidump_byte_array_writer.h b/third_party/crashpad/crashpad/minidump/minidump_byte_array_writer.h
new file mode 100644
index 0000000..c399f03
--- /dev/null
+++ b/third_party/crashpad/crashpad/minidump/minidump_byte_array_writer.h
@@ -0,0 +1,65 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_MINIDUMP_MINIDUMP_BYTE_ARRAY_WRITER_H_
+#define CRASHPAD_MINIDUMP_MINIDUMP_BYTE_ARRAY_WRITER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "minidump/minidump_extensions.h"
+#include "minidump/minidump_writable.h"
+
+namespace crashpad {
+
+//! \brief Writes a variable-length byte array for a minidump into a
+//!     \sa MinidumpByteArray.
+class MinidumpByteArrayWriter final : public internal::MinidumpWritable {
+ public:
+  MinidumpByteArrayWriter();
+  ~MinidumpByteArrayWriter() override;
+
+  //! \brief Sets the data to be written.
+  //!
+  //! \note Valid in #kStateMutable.
+  void set_data(const std::vector<uint8_t>& data) { data_ = data; }
+
+  //! \brief Sets the data to be written.
+  //!
+  //! \note Valid in #kStateMutable.
+  void set_data(const uint8_t* data, size_t size);
+
+  //! \brief Gets the data to be written.
+  //!
+  //! \note Valid in any state.
+  const std::vector<uint8_t>& data() const { return data_; }
+
+ protected:
+  // MinidumpWritable:
+
+  bool Freeze() override;
+  size_t SizeOfObject() override;
+  bool WriteObject(FileWriterInterface* file_writer) override;
+
+ private:
+  std::unique_ptr<MinidumpByteArray> minidump_array_;
+  std::vector<uint8_t> data_;
+
+  DISALLOW_COPY_AND_ASSIGN(MinidumpByteArrayWriter);
+};
+
+}  // namespace crashpad
+
+#endif  // CRASHPAD_MINIDUMP_MINIDUMP_BYTE_ARRAY_WRITER_H_
diff --git a/third_party/crashpad/crashpad/minidump/minidump_byte_array_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_byte_array_writer_test.cc
new file mode 100644
index 0000000..f20ad35a
--- /dev/null
+++ b/third_party/crashpad/crashpad/minidump/minidump_byte_array_writer_test.cc
@@ -0,0 +1,80 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "minidump/minidump_byte_array_writer.h"
+
+#include <memory>
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "gtest/gtest.h"
+#include "minidump/test/minidump_writable_test_util.h"
+#include "util/file/string_file.h"
+
+namespace crashpad {
+namespace test {
+namespace {
+
+TEST(MinidumpByteArrayWriter, Write) {
+  const std::vector<uint8_t> kTests[] = {
+      {'h', 'e', 'l', 'l', 'o'},
+      {0x42, 0x99, 0x00, 0xbe},
+      {0x00},
+      {},
+  };
+
+  for (size_t i = 0; i < arraysize(kTests); ++i) {
+    SCOPED_TRACE(base::StringPrintf("index %" PRIuS, i));
+
+    StringFile string_file;
+
+    crashpad::MinidumpByteArrayWriter writer;
+    writer.set_data(kTests[i]);
+    EXPECT_TRUE(writer.WriteEverything(&string_file));
+
+    ASSERT_EQ(string_file.string().size(),
+              sizeof(MinidumpByteArray) + kTests[i].size());
+
+    auto byte_array = std::make_unique<MinidumpByteArray>();
+    EXPECT_EQ(string_file.Seek(0, SEEK_SET), 0);
+    string_file.Read(byte_array.get(), sizeof(*byte_array));
+
+    EXPECT_EQ(byte_array->length, kTests[i].size());
+
+    std::vector<uint8_t> data(byte_array->length);
+    string_file.Read(data.data(), byte_array->length);
+
+    EXPECT_EQ(data, kTests[i]);
+  }
+}
+
+TEST(MinidumpByteArrayWriter, SetData) {
+  const std::vector<uint8_t> kTests[] = {
+    {1, 2, 3, 4, 5},
+    {0x0},
+    {},
+  };
+
+  for (size_t i = 0; i < arraysize(kTests); ++i) {
+    SCOPED_TRACE(base::StringPrintf("index %" PRIuS, i));
+
+    crashpad::MinidumpByteArrayWriter writer;
+    writer.set_data(kTests[i].data(), kTests[i].size());
+    EXPECT_EQ(writer.data(), kTests[i]);
+  }
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc
index c6c29d9..218d7775a 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc
+++ b/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc
@@ -23,6 +23,7 @@
 #include "base/logging.h"
 #include "snapshot/cpu_context.h"
 #include "util/file/file_writer.h"
+#include "util/stdlib/aligned_allocator.h"
 
 namespace crashpad {
 
@@ -65,10 +66,8 @@
     }
 
     case kCPUArchitectureX86_64: {
-      MSVC_PUSH_DISABLE_WARNING(4316);  // Object on heap may not be aligned.
       MinidumpContextAMD64Writer* context_amd64 =
           new MinidumpContextAMD64Writer();
-      MSVC_POP_WARNING();  // C4316
       context.reset(context_amd64);
       context_amd64->InitializeFromSnapshot(context_snapshot->x86_64);
       break;
@@ -152,6 +151,12 @@
   return sizeof(context_);
 }
 
+static_assert(alignof(MinidumpContextAMD64) >= 16,
+              "MinidumpContextAMD64 alignment");
+static_assert(alignof(MinidumpContextAMD64Writer) >=
+                  alignof(MinidumpContextAMD64),
+              "MinidumpContextAMD64Writer alignment");
+
 MinidumpContextAMD64Writer::MinidumpContextAMD64Writer()
     : MinidumpContextWriter(), context_() {
   context_.context_flags = kMinidumpContextAMD64;
@@ -160,6 +165,20 @@
 MinidumpContextAMD64Writer::~MinidumpContextAMD64Writer() {
 }
 
+// static
+void* MinidumpContextAMD64Writer::operator new(size_t size) {
+  // MinidumpContextAMD64 requests an alignment of 16, which can be larger than
+  // what standard new provides. This may trigger MSVC warning C4316. As a
+  // workaround to this language deficiency, provide a custom allocation
+  // function to allocate a block meeting the alignment requirement.
+  return AlignedAllocate(alignof(MinidumpContextAMD64Writer), size);
+}
+
+// static
+void MinidumpContextAMD64Writer::operator delete(void* pointer) {
+  return AlignedFree(pointer);
+}
+
 void MinidumpContextAMD64Writer::InitializeFromSnapshot(
     const CPUContextX86_64* context_snapshot) {
   DCHECK_EQ(state(), kStateMutable);
diff --git a/third_party/crashpad/crashpad/minidump/minidump_context_writer.h b/third_party/crashpad/crashpad/minidump/minidump_context_writer.h
index 29bc3ee..25d717e 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_context_writer.h
+++ b/third_party/crashpad/crashpad/minidump/minidump_context_writer.h
@@ -110,6 +110,16 @@
   MinidumpContextAMD64Writer();
   ~MinidumpContextAMD64Writer() override;
 
+  // Ensure proper alignment of heap-allocated objects. This should not be
+  // necessary in C++17.
+  static void* operator new(size_t size);
+  static void operator delete(void* ptr);
+
+  // Prevent unaligned heap-allocated arrays. Provisions could be made to allow
+  // these if necessary, but there is currently no use for them.
+  static void* operator new[](size_t size) = delete;
+  static void operator delete[](void* ptr) = delete;
+
   //! \brief Initializes the MinidumpContextAMD64 based on \a context_snapshot.
   //!
   //! \param[in] context_snapshot The context snapshot to use as source data.
diff --git a/third_party/crashpad/crashpad/minidump/minidump_context_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_context_writer_test.cc
index 0c2b5ea2..82b4db7 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_context_writer_test.cc
+++ b/third_party/crashpad/crashpad/minidump/minidump_context_writer_test.cc
@@ -69,6 +69,15 @@
 }
 
 TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) {
+  {
+    // Make sure that a heap-allocated context writer has the proper alignment,
+    // because it may be nonstandard.
+    auto context_writer = std::make_unique<MinidumpContextAMD64Writer>();
+    EXPECT_EQ(reinterpret_cast<uintptr_t>(context_writer.get()) &
+                  (alignof(MinidumpContextAMD64Writer) - 1),
+              0u);
+  }
+
   StringFile string_file;
 
   {
diff --git a/third_party/crashpad/crashpad/minidump/minidump_extensions.h b/third_party/crashpad/crashpad/minidump/minidump_extensions.h
index f361566..ad69aecb 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_extensions.h
+++ b/third_party/crashpad/crashpad/minidump/minidump_extensions.h
@@ -118,6 +118,17 @@
   uint8_t Buffer[0];
 };
 
+//! \brief A variable-length array of bytes carried within a minidump file.
+//!     The data have no intrinsic type and should be interpreted according
+//!     to their referencing context.
+struct ALIGNAS(4) PACKED MinidumpByteArray {
+  //! \brief The length of the #data field.
+  uint32_t length;
+
+  //! \brief The bytes of data.
+  uint8_t data[0];
+};
+
 //! \brief CPU type values for MINIDUMP_SYSTEM_INFO::ProcessorArchitecture.
 //!
 //! \sa \ref PROCESSOR_ARCHITECTURE_x "PROCESSOR_ARCHITECTURE_*"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_file_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_file_writer_test.cc
index 448ee60b..e41ed75f 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_file_writer_test.cc
+++ b/third_party/crashpad/crashpad/minidump/minidump_file_writer_test.cc
@@ -21,6 +21,7 @@
 #include <utility>
 
 #include "base/compiler_specific.h"
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 #include "minidump/minidump_stream_writer.h"
 #include "minidump/minidump_user_extension_stream_data_source.h"
@@ -395,9 +396,18 @@
   // In a 32-bit environment, this will give a “timestamp out of range” warning,
   // but the test should complete without failure.
   constexpr uint32_t kSnapshotTime = 0xfd469ab8;
+#if defined(COMPILER_GCC) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wconstant-conversion"
+#define DISABLED_WCONSTANT_CONVERSION
+#endif  // COMPILER_GCC || __clang__
   MSVC_SUPPRESS_WARNING(4309);  // Truncation of constant value.
   MSVC_SUPPRESS_WARNING(4838);  // Narrowing conversion.
   constexpr timeval kSnapshotTimeval = {static_cast<time_t>(kSnapshotTime), 0};
+#if defined(DISABLED_WCONSTANT_CONVERSION)
+#pragma GCC diagnostic pop
+#undef DISABLED_WCONSTANT_CONVERSION
+#endif  // DISABLED_WCONSTANT_CONVERSION
 
   TestProcessSnapshot process_snapshot;
   process_snapshot.SetSnapshotTime(kSnapshotTimeval);
diff --git a/third_party/crashpad/crashpad/minidump/minidump_test.gyp b/third_party/crashpad/crashpad/minidump/minidump_test.gyp
index 80f803db..beb4151 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_test.gyp
+++ b/third_party/crashpad/crashpad/minidump/minidump_test.gyp
@@ -29,6 +29,8 @@
         '..',
       ],
       'sources': [
+        'test/minidump_byte_array_writer_test_util.cc',
+        'test/minidump_byte_array_writer_test_util.h',
         'test/minidump_context_test_util.cc',
         'test/minidump_context_test_util.h',
         'test/minidump_file_writer_test_util.cc',
@@ -62,6 +64,7 @@
         '..',
       ],
       'sources': [
+        'minidump_byte_array_writer_test.cc',
         'minidump_context_writer_test.cc',
         'minidump_crashpad_info_writer_test.cc',
         'minidump_exception_writer_test.cc',
diff --git a/third_party/crashpad/crashpad/minidump/minidump_thread_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_thread_writer_test.cc
index 3e8e7de..60173da2 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_thread_writer_test.cc
+++ b/third_party/crashpad/crashpad/minidump/minidump_thread_writer_test.cc
@@ -220,13 +220,7 @@
       kMemoryBase, kMemorySize, kMemoryValue);
   thread_writer->SetStack(std::move(memory_writer));
 
-  // Object allocated on heap may not be aligned.
-  MSVC_PUSH_DISABLE_WARNING(4316);
-  // This would use std::make_unique, but since the “new” would be in <memory>
-  // and not here, MSVC_PUSH_DISABLE_WARNING wouldn’t have the intended effect.
-  std::unique_ptr<MinidumpContextAMD64Writer> context_amd64_writer(
-      new MinidumpContextAMD64Writer());
-  MSVC_POP_WARNING();  // C4316.
+  auto context_amd64_writer = std::make_unique<MinidumpContextAMD64Writer>();
   InitializeMinidumpContextAMD64(context_amd64_writer->context(), kSeed);
   thread_writer->SetContext(std::move(context_amd64_writer));
 
diff --git a/third_party/crashpad/crashpad/minidump/test/minidump_byte_array_writer_test_util.cc b/third_party/crashpad/crashpad/minidump/test/minidump_byte_array_writer_test_util.cc
new file mode 100644
index 0000000..01e9d0a6
--- /dev/null
+++ b/third_party/crashpad/crashpad/minidump/test/minidump_byte_array_writer_test_util.cc
@@ -0,0 +1,36 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "minidump/test/minidump_byte_array_writer_test_util.h"
+
+#include "minidump/test/minidump_writable_test_util.h"
+
+namespace crashpad {
+namespace test {
+
+std::vector<uint8_t> MinidumpByteArrayAtRVA(const std::string& file_contents,
+                                            RVA rva) {
+  auto* minidump_byte_array =
+      MinidumpWritableAtRVA<MinidumpByteArray>(file_contents, rva);
+  if (!minidump_byte_array) {
+    return {};
+  }
+  auto* data = static_cast<const uint8_t*>(minidump_byte_array->data);
+  const uint8_t* data_end = data + minidump_byte_array->length;
+  return std::vector<uint8_t>(data, data_end);
+}
+
+
+}  // namespace test
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/minidump/test/minidump_byte_array_writer_test_util.h b/third_party/crashpad/crashpad/minidump/test/minidump_byte_array_writer_test_util.h
new file mode 100644
index 0000000..d2c926b
--- /dev/null
+++ b/third_party/crashpad/crashpad/minidump/test/minidump_byte_array_writer_test_util.h
@@ -0,0 +1,43 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef MINIDUMP_TEST_MINIDUMP_BYTE_ARRAY_WRITER_TEST_UTIL_H_
+#define MINIDUMP_TEST_MINIDUMP_BYTE_ARRAY_WRITER_TEST_UTIL_H_
+
+#include <windows.h>
+#include <dbghelp.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+namespace crashpad {
+namespace test {
+
+//! \brief Returns the bytes referenced by a MinidumpByteArray object located
+//!     in a minidump file at the specified RVA.
+//!
+//! \param[in] file_contents The contents of the minidump file.
+//! \param[in] rva The offset in the minidump file of the MinidumpByteArray.
+//!
+//! \return The MinidumpByteArray::data referenced by the \a rva. Note that
+//!       this function does not check that the data are within the bounds of
+//!       the \a file_contents.
+std::vector<uint8_t> MinidumpByteArrayAtRVA(const std::string& file_contents,
+                                            RVA rva);
+
+}  // namespace test
+}  // namespace crashpad
+
+#endif  // MINIDUMP_TEST_MINIDUMP_BYTE_ARRAY_WRITER_TEST_UTIL_H_
diff --git a/third_party/crashpad/crashpad/snapshot/annotation_snapshot.cc b/third_party/crashpad/crashpad/snapshot/annotation_snapshot.cc
new file mode 100644
index 0000000..c3350ec
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/annotation_snapshot.cc
@@ -0,0 +1,32 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "snapshot/annotation_snapshot.h"
+
+namespace crashpad {
+
+AnnotationSnapshot::AnnotationSnapshot() : name(), type(0), value() {}
+
+AnnotationSnapshot::AnnotationSnapshot(const std::string& name,
+                                       uint16_t type,
+                                       const std::vector<uint8_t>& value)
+    : name(name), type(type), value(value) {}
+
+AnnotationSnapshot::~AnnotationSnapshot() = default;
+
+bool AnnotationSnapshot::operator==(const AnnotationSnapshot& other) const {
+  return name == other.name && type == other.type && value == other.value;
+}
+
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/annotation_snapshot.h b/third_party/crashpad/crashpad/snapshot/annotation_snapshot.h
new file mode 100644
index 0000000..11de475
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/annotation_snapshot.h
@@ -0,0 +1,54 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_SNAPSHOT_ANNOTATION_SNAPSHOT_H_
+#define CRASHPAD_SNAPSHOT_ANNOTATION_SNAPSHOT_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+namespace crashpad {
+
+// \!brief The snapshot representation of a client's Annotation.
+struct AnnotationSnapshot {
+  AnnotationSnapshot();
+  AnnotationSnapshot(const std::string& name,
+                     uint16_t type,
+                     const std::vector<uint8_t>& value);
+  ~AnnotationSnapshot();
+
+  bool operator==(const AnnotationSnapshot& other) const;
+  bool operator!=(const AnnotationSnapshot& other) const {
+    return !(*this == other);
+  }
+
+  //! \brief A non-unique name by which this annotation can be identified.
+  std::string name;
+
+  //! \brief The Annotation::Type of data stored in the annotation. This value
+  //!     may be client-supplied and need not correspond to a Crashpad-defined
+  //!     type.
+  uint16_t type;
+
+  //! \brief The data for the annotation. Guranteed to be non-empty, since
+  //!     empty annotations are skipped. The representation of the data should
+  //!     be interpreted as \a #type.
+  std::vector<uint8_t> value;
+};
+
+}  // namespace crashpad
+
+#endif  // CRASHPAD_SNAPSHOT_ANNOTATION_SNAPSHOT_H_
diff --git a/third_party/crashpad/crashpad/snapshot/crashpad_info_client_options_test.cc b/third_party/crashpad/crashpad/snapshot/crashpad_info_client_options_test.cc
index 697c14e..45f3f17 100644
--- a/third_party/crashpad/crashpad/snapshot/crashpad_info_client_options_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/crashpad_info_client_options_test.cc
@@ -141,13 +141,10 @@
 
 TEST(CrashpadInfoClientOptions, TwoModules) {
   // Open the module, which has its own CrashpadInfo structure.
-#if defined(OS_MACOSX)
-  const base::FilePath::StringType kDlExtension = FILE_PATH_LITERAL(".so");
-#elif defined(OS_WIN)
-  const base::FilePath::StringType kDlExtension = FILE_PATH_LITERAL(".dll");
-#endif
-  base::FilePath module_path = TestPaths::Executable().DirName().Append(
-      FILE_PATH_LITERAL("crashpad_snapshot_test_module") + kDlExtension);
+  base::FilePath module_path =
+      TestPaths::BuildArtifact(FILE_PATH_LITERAL("snapshot"),
+                               FILE_PATH_LITERAL("module"),
+                               TestPaths::FileType::kLoadableModule);
 #if defined(OS_MACOSX)
   ScopedModuleHandle module(
       dlopen(module_path.value().c_str(), RTLD_LAZY | RTLD_LOCAL));
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader.cc
index df8bebad..1a74d812 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader.cc
@@ -25,6 +25,7 @@
 #include "client/simple_string_dictionary.h"
 #include "snapshot/mac/mach_o_image_reader.h"
 #include "snapshot/mac/process_reader.h"
+#include "snapshot/snapshot_constants.h"
 #include "util/mach/task_memory.h"
 #include "util/stdlib/strnlen.h"
 
@@ -57,6 +58,15 @@
   return simple_map_annotations;
 }
 
+std::vector<AnnotationSnapshot> MachOImageAnnotationsReader::AnnotationsList()
+    const {
+  std::vector<AnnotationSnapshot> annotations;
+
+  ReadCrashpadAnnotationsList(&annotations);
+
+  return annotations;
+}
+
 void MachOImageAnnotationsReader::ReadCrashReporterClientAnnotations(
     std::vector<std::string>* vector_annotations) const {
   mach_vm_address_t crash_info_address;
@@ -173,4 +183,64 @@
   }
 }
 
+// TODO(rsesek): When there is a platform-agnostic remote memory reader
+// interface available, use it so that the implementation is not duplicated
+// in the PEImageAnnotationsReader.
+void MachOImageAnnotationsReader::ReadCrashpadAnnotationsList(
+    std::vector<AnnotationSnapshot>* annotations) const {
+  process_types::CrashpadInfo crashpad_info;
+  if (!image_reader_->GetCrashpadInfo(&crashpad_info)) {
+    return;
+  }
+
+  if (!crashpad_info.annotations_list) {
+    return;
+  }
+
+  process_types::AnnotationList annotation_list_object;
+  if (!annotation_list_object.Read(process_reader_,
+                                   crashpad_info.annotations_list)) {
+    LOG(WARNING) << "could not read annotations list object in " << name_;
+    return;
+  }
+
+  process_types::Annotation current = annotation_list_object.head;
+  for (size_t index = 0;
+       current.link_node != annotation_list_object.tail_pointer &&
+       index < kMaxNumberOfAnnotations;
+       ++index) {
+    if (!current.Read(process_reader_, current.link_node)) {
+      LOG(WARNING) << "could not read annotation at index " << index << " in "
+                   << name_;
+      return;
+    }
+
+    if (current.size == 0) {
+      continue;
+    }
+
+    AnnotationSnapshot snapshot;
+    snapshot.type = current.type;
+    snapshot.value.resize(current.size);
+
+    if (!process_reader_->Memory()->ReadCStringSizeLimited(
+            current.name, Annotation::kNameMaxLength, &snapshot.name)) {
+      LOG(WARNING) << "could not read annotation name at index " << index
+                   << " in " << name_;
+      continue;
+    }
+
+    size_t size =
+        std::min(static_cast<size_t>(current.size), Annotation::kValueMaxSize);
+    if (!process_reader_->Memory()->Read(
+            current.value, size, snapshot.value.data())) {
+      LOG(WARNING) << "could not read annotation value at index " << index
+                   << " in " << name_;
+      continue;
+    }
+
+    annotations->push_back(std::move(snapshot));
+  }
+}
+
 }  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader.h b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader.h
index 2ff6e0e..06d2bea 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader.h
+++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader.h
@@ -20,6 +20,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "snapshot/annotation_snapshot.h"
 #include "snapshot/mac/process_types.h"
 
 namespace crashpad {
@@ -67,6 +68,10 @@
   //!     pairs, where all keys and values are strings.
   std::map<std::string, std::string> SimpleMap() const;
 
+  //! \brief Returns the module’s annotations that are organized as a list of
+  //      typed annotation objects.
+  std::vector<AnnotationSnapshot> AnnotationsList() const;
+
  private:
   // Reades crashreporter_annotations_t::message and
   // crashreporter_annotations_t::message2 on behalf of Vector().
@@ -81,6 +86,10 @@
   void ReadCrashpadSimpleAnnotations(
       std::map<std::string, std::string>* simple_map_annotations) const;
 
+  // Reads CrashpadInfo::annotations_list_ on behalf of AnnotationsList().
+  void ReadCrashpadAnnotationsList(
+      std::vector<AnnotationSnapshot>* vector_annotations) const;
+
   std::string name_;
   ProcessReader* process_reader_;  // weak
   const MachOImageReader* image_reader_;  // weak
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc
index 68d6c4e..3e7864b 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc
@@ -28,6 +28,8 @@
 
 #include "base/files/file_path.h"
 #include "base/macros.h"
+#include "client/annotation.h"
+#include "client/annotation_list.h"
 #include "client/crashpad_info.h"
 #include "client/simple_string_dictionary.h"
 #include "gtest/gtest.h"
@@ -49,13 +51,16 @@
 namespace {
 
 // \return The path to crashpad_snapshot_test_module_crashy_initializer.so
-std::string ModuleWithCrashyInitializer() {
-  return TestPaths::Executable().value() + "_module_crashy_initializer.so";
+base::FilePath ModuleWithCrashyInitializer() {
+  return TestPaths::BuildArtifact("snapshot",
+                                  "module_crashy_initializer",
+                                  TestPaths::FileType::kLoadableModule);
 }
 
 //! \return The path to the crashpad_snapshot_test_no_op executable.
 base::FilePath NoOpExecutable() {
-  return base::FilePath(TestPaths::Executable().value() + "_no_op");
+  return TestPaths::BuildArtifact(
+      "snapshot", "no_op", TestPaths::FileType::kExecutable);
 }
 
 class TestMachOImageAnnotationsReader final
@@ -181,7 +186,7 @@
           case kCrashModuleInitialization:
             // This message is set by dyld-353.2.1/src/ImageLoaderMachO.cpp
             // ImageLoaderMachO::doInitialization().
-            expected_annotation = ModuleWithCrashyInitializer();
+            expected_annotation = ModuleWithCrashyInitializer().value();
             break;
 
           case kCrashDyld:
@@ -248,10 +253,12 @@
     char c;
     CheckedReadFileExactly(ReadPipeHandle(), &c, sizeof(c));
 
-    // Verify the “simple map” annotations set via the CrashpadInfo interface.
+    // Verify the “simple map” and object-based annotations set via the
+    // CrashpadInfo interface.
     const std::vector<ProcessReader::Module>& modules =
         process_reader.Modules();
     std::map<std::string, std::string> all_annotations_simple_map;
+    std::vector<AnnotationSnapshot> all_annotations;
     for (const ProcessReader::Module& module : modules) {
       MachOImageAnnotationsReader module_annotations_reader(
           &process_reader, module.reader, module.name);
@@ -259,6 +266,11 @@
           module_annotations_reader.SimpleMap();
       all_annotations_simple_map.insert(module_annotations_simple_map.begin(),
                                         module_annotations_simple_map.end());
+
+      std::vector<AnnotationSnapshot> annotations =
+          module_annotations_reader.AnnotationsList();
+      all_annotations.insert(
+          all_annotations.end(), annotations.begin(), annotations.end());
     }
 
     EXPECT_GE(all_annotations_simple_map.size(), 5u);
@@ -268,6 +280,31 @@
     EXPECT_EQ(all_annotations_simple_map["#TEST# longer"], "shorter");
     EXPECT_EQ(all_annotations_simple_map["#TEST# empty_value"], "");
 
+    EXPECT_EQ(all_annotations.size(), 3u);
+    bool saw_same_name_3 = false, saw_same_name_4 = false;
+    for (const auto& annotation : all_annotations) {
+      EXPECT_EQ(annotation.type,
+                static_cast<uint16_t>(Annotation::Type::kString));
+      std::string value(reinterpret_cast<const char*>(annotation.value.data()),
+                        annotation.value.size());
+
+      if (annotation.name == "#TEST# one") {
+        EXPECT_EQ(value, "moocow");
+      } else if (annotation.name == "#TEST# same-name") {
+        if (value == "same-name 3") {
+          EXPECT_FALSE(saw_same_name_3);
+          saw_same_name_3 = true;
+        } else if (value == "same-name 4") {
+          EXPECT_FALSE(saw_same_name_4);
+          saw_same_name_4 = true;
+        } else {
+          ADD_FAILURE() << "unexpected annotation value " << value;
+        }
+      } else {
+        ADD_FAILURE() << "unexpected annotation " << annotation.name;
+      }
+    }
+
     // Tell the child process that it’s permitted to crash.
     CheckedWriteFile(WritePipeHandle(), &c, sizeof(c));
 
@@ -329,6 +366,19 @@
 
     crashpad_info->set_simple_annotations(simple_annotations);
 
+    AnnotationList::Register();  // This is “leaked” to crashpad_info.
+
+    static StringAnnotation<32> test_annotation_one{"#TEST# one"};
+    static StringAnnotation<32> test_annotation_two{"#TEST# two"};
+    static StringAnnotation<32> test_annotation_three{"#TEST# same-name"};
+    static StringAnnotation<32> test_annotation_four{"#TEST# same-name"};
+
+    test_annotation_one.Set("moocow");
+    test_annotation_two.Set("this will be cleared");
+    test_annotation_three.Set("same-name 3");
+    test_annotation_four.Set("same-name 4");
+    test_annotation_two.Clear();
+
     // Tell the parent that the environment has been set up.
     char c = '\0';
     CheckedWriteFile(WritePipeHandle(), &c, sizeof(c));
@@ -355,7 +405,7 @@
 
       case kCrashModuleInitialization: {
         // Load a module that crashes while executing a module initializer.
-        void* dl_handle = dlopen(ModuleWithCrashyInitializer().c_str(),
+        void* dl_handle = dlopen(ModuleWithCrashyInitializer().value().c_str(),
                                  RTLD_LAZY | RTLD_LOCAL);
 
         // This should have crashed in the dlopen(). If dlopen() failed, the
diff --git a/third_party/crashpad/crashpad/snapshot/mac/module_snapshot_mac.cc b/third_party/crashpad/crashpad/snapshot/mac/module_snapshot_mac.cc
index 272c8c1..2d75037 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/module_snapshot_mac.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/module_snapshot_mac.cc
@@ -185,6 +185,12 @@
   return annotations_reader.SimpleMap();
 }
 
+std::vector<AnnotationSnapshot> ModuleSnapshotMac::AnnotationObjects() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+  NOTREACHED();
+  return {};
+}
+
 std::set<CheckedRange<uint64_t>> ModuleSnapshotMac::ExtraMemoryRanges() const {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
   return std::set<CheckedRange<uint64_t>>();
diff --git a/third_party/crashpad/crashpad/snapshot/mac/module_snapshot_mac.h b/third_party/crashpad/crashpad/snapshot/mac/module_snapshot_mac.h
index 16ad7e1..44c07910 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/module_snapshot_mac.h
+++ b/third_party/crashpad/crashpad/snapshot/mac/module_snapshot_mac.h
@@ -79,6 +79,7 @@
   std::string DebugFileName() const override;
   std::vector<std::string> AnnotationsVector() const override;
   std::map<std::string, std::string> AnnotationsSimpleMap() const override;
+  std::vector<AnnotationSnapshot> AnnotationObjects() const override;
   std::set<CheckedRange<uint64_t>> ExtraMemoryRanges() const override;
   std::vector<const UserMinidumpStream*> CustomMinidumpStreams() const override;
 
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_reader_test.cc b/third_party/crashpad/crashpad/snapshot/mac/process_reader_test.cc
index 36b372fb..c9f39e715 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/process_reader_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/process_reader_test.cc
@@ -42,16 +42,6 @@
 #include "util/misc/from_pointer_cast.h"
 #include "util/synchronization/semaphore.h"
 
-#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
-extern "C" {
-
-// Redeclare a typedef whose availability (OS X 10.10) is newer than the
-// deployment target.
-typedef struct _cl_device_id* cl_device_id;
-
-}  // extern "C"
-#endif
-
 namespace crashpad {
 namespace test {
 namespace {
@@ -574,10 +564,24 @@
     cl_int rv = clGetPlatformIDs(1, &platform_id, nullptr);
     ASSERT_EQ(rv, CL_SUCCESS) << "clGetPlatformIDs";
 
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10 && \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
+    // cl_device_id is really available in OpenCL.framework back to 10.5, but in
+    // the 10.10 SDK and later, OpenCL.framework includes <OpenGL/CGLDevice.h>,
+    // which has its own cl_device_id that was introduced in 10.10. That
+    // triggers erroneous availability warnings.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
+#define DISABLED_WUNGUARDED_AVAILABILITY
+#endif  // SDK >= 10.10 && DT < 10.10
     // Use CL_DEVICE_TYPE_CPU to ensure that the kernel would execute on the
     // CPU. This is the only device type that a cl_kernels image will be created
     // for.
     cl_device_id device_id;
+#if defined(DISABLED_WUNGUARDED_AVAILABILITY)
+#pragma clang diagnostic pop
+#undef DISABLED_WUNGUARDED_AVAILABILITY
+#endif  // DISABLED_WUNGUARDED_AVAILABILITY
     rv =
         clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_CPU, 1, &device_id, nullptr);
     ASSERT_EQ(rv, CL_SUCCESS) << "clGetDeviceIDs";
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_types/all.proctype b/third_party/crashpad/crashpad/snapshot/mac/process_types/all.proctype
index 7ef54d5..d84b41d1 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/process_types/all.proctype
+++ b/third_party/crashpad/crashpad/snapshot/mac/process_types/all.proctype
@@ -19,6 +19,7 @@
 // snapshot/mac/process_types.cc to produce process type struct definitions and
 // accessors.
 
+#include "snapshot/mac/process_types/annotation.proctype"
 #include "snapshot/mac/process_types/crashpad_info.proctype"
 #include "snapshot/mac/process_types/crashreporterclient.proctype"
 #include "snapshot/mac/process_types/dyld_images.proctype"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_types/annotation.proctype b/third_party/crashpad/crashpad/snapshot/mac/process_types/annotation.proctype
new file mode 100644
index 0000000..5d34fda
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/mac/process_types/annotation.proctype
@@ -0,0 +1,31 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+PROCESS_TYPE_STRUCT_BEGIN(Annotation)
+  PROCESS_TYPE_STRUCT_MEMBER(Pointer, link_node)
+  PROCESS_TYPE_STRUCT_MEMBER(Pointer, name)
+  PROCESS_TYPE_STRUCT_MEMBER(Pointer, value)
+  PROCESS_TYPE_STRUCT_MEMBER(uint32_t, size)
+  PROCESS_TYPE_STRUCT_MEMBER(uint16_t, type)
+PROCESS_TYPE_STRUCT_END(Annotation)
+
+#if !defined(PROCESS_TYPE_STRUCT_IMPLEMENT_ARRAY)
+
+PROCESS_TYPE_STRUCT_BEGIN(AnnotationList)
+  PROCESS_TYPE_STRUCT_MEMBER(Pointer, tail_pointer)
+  PROCESS_TYPE_STRUCT_MEMBER(crashpad::process_types::Annotation, head)
+  PROCESS_TYPE_STRUCT_MEMBER(crashpad::process_types::Annotation, tail)
+PROCESS_TYPE_STRUCT_END(AnnotationList)
+
+#endif  // !defined(PROCESS_TYPE_STRUCT_IMPLEMENT_ARRAY)
diff --git a/third_party/crashpad/crashpad/snapshot/minidump/module_snapshot_minidump.cc b/third_party/crashpad/crashpad/snapshot/minidump/module_snapshot_minidump.cc
index f5132270..195fc89 100644
--- a/third_party/crashpad/crashpad/snapshot/minidump/module_snapshot_minidump.cc
+++ b/third_party/crashpad/crashpad/snapshot/minidump/module_snapshot_minidump.cc
@@ -135,6 +135,13 @@
   return annotations_simple_map_;
 }
 
+std::vector<AnnotationSnapshot> ModuleSnapshotMinidump::AnnotationObjects()
+    const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+  NOTREACHED();
+  return {};
+}
+
 std::set<CheckedRange<uint64_t>> ModuleSnapshotMinidump::ExtraMemoryRanges()
     const {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
diff --git a/third_party/crashpad/crashpad/snapshot/minidump/module_snapshot_minidump.h b/third_party/crashpad/crashpad/snapshot/minidump/module_snapshot_minidump.h
index 3d63f2a..ad65dbc9 100644
--- a/third_party/crashpad/crashpad/snapshot/minidump/module_snapshot_minidump.h
+++ b/third_party/crashpad/crashpad/snapshot/minidump/module_snapshot_minidump.h
@@ -76,6 +76,7 @@
   std::string DebugFileName() const override;
   std::vector<std::string> AnnotationsVector() const override;
   std::map<std::string, std::string> AnnotationsSimpleMap() const override;
+  std::vector<AnnotationSnapshot> AnnotationObjects() const override;
   std::set<CheckedRange<uint64_t>> ExtraMemoryRanges() const override;
   std::vector<const UserMinidumpStream*> CustomMinidumpStreams() const override;
 
diff --git a/third_party/crashpad/crashpad/snapshot/module_snapshot.h b/third_party/crashpad/crashpad/snapshot/module_snapshot.h
index cd3dbd3..eea7466 100644
--- a/third_party/crashpad/crashpad/snapshot/module_snapshot.h
+++ b/third_party/crashpad/crashpad/snapshot/module_snapshot.h
@@ -24,6 +24,7 @@
 #include <string>
 #include <vector>
 
+#include "snapshot/annotation_snapshot.h"
 #include "snapshot/memory_snapshot.h"
 #include "util/misc/uuid.h"
 #include "util/numeric/checked_range.h"
@@ -172,7 +173,7 @@
   //! (`dyld`) can provide an annotation at its `_error_string` symbol.
   //!
   //! The annotations returned by this method do not duplicate those returned by
-  //! AnnotationsSimpleMap().
+  //! AnnotationsSimpleMap() or AnnotationObjects().
   virtual std::vector<std::string> AnnotationsVector() const = 0;
 
   //! \brief Returns key-value string annotations recorded in the module.
@@ -190,11 +191,27 @@
   //! method. For clients such as Chrome, this includes the process type.
   //!
   //! The annotations returned by this method do not duplicate those returned by
-  //! AnnotationsVector(). Additional annotations related to the process,
-  //! system, or snapshot producer may be obtained by calling
+  //! AnnotationsVector() or AnnotationObjects(). Additional annotations related
+  //! to the process, system, or snapshot producer may be obtained by calling
   //! ProcessSnapshot::AnnotationsSimpleMap().
   virtual std::map<std::string, std::string> AnnotationsSimpleMap() const = 0;
 
+  //! \brief Returns the typed annotation objects recorded in the module.
+  //!
+  //! This method retrieves annotations recorded in a module. These annotations
+  //! are intended for diagnostic use, including crash analysis. Annotation
+  //! objects are strongly-typed name-value pairs. The names are not unique.
+  //!
+  //! For macOS snapshots, these annotations are found by interpreting the
+  //! `__DATA,crashpad_info` section as `CrashpadInfo`. Clients can use the
+  //! Crashpad client interface to store annotations in this structure. Most
+  //! annotations under the client’s direct control will be retrievable by this
+  //! method. For clients such as Chrome, this includes the process type.
+  //!
+  //! The annotations returned by this method do not duplicate those returned by
+  //! AnnotationsVector() or AnnotationsSimpleMap().
+  virtual std::vector<AnnotationSnapshot> AnnotationObjects() const = 0;
+
   //! \brief Returns a set of extra memory ranges specified in the module as
   //!     being desirable to include in the crash dump.
   virtual std::set<CheckedRange<uint64_t>> ExtraMemoryRanges() const = 0;
diff --git a/third_party/crashpad/crashpad/snapshot/snapshot.gyp b/third_party/crashpad/crashpad/snapshot/snapshot.gyp
index 4b5e8c94..73a5da0 100644
--- a/third_party/crashpad/crashpad/snapshot/snapshot.gyp
+++ b/third_party/crashpad/crashpad/snapshot/snapshot.gyp
@@ -30,6 +30,8 @@
         '..',
       ],
       'sources': [
+        'annotation_snapshot.cc',
+        'annotation_snapshot.h',
         'capture_memory.cc',
         'capture_memory.h',
         'cpu_architecture.h',
@@ -84,6 +86,7 @@
         'mac/process_types.cc',
         'mac/process_types.h',
         'mac/process_types/all.proctype',
+        'mac/process_types/annotation.proctype',
         'mac/process_types/crashpad_info.proctype',
         'mac/process_types/crashreporterclient.proctype',
         'mac/process_types/custom.cc',
@@ -112,6 +115,7 @@
         'posix/timezone.cc',
         'posix/timezone.h',
         'process_snapshot.h',
+        'snapshot_constants.h',
         'system_snapshot.h',
         'thread_snapshot.h',
         'unloaded_module_snapshot.cc',
diff --git a/third_party/crashpad/crashpad/snapshot/snapshot_constants.h b/third_party/crashpad/crashpad/snapshot/snapshot_constants.h
new file mode 100644
index 0000000..2bbddda
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/snapshot_constants.h
@@ -0,0 +1,28 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SNAPSHOT_SNAPSHOT_CONSTANTS_H_
+#define SNAPSHOT_SNAPSHOT_CONSTANTS_H_
+
+namespace crashpad {
+
+//! \brief The maximum number of crashpad::Annotations that will be read from
+//!     a client process.
+//!
+//! \note This maximum was chosen arbitrarily and may change in the future.
+constexpr size_t kMaxNumberOfAnnotations = 200;
+
+}  // namespace crashpad
+
+#endif  // SNAPSHOT_SNAPSHOT_CONSTANTS_H_
diff --git a/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp b/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp
index 4b6db39..d720a10e 100644
--- a/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp
+++ b/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp
@@ -67,9 +67,9 @@
         '..',
       ],
       'sources': [
+        'api/module_annotations_win_test.cc',
         'cpu_context_test.cc',
         'crashpad_info_client_options_test.cc',
-        'api/module_annotations_win_test.cc',
         'elf/elf_image_reader_test.cc',
         'linux/debug_rendezvous_test.cc',
         'linux/exception_snapshot_linux_test.cc',
@@ -107,8 +107,10 @@
         }],
         ['OS=="win"', {
           'dependencies': [
+            'crashpad_snapshot_test_annotations',
             'crashpad_snapshot_test_crashing_child',
             'crashpad_snapshot_test_dump_without_crashing',
+            'crashpad_snapshot_test_extra_memory_ranges',
             'crashpad_snapshot_test_image_reader',
             'crashpad_snapshot_test_image_reader_module',
           ],
@@ -247,7 +249,7 @@
           },
         },
         {
-          'target_name': 'crashpad_snapshot_test_simple_annotations',
+          'target_name': 'crashpad_snapshot_test_annotations',
           'type': 'executable',
           'dependencies': [
             '../client/client.gyp:crashpad_client',
@@ -255,7 +257,7 @@
             '../third_party/mini_chromium/mini_chromium.gyp:base',
           ],
           'sources': [
-            'win/crashpad_snapshot_test_simple_annotations.cc',
+            'win/crashpad_snapshot_test_annotations.cc',
           ],
         },
       ],
diff --git a/third_party/crashpad/crashpad/snapshot/test/test_module_snapshot.cc b/third_party/crashpad/crashpad/snapshot/test/test_module_snapshot.cc
index 47962ce..9141edad 100644
--- a/third_party/crashpad/crashpad/snapshot/test/test_module_snapshot.cc
+++ b/third_party/crashpad/crashpad/snapshot/test/test_module_snapshot.cc
@@ -94,6 +94,10 @@
   return annotations_simple_map_;
 }
 
+std::vector<AnnotationSnapshot> TestModuleSnapshot::AnnotationObjects() const {
+  return annotation_objects_;
+}
+
 std::set<CheckedRange<uint64_t>> TestModuleSnapshot::ExtraMemoryRanges() const {
   return extra_memory_ranges_;
 }
diff --git a/third_party/crashpad/crashpad/snapshot/test/test_module_snapshot.h b/third_party/crashpad/crashpad/snapshot/test/test_module_snapshot.h
index 92b3f094..d1262fa6 100644
--- a/third_party/crashpad/crashpad/snapshot/test/test_module_snapshot.h
+++ b/third_party/crashpad/crashpad/snapshot/test/test_module_snapshot.h
@@ -75,6 +75,10 @@
       const std::map<std::string, std::string>& annotations_simple_map) {
     annotations_simple_map_ = annotations_simple_map;
   }
+  void SetAnnotationObjects(
+      const std::vector<AnnotationSnapshot>& annotations) {
+    annotation_objects_ = annotations;
+  }
   void SetExtraMemoryRanges(
       const std::set<CheckedRange<uint64_t>>& extra_memory_ranges) {
     extra_memory_ranges_ = extra_memory_ranges;
@@ -99,6 +103,7 @@
   std::string DebugFileName() const override;
   std::vector<std::string> AnnotationsVector() const override;
   std::map<std::string, std::string> AnnotationsSimpleMap() const override;
+  std::vector<AnnotationSnapshot> AnnotationObjects() const override;
   std::set<CheckedRange<uint64_t>> ExtraMemoryRanges() const override;
   std::vector<const UserMinidumpStream*> CustomMinidumpStreams() const override;
 
@@ -115,6 +120,7 @@
   std::string debug_file_name_;
   std::vector<std::string> annotations_vector_;
   std::map<std::string, std::string> annotations_simple_map_;
+  std::vector<AnnotationSnapshot> annotation_objects_;
   std::set<CheckedRange<uint64_t>> extra_memory_ranges_;
 
   DISALLOW_COPY_AND_ASSIGN(TestModuleSnapshot);
diff --git a/third_party/crashpad/crashpad/snapshot/win/cpu_context_win_test.cc b/third_party/crashpad/crashpad/snapshot/win/cpu_context_win_test.cc
index 41adde3..aa2afe9 100644
--- a/third_party/crashpad/crashpad/snapshot/win/cpu_context_win_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/cpu_context_win_test.cc
@@ -80,9 +80,9 @@
     EXPECT_EQ(cpu_context_x86.fxsave.fsw, 0x0004);
     EXPECT_EQ(cpu_context_x86.fxsave.ftw, 0x00f0);
     EXPECT_EQ(cpu_context_x86.fxsave.fop, 0x0bad);
-    EXPECT_EQ(cpu_context_x86.fxsave.fpu_ip, 0x01234567);
+    EXPECT_EQ(cpu_context_x86.fxsave.fpu_ip, 0x01234567u);
     EXPECT_EQ(cpu_context_x86.fxsave.fpu_cs, 0x0003);
-    EXPECT_EQ(cpu_context_x86.fxsave.fpu_dp, 0x89abcdef);
+    EXPECT_EQ(cpu_context_x86.fxsave.fpu_dp, 0x89abcdefu);
     EXPECT_EQ(cpu_context_x86.fxsave.fpu_ds, 0x0007);
     for (size_t st_mm = 0; st_mm < 7; ++st_mm) {
       EXPECT_EQ(
diff --git a/third_party/crashpad/crashpad/snapshot/win/crashpad_snapshot_test_simple_annotations.cc b/third_party/crashpad/crashpad/snapshot/win/crashpad_snapshot_test_annotations.cc
similarity index 75%
rename from third_party/crashpad/crashpad/snapshot/win/crashpad_snapshot_test_simple_annotations.cc
rename to third_party/crashpad/crashpad/snapshot/win/crashpad_snapshot_test_annotations.cc
index 11e7b4e..6005f4d 100644
--- a/third_party/crashpad/crashpad/snapshot/win/crashpad_snapshot_test_simple_annotations.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/crashpad_snapshot_test_annotations.cc
@@ -15,6 +15,8 @@
 #include <windows.h>
 
 #include "base/logging.h"
+#include "client/annotation.h"
+#include "client/annotation_list.h"
 #include "client/crashpad_info.h"
 #include "util/file/file_io.h"
 
@@ -34,6 +36,20 @@
 
   crashpad_info->set_simple_annotations(simple_annotations);
 
+  // Set the annotation objects.
+  crashpad::AnnotationList::Register();
+
+  static crashpad::StringAnnotation<32> annotation_one("#TEST# one");
+  static crashpad::StringAnnotation<32> annotation_two("#TEST# two");
+  static crashpad::StringAnnotation<32> annotation_three("#TEST# same-name");
+  static crashpad::StringAnnotation<32> annotation_four("#TEST# same-name");
+
+  annotation_one.Set("moocow");
+  annotation_two.Set("this will be cleared");
+  annotation_three.Set("same-name 3");
+  annotation_four.Set("same-name 4");
+  annotation_two.Clear();
+
   // Tell the parent that the environment has been set up.
   HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
   PCHECK(out != INVALID_HANDLE_VALUE) << "GetStdHandle";
diff --git a/third_party/crashpad/crashpad/snapshot/win/crashpad_snapshot_test_image_reader.cc b/third_party/crashpad/crashpad/snapshot/win/crashpad_snapshot_test_image_reader.cc
index 6f4203d..4ebd98e9 100644
--- a/third_party/crashpad/crashpad/snapshot/win/crashpad_snapshot_test_image_reader.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/crashpad_snapshot_test_image_reader.cc
@@ -28,7 +28,7 @@
 
   // Allocate a bunch of pointers to things on the stack.
   int* pointers[1000];
-  for (int i = 0; i < arraysize(pointers); ++i) {
+  for (size_t i = 0; i < arraysize(pointers); ++i) {
     pointers[i] = new int[2048];
   }
 
@@ -52,7 +52,7 @@
   // verify the cap on pointed-to memory.
   crashpad::Semaphore semaphore(0);
   crashpad::ScopedKernelHANDLE threads[100];
-  for (int i = 0; i < arraysize(threads); ++i) {
+  for (size_t i = 0; i < arraysize(threads); ++i) {
     threads[i].reset(CreateThread(nullptr,
                                   0,
                                   &LotsOfReferencesThreadProc,
@@ -65,7 +65,7 @@
     }
   }
 
-  for (int i = 0; i < arraysize(threads); ++i) {
+  for (size_t i = 0; i < arraysize(threads); ++i) {
     semaphore.Wait();
   }
 
diff --git a/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc b/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc
index a782ae6..843ad263 100644
--- a/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc
@@ -121,7 +121,7 @@
   DISALLOW_COPY_AND_ASSIGN(CrashingDelegate);
 };
 
-void TestCrashingChild(const base::FilePath& directory) {
+void TestCrashingChild(TestPaths::Architecture architecture) {
   // Set up the registration server on a background thread.
   ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr));
   ASSERT_TRUE(server_ready.is_valid()) << ErrorMessage("CreateEvent");
@@ -141,13 +141,11 @@
       << ErrorMessage("WaitForSingleObject");
 
   // Spawn a child process, passing it the pipe name to connect to.
-  std::wstring child_test_executable = directory
-                                           .Append(TestPaths::Executable()
-                                                       .BaseName()
-                                                       .RemoveFinalExtension()
-                                                       .value() +
-                                                   L"_crashing_child.exe")
-                                           .value();
+  base::FilePath child_test_executable =
+      TestPaths::BuildArtifact(L"snapshot",
+                               L"crashing_child",
+                               TestPaths::FileType::kExecutable,
+                               architecture);
   ChildLauncher child(child_test_executable, pipe_name);
   ASSERT_NO_FATAL_FAILURE(child.Start());
 
@@ -166,17 +164,16 @@
 }
 
 TEST(ExceptionSnapshotWinTest, ChildCrash) {
-  TestCrashingChild(TestPaths::Executable().DirName());
+  TestCrashingChild(TestPaths::Architecture::kDefault);
 }
 
 #if defined(ARCH_CPU_64_BITS)
 TEST(ExceptionSnapshotWinTest, ChildCrashWOW64) {
-  base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
-  if (output_32_bit_directory.empty()) {
+  if (!TestPaths::Has32BitBuildArtifacts()) {
     DISABLED_TEST();
   }
 
-  TestCrashingChild(output_32_bit_directory);
+  TestCrashingChild(TestPaths::Architecture::k32Bit);
 }
 #endif  // ARCH_CPU_64_BITS
 
@@ -203,7 +200,7 @@
                         exception_information_address,
                         debug_critical_section_address);
     EXPECT_TRUE(snapshot.Exception());
-    EXPECT_EQ(snapshot.Exception()->Exception(), 0x517a7ed);
+    EXPECT_EQ(snapshot.Exception()->Exception(), 0x517a7edu);
 
     // Verify the dump was captured at the expected location with some slop
     // space.
@@ -229,7 +226,7 @@
   DISALLOW_COPY_AND_ASSIGN(SimulateDelegate);
 };
 
-void TestDumpWithoutCrashingChild(const base::FilePath& directory) {
+void TestDumpWithoutCrashingChild(TestPaths::Architecture architecture) {
   // Set up the registration server on a background thread.
   ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr));
   ASSERT_TRUE(server_ready.is_valid()) << ErrorMessage("CreateEvent");
@@ -249,14 +246,11 @@
       << ErrorMessage("WaitForSingleObject");
 
   // Spawn a child process, passing it the pipe name to connect to.
-  std::wstring child_test_executable =
-      directory
-          .Append(TestPaths::Executable()
-                      .BaseName()
-                      .RemoveFinalExtension()
-                      .value() +
-                  L"_dump_without_crashing.exe")
-          .value();
+  base::FilePath child_test_executable =
+      TestPaths::BuildArtifact(L"snapshot",
+                               L"dump_without_crashing",
+                               TestPaths::FileType::kExecutable,
+                               architecture);
   ChildLauncher child(child_test_executable, pipe_name);
   ASSERT_NO_FATAL_FAILURE(child.Start());
 
@@ -271,21 +265,20 @@
   EXPECT_EQ(WaitForSingleObject(completed.get(), INFINITE), WAIT_OBJECT_0)
       << ErrorMessage("WaitForSingleObject");
 
-  EXPECT_EQ(child.WaitForExit(), 0);
+  EXPECT_EQ(child.WaitForExit(), 0u);
 }
 
 TEST(SimulateCrash, ChildDumpWithoutCrashing) {
-  TestDumpWithoutCrashingChild(TestPaths::Executable().DirName());
+  TestDumpWithoutCrashingChild(TestPaths::Architecture::kDefault);
 }
 
 #if defined(ARCH_CPU_64_BITS)
 TEST(SimulateCrash, ChildDumpWithoutCrashingWOW64) {
-  base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
-  if (output_32_bit_directory.empty()) {
+  if (!TestPaths::Has32BitBuildArtifacts()) {
     DISABLED_TEST();
   }
 
-  TestDumpWithoutCrashingChild(output_32_bit_directory);
+  TestDumpWithoutCrashingChild(TestPaths::Architecture::k32Bit);
 }
 #endif  // ARCH_CPU_64_BITS
 
diff --git a/third_party/crashpad/crashpad/snapshot/win/extra_memory_ranges_test.cc b/third_party/crashpad/crashpad/snapshot/win/extra_memory_ranges_test.cc
index d0820a0..dcef805 100644
--- a/third_party/crashpad/crashpad/snapshot/win/extra_memory_ranges_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/extra_memory_ranges_test.cc
@@ -43,15 +43,14 @@
   kCrashDebugBreak,
 };
 
-void TestExtraMemoryRanges(TestType type, const base::FilePath& directory) {
+void TestExtraMemoryRanges(TestType type,
+                           TestPaths::Architecture architecture) {
   // Spawn a child process, passing it the pipe name to connect to.
-  std::wstring child_test_executable = directory
-                                           .Append(TestPaths::Executable()
-                                                       .BaseName()
-                                                       .RemoveFinalExtension()
-                                                       .value() +
-                                                   L"_extra_memory_ranges.exe")
-                                           .value();
+  base::FilePath child_test_executable =
+      TestPaths::BuildArtifact(L"snapshot",
+                               L"extra_memory_ranges",
+                               TestPaths::FileType::kExecutable,
+                               architecture);
   ChildLauncher child(child_test_executable, L"");
   ASSERT_NO_FATAL_FAILURE(child.Start());
 
@@ -101,30 +100,28 @@
 }
 
 TEST(ExtraMemoryRanges, DontCrash) {
-  TestExtraMemoryRanges(kDontCrash, TestPaths::Executable().DirName());
+  TestExtraMemoryRanges(kDontCrash, TestPaths::Architecture::kDefault);
 }
 
 TEST(ExtraMemoryRanges, CrashDebugBreak) {
-  TestExtraMemoryRanges(kCrashDebugBreak, TestPaths::Executable().DirName());
+  TestExtraMemoryRanges(kCrashDebugBreak, TestPaths::Architecture::kDefault);
 }
 
 #if defined(ARCH_CPU_64_BITS)
 TEST(ExtraMemoryRanges, DontCrashWOW64) {
-  base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
-  if (output_32_bit_directory.empty()) {
+  if (!TestPaths::Has32BitBuildArtifacts()) {
     DISABLED_TEST();
   }
 
-  TestExtraMemoryRanges(kDontCrash, output_32_bit_directory);
+  TestExtraMemoryRanges(kDontCrash, TestPaths::Architecture::k32Bit);
 }
 
 TEST(ExtraMemoryRanges, CrashDebugBreakWOW64) {
-  base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
-  if (output_32_bit_directory.empty()) {
+  if (!TestPaths::Has32BitBuildArtifacts()) {
     DISABLED_TEST();
   }
 
-  TestExtraMemoryRanges(kCrashDebugBreak, output_32_bit_directory);
+  TestExtraMemoryRanges(kCrashDebugBreak, TestPaths::Architecture::k32Bit);
 }
 #endif  // ARCH_CPU_64_BITS
 
diff --git a/third_party/crashpad/crashpad/snapshot/win/module_snapshot_win.cc b/third_party/crashpad/crashpad/snapshot/win/module_snapshot_win.cc
index ec0bab5..b130eccb 100644
--- a/third_party/crashpad/crashpad/snapshot/win/module_snapshot_win.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/module_snapshot_win.cc
@@ -190,6 +190,12 @@
   return annotations_reader.SimpleMap();
 }
 
+std::vector<AnnotationSnapshot> ModuleSnapshotWin::AnnotationObjects() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+  NOTREACHED();
+  return {};
+}
+
 std::set<CheckedRange<uint64_t>> ModuleSnapshotWin::ExtraMemoryRanges() const {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
   std::set<CheckedRange<uint64_t>> ranges;
diff --git a/third_party/crashpad/crashpad/snapshot/win/module_snapshot_win.h b/third_party/crashpad/crashpad/snapshot/win/module_snapshot_win.h
index 4cc7b84..2a7083d 100644
--- a/third_party/crashpad/crashpad/snapshot/win/module_snapshot_win.h
+++ b/third_party/crashpad/crashpad/snapshot/win/module_snapshot_win.h
@@ -85,6 +85,7 @@
   std::string DebugFileName() const override;
   std::vector<std::string> AnnotationsVector() const override;
   std::map<std::string, std::string> AnnotationsSimpleMap() const override;
+  std::vector<AnnotationSnapshot> AnnotationObjects() const override;
   std::set<CheckedRange<uint64_t>> ExtraMemoryRanges() const override;
   std::vector<const UserMinidumpStream*> CustomMinidumpStreams() const override;
 
diff --git a/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader.cc b/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader.cc
index 87de1e3..4ef8a1eae 100644
--- a/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader.cc
@@ -18,13 +18,35 @@
 #include <sys/types.h>
 
 #include "base/strings/utf_string_conversions.h"
+#include "client/annotation.h"
 #include "client/simple_string_dictionary.h"
+#include "snapshot/snapshot_constants.h"
 #include "snapshot/win/pe_image_reader.h"
 #include "snapshot/win/process_reader_win.h"
 #include "util/win/process_structs.h"
 
 namespace crashpad {
 
+namespace process_types {
+
+template <class Traits>
+struct Annotation {
+  typename Traits::Pointer link_node;
+  typename Traits::Pointer name;
+  typename Traits::Pointer value;
+  uint32_t size;
+  uint16_t type;
+};
+
+template <class Traits>
+struct AnnotationList {
+  typename Traits::Pointer tail_pointer;
+  Annotation<Traits> head;
+  Annotation<Traits> tail;
+};
+
+}  // namespace process_types
+
 PEImageAnnotationsReader::PEImageAnnotationsReader(
     ProcessReaderWin* process_reader,
     const PEImageReader* pe_image_reader,
@@ -46,6 +68,19 @@
   return simple_map_annotations;
 }
 
+std::vector<AnnotationSnapshot> PEImageAnnotationsReader::AnnotationsList()
+    const {
+  std::vector<AnnotationSnapshot> annotations;
+  if (process_reader_->Is64Bit()) {
+    ReadCrashpadAnnotationsList<process_types::internal::Traits64>(
+        &annotations);
+  } else {
+    ReadCrashpadAnnotationsList<process_types::internal::Traits32>(
+        &annotations);
+  }
+  return annotations;
+}
+
 template <class Traits>
 void PEImageAnnotationsReader::ReadCrashpadSimpleAnnotations(
     std::map<std::string, std::string>* simple_map_annotations) const {
@@ -80,4 +115,71 @@
   }
 }
 
+// TODO(rsesek): When there is a platform-agnostic remote memory reader
+// interface available, use it so that the implementation is not duplicated
+// in the MachOImageAnnotationsReader.
+template <class Traits>
+void PEImageAnnotationsReader::ReadCrashpadAnnotationsList(
+    std::vector<AnnotationSnapshot>* vector_annotations) const {
+  process_types::CrashpadInfo<Traits> crashpad_info;
+  if (!pe_image_reader_->GetCrashpadInfo(&crashpad_info)) {
+    return;
+  }
+
+  if (!crashpad_info.annotations_list) {
+    return;
+  }
+
+  process_types::AnnotationList<Traits> annotation_list_object;
+  if (!process_reader_->ReadMemory(crashpad_info.annotations_list,
+                                   sizeof(annotation_list_object),
+                                   &annotation_list_object)) {
+    LOG(WARNING) << "could not read annotations list object in "
+                 << base::UTF16ToUTF8(name_);
+    return;
+  }
+
+  process_types::Annotation<Traits> current = annotation_list_object.head;
+  for (size_t index = 0;
+       current.link_node != annotation_list_object.tail_pointer &&
+       index < kMaxNumberOfAnnotations;
+       ++index) {
+    if (!process_reader_->ReadMemory(
+            current.link_node, sizeof(current), &current)) {
+      LOG(WARNING) << "could not read annotation at index " << index << " in "
+                   << base::UTF16ToUTF8(name_);
+      return;
+    }
+
+    if (current.size == 0) {
+      continue;
+    }
+
+    AnnotationSnapshot snapshot;
+    snapshot.type = current.type;
+
+    char name[Annotation::kNameMaxLength];
+    if (!process_reader_->ReadMemory(current.name, arraysize(name), name)) {
+      LOG(WARNING) << "could not read annotation name at index " << index
+                   << " in " << base::UTF16ToUTF8(name_);
+      continue;
+    }
+
+    size_t name_length = strnlen(name, Annotation::kNameMaxLength);
+    snapshot.name = std::string(name, name_length);
+
+    size_t value_length =
+        std::min(static_cast<size_t>(current.size), Annotation::kValueMaxSize);
+    snapshot.value.resize(value_length);
+    if (!process_reader_->ReadMemory(
+            current.value, value_length, snapshot.value.data())) {
+      LOG(WARNING) << "could not read annotation value at index " << index
+                   << " in " << base::UTF16ToUTF8(name_);
+      continue;
+    }
+
+    vector_annotations->push_back(std::move(snapshot));
+  }
+}
+
 }  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader.h b/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader.h
index 85f3bed..6379b27 100644
--- a/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader.h
+++ b/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader.h
@@ -20,6 +20,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "snapshot/annotation_snapshot.h"
 
 namespace crashpad {
 
@@ -54,12 +55,21 @@
   //!     pairs, where all keys and values are strings.
   std::map<std::string, std::string> SimpleMap() const;
 
+  //! \brief Returns the module's annotations that are organized as a list of
+  //!     typed annotation objects.
+  std::vector<AnnotationSnapshot> AnnotationsList() const;
+
  private:
   // Reads CrashpadInfo::simple_annotations_ on behalf of SimpleMap().
   template <class Traits>
   void ReadCrashpadSimpleAnnotations(
       std::map<std::string, std::string>* simple_map_annotations) const;
 
+  // Reads CrashpadInfo::annotations_list_ on behalf of AnnotationsList().
+  template <class Traits>
+  void ReadCrashpadAnnotationsList(
+      std::vector<AnnotationSnapshot>* vector_annotations) const;
+
   std::wstring name_;
   ProcessReaderWin* process_reader_;  // weak
   const PEImageReader* pe_image_reader_;  // weak
diff --git a/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader_test.cc b/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader_test.cc
index f69f5ab..f576394 100644
--- a/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader_test.cc
@@ -27,6 +27,7 @@
 #include "client/crashpad_info.h"
 #include "client/simple_string_dictionary.h"
 #include "gtest/gtest.h"
+#include "snapshot/annotation_snapshot.h"
 #include "snapshot/win/pe_image_reader.h"
 #include "snapshot/win/process_reader_win.h"
 #include "test/gtest_disabled.h"
@@ -47,15 +48,14 @@
   kCrashDebugBreak,
 };
 
-void TestAnnotationsOnCrash(TestType type, const base::FilePath& directory) {
+void TestAnnotationsOnCrash(TestType type,
+                            TestPaths::Architecture architecture) {
   // Spawn a child process, passing it the pipe name to connect to.
-  std::wstring child_test_executable = directory
-                                           .Append(TestPaths::Executable()
-                                                       .BaseName()
-                                                       .RemoveFinalExtension()
-                                                       .value() +
-                                                   L"_simple_annotations.exe")
-                                           .value();
+  base::FilePath child_test_executable =
+      TestPaths::BuildArtifact(L"snapshot",
+                               L"annotations",
+                               TestPaths::FileType::kExecutable,
+                               architecture);
   ChildLauncher child(child_test_executable, L"");
   ASSERT_NO_FATAL_FAILURE(child.Start());
 
@@ -68,9 +68,11 @@
   ASSERT_TRUE(process_reader.Initialize(child.process_handle(),
                                         ProcessSuspensionState::kRunning));
 
-  // Verify the "simple map" annotations set via the CrashpadInfo interface.
+  // Read all the kinds of annotations referenced from the CrashpadInfo
+  // structure.
   const std::vector<ProcessInfo::Module>& modules = process_reader.Modules();
   std::map<std::string, std::string> all_annotations_simple_map;
+  std::vector<AnnotationSnapshot> all_annotation_objects;
   for (const ProcessInfo::Module& module : modules) {
     PEImageReader pe_image_reader;
     pe_image_reader.Initialize(&process_reader,
@@ -79,12 +81,19 @@
                                base::UTF16ToUTF8(module.name));
     PEImageAnnotationsReader module_annotations_reader(
         &process_reader, &pe_image_reader, module.name);
+
     std::map<std::string, std::string> module_annotations_simple_map =
         module_annotations_reader.SimpleMap();
     all_annotations_simple_map.insert(module_annotations_simple_map.begin(),
                                       module_annotations_simple_map.end());
+
+    auto module_annotations_list = module_annotations_reader.AnnotationsList();
+    all_annotation_objects.insert(all_annotation_objects.end(),
+                                  module_annotations_list.begin(),
+                                  module_annotations_list.end());
   }
 
+  // Verify the "simple map" annotations.
   EXPECT_GE(all_annotations_simple_map.size(), 5u);
   EXPECT_EQ(all_annotations_simple_map["#TEST# pad"], "crash");
   EXPECT_EQ(all_annotations_simple_map["#TEST# key"], "value");
@@ -92,6 +101,32 @@
   EXPECT_EQ(all_annotations_simple_map["#TEST# longer"], "shorter");
   EXPECT_EQ(all_annotations_simple_map["#TEST# empty_value"], "");
 
+  // Verify the typed annotation objects.
+  EXPECT_EQ(all_annotation_objects.size(), 3);
+  bool saw_same_name_3 = false, saw_same_name_4 = false;
+  for (const auto& annotation : all_annotation_objects) {
+    EXPECT_EQ(annotation.type,
+              static_cast<uint16_t>(Annotation::Type::kString));
+    std::string value(reinterpret_cast<const char*>(annotation.value.data()),
+                      annotation.value.size());
+
+    if (annotation.name == "#TEST# one") {
+      EXPECT_EQ(value, "moocow");
+    } else if (annotation.name == "#TEST# same-name") {
+      if (value == "same-name 3") {
+        EXPECT_FALSE(saw_same_name_3);
+        saw_same_name_3 = true;
+      } else if (value == "same-name 4") {
+        EXPECT_FALSE(saw_same_name_4);
+        saw_same_name_4 = true;
+      } else {
+        ADD_FAILURE() << "unexpected annotation value " << value;
+      }
+    } else {
+      ADD_FAILURE() << "unexpected annotation " << annotation.name;
+    }
+  }
+
   // Tell the child process to continue.
   DWORD expected_exit_code;
   switch (type) {
@@ -112,30 +147,28 @@
 }
 
 TEST(PEImageAnnotationsReader, DontCrash) {
-  TestAnnotationsOnCrash(kDontCrash, TestPaths::Executable().DirName());
+  TestAnnotationsOnCrash(kDontCrash, TestPaths::Architecture::kDefault);
 }
 
 TEST(PEImageAnnotationsReader, CrashDebugBreak) {
-  TestAnnotationsOnCrash(kCrashDebugBreak, TestPaths::Executable().DirName());
+  TestAnnotationsOnCrash(kCrashDebugBreak, TestPaths::Architecture::kDefault);
 }
 
 #if defined(ARCH_CPU_64_BITS)
 TEST(PEImageAnnotationsReader, DontCrashWOW64) {
-  base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
-  if (output_32_bit_directory.empty()) {
+  if (!TestPaths::Has32BitBuildArtifacts()) {
     DISABLED_TEST();
   }
 
-  TestAnnotationsOnCrash(kDontCrash, output_32_bit_directory);
+  TestAnnotationsOnCrash(kDontCrash, TestPaths::Architecture::k32Bit);
 }
 
 TEST(PEImageAnnotationsReader, CrashDebugBreakWOW64) {
-  base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
-  if (output_32_bit_directory.empty()) {
+  if (!TestPaths::Has32BitBuildArtifacts()) {
     DISABLED_TEST();
   }
 
-  TestAnnotationsOnCrash(kCrashDebugBreak, output_32_bit_directory);
+  TestAnnotationsOnCrash(kCrashDebugBreak, TestPaths::Architecture::k32Bit);
 }
 #endif  // ARCH_CPU_64_BITS
 
diff --git a/third_party/crashpad/crashpad/snapshot/win/pe_image_reader_test.cc b/third_party/crashpad/crashpad/snapshot/win/pe_image_reader_test.cc
index bf53279..3192a44 100644
--- a/third_party/crashpad/crashpad/snapshot/win/pe_image_reader_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/pe_image_reader_test.cc
@@ -22,6 +22,7 @@
 #include "gtest/gtest.h"
 #include "snapshot/win/process_reader_win.h"
 #include "test/errors.h"
+#include "test/test_paths.h"
 #include "util/misc/from_pointer_cast.h"
 #include "util/win/get_module_information.h"
 #include "util/win/module_version.h"
@@ -52,7 +53,11 @@
   DWORD age;
   std::string pdbname;
   EXPECT_TRUE(pe_image_reader.DebugDirectoryInformation(&uuid, &age, &pdbname));
-  EXPECT_NE(pdbname.find("crashpad_snapshot_test"), std::string::npos);
+  std::string self_name = base::UTF16ToUTF8(
+      TestPaths::ExpectedExecutableBasename(L"crashpad_snapshot_test")
+          .RemoveFinalExtension()
+          .value());
+  EXPECT_NE(pdbname.find(self_name), std::string::npos);
   const std::string suffix(".pdb");
   EXPECT_EQ(
       pdbname.compare(pdbname.size() - suffix.size(), suffix.size(), suffix),
@@ -73,13 +78,14 @@
   ASSERT_TRUE(observed_rv || !known_dll);
 
   if (observed_rv) {
-    EXPECT_EQ(observed.dwSignature, VS_FFI_SIGNATURE);
-    EXPECT_EQ(observed.dwStrucVersion, VS_FFI_STRUCVERSION);
-    EXPECT_EQ(observed.dwFileFlags & ~observed.dwFileFlagsMask, 0);
-    EXPECT_EQ(observed.dwFileOS, VOS_NT_WINDOWS32);
+    EXPECT_EQ(observed.dwSignature, static_cast<DWORD>(VS_FFI_SIGNATURE));
+    EXPECT_EQ(observed.dwStrucVersion, static_cast<DWORD>(VS_FFI_STRUCVERSION));
+    EXPECT_EQ(observed.dwFileFlags & ~observed.dwFileFlagsMask, 0u);
     if (known_dll) {
-      EXPECT_EQ(observed.dwFileType, VFT_DLL);
+      EXPECT_EQ(observed.dwFileOS, static_cast<DWORD>(VOS_NT_WINDOWS32));
+      EXPECT_EQ(observed.dwFileType, static_cast<DWORD>(VFT_DLL));
     } else {
+      EXPECT_NE(observed.dwFileOS & VOS_NT_WINDOWS32, 0u);
       EXPECT_TRUE(observed.dwFileType == VFT_APP ||
                   observed.dwFileType == VFT_DLL);
     }
diff --git a/third_party/crashpad/crashpad/snapshot/win/process_reader_win_test.cc b/third_party/crashpad/crashpad/snapshot/win/process_reader_win_test.cc
index 9e62e11..d0d4d96 100644
--- a/third_party/crashpad/crashpad/snapshot/win/process_reader_win_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/process_reader_win_test.cc
@@ -107,12 +107,12 @@
 
   EXPECT_EQ(threads[0].id, GetCurrentThreadId());
 #if defined(ARCH_CPU_64_BITS)
-  EXPECT_NE(threads[0].context.native.Rip, 0);
+  EXPECT_NE(threads[0].context.native.Rip, 0u);
 #else
   EXPECT_NE(threads[0].context.native.Eip, 0u);
 #endif
 
-  EXPECT_EQ(threads[0].suspend_count, 0);
+  EXPECT_EQ(threads[0].suspend_count, 0u);
 }
 
 class ProcessReaderChildThreadSuspendCount final : public WinMultiprocess {
@@ -188,7 +188,7 @@
     // the pipe.
     CheckedReadFileAtEOF(ReadPipeHandle());
 
-    for (int i = 0; i < arraysize(threads); ++i)
+    for (size_t i = 0; i < arraysize(threads); ++i)
       done.Signal();
     for (auto& thread : threads)
       thread.Join();
diff --git a/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win_test.cc b/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win_test.cc
index 839ba48..b2448fc 100644
--- a/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win_test.cc
@@ -31,20 +31,18 @@
 namespace test {
 namespace {
 
-void TestImageReaderChild(const base::FilePath& directory) {
+void TestImageReaderChild(const TestPaths::Architecture architecture) {
   UUID done_uuid;
   done_uuid.InitializeWithNew();
   ScopedKernelHANDLE done(
       CreateEvent(nullptr, true, false, done_uuid.ToString16().c_str()));
   ASSERT_TRUE(done.is_valid()) << ErrorMessage("CreateEvent");
 
-  std::wstring child_test_executable = directory
-                                           .Append(TestPaths::Executable()
-                                                       .BaseName()
-                                                       .RemoveFinalExtension()
-                                                       .value() +
-                                                   L"_image_reader.exe")
-                                           .value();
+  base::FilePath child_test_executable =
+      TestPaths::BuildArtifact(L"snapshot",
+                               L"image_reader",
+                               TestPaths::FileType::kExecutable,
+                               architecture);
   ChildLauncher child(child_test_executable, done_uuid.ToString16());
   ASSERT_NO_FATAL_FAILURE(child.Start());
 
@@ -109,21 +107,20 @@
   // Tell the child it can terminate.
   EXPECT_TRUE(SetEvent(done.get())) << ErrorMessage("SetEvent");
 
-  EXPECT_EQ(child.WaitForExit(), 0);
+  EXPECT_EQ(child.WaitForExit(), 0u);
 }
 
 TEST(ProcessSnapshotTest, CrashpadInfoChild) {
-  TestImageReaderChild(TestPaths::Executable().DirName());
+  TestImageReaderChild(TestPaths::Architecture::kDefault);
 }
 
 #if defined(ARCH_CPU_64_BITS)
 TEST(ProcessSnapshotTest, CrashpadInfoChildWOW64) {
-  base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
-  if (output_32_bit_directory.empty()) {
+  if (!TestPaths::Has32BitBuildArtifacts()) {
     DISABLED_TEST();
   }
 
-  TestImageReaderChild(output_32_bit_directory);
+  TestImageReaderChild(TestPaths::Architecture::k32Bit);
 }
 #endif
 
diff --git a/third_party/crashpad/crashpad/util/file/filesystem_test_util.cc b/third_party/crashpad/crashpad/test/filesystem.cc
similarity index 98%
rename from third_party/crashpad/crashpad/util/file/filesystem_test_util.cc
rename to third_party/crashpad/crashpad/test/filesystem.cc
index 5d991ee7..a9a73f6a 100644
--- a/third_party/crashpad/crashpad/util/file/filesystem_test_util.cc
+++ b/third_party/crashpad/crashpad/test/filesystem.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "util/file/filesystem_test_util.h"
+#include "test/filesystem.h"
 
 #include <errno.h>
 #include <sys/stat.h>
diff --git a/third_party/crashpad/crashpad/util/file/filesystem_test_util.h b/third_party/crashpad/crashpad/test/filesystem.h
similarity index 92%
rename from third_party/crashpad/crashpad/util/file/filesystem_test_util.h
rename to third_party/crashpad/crashpad/test/filesystem.h
index b74653f..7e65845 100644
--- a/third_party/crashpad/crashpad/util/file/filesystem_test_util.h
+++ b/third_party/crashpad/crashpad/test/filesystem.h
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef CRASHPAD_UTIL_FILE_FILESYSTEM_TEST_UTIL_H_
-#define CRASHPAD_UTIL_FILE_FILESYSTEM_TEST_UTIL_H_
+#ifndef CRASHPAD_TEST_FILESYSTEM_H_
+#define CRASHPAD_TEST_FILESYSTEM_H_
 
 #include "base/files/file_path.h"
 
@@ -56,4 +56,4 @@
 }  // namespace test
 }  // namespace crashpad
 
-#endif  // CRASHPAD_UTIL_FILE_FILESYSTEM_TEST_UTIL_H_
+#endif  // CRASHPAD_TEST_FILESYSTEM_H_
diff --git a/third_party/crashpad/crashpad/test/gtest_main.cc b/third_party/crashpad/crashpad/test/gtest_main.cc
index 6e082828..d8c2a904 100644
--- a/third_party/crashpad/crashpad/test/gtest_main.cc
+++ b/third_party/crashpad/crashpad/test/gtest_main.cc
@@ -33,15 +33,6 @@
 
 int main(int argc, char* argv[]) {
   crashpad::test::InitializeMainArguments(argc, argv);
-
-#if defined(CRASHPAD_TEST_LAUNCHER_GMOCK)
-  testing::InitGoogleMock(&argc, argv);
-#elif defined(CRASHPAD_TEST_LAUNCHER_GTEST)
-  testing::InitGoogleTest(&argc, argv);
-#else  // CRASHPAD_TEST_LAUNCHER_GTEST
-#error #define CRASHPAD_TEST_LAUNCHER_GTEST or CRASHPAD_TEST_LAUNCHER_GMOCK
-#endif  // CRASHPAD_TEST_LAUNCHER_GTEST
-
   testing::AddGlobalTestEnvironment(
       crashpad::test::DisabledTestGtestEnvironment::Get());
 
@@ -69,5 +60,13 @@
 
 #endif  // CRASHPAD_IN_CHROMIUM
 
+#if defined(CRASHPAD_TEST_LAUNCHER_GMOCK)
+  testing::InitGoogleMock(&argc, argv);
+#elif defined(CRASHPAD_TEST_LAUNCHER_GTEST)
+  testing::InitGoogleTest(&argc, argv);
+#else  // CRASHPAD_TEST_LAUNCHER_GMOCK
+#error #define CRASHPAD_TEST_LAUNCHER_GTEST or CRASHPAD_TEST_LAUNCHER_GMOCK
+#endif  // CRASHPAD_TEST_LAUNCHER_GMOCK
+
   return RUN_ALL_TESTS();
 }
diff --git a/third_party/crashpad/crashpad/test/multiprocess_exec.h b/third_party/crashpad/crashpad/test/multiprocess_exec.h
index 9b2ffc1..258a3f8 100644
--- a/third_party/crashpad/crashpad/test/multiprocess_exec.h
+++ b/third_party/crashpad/crashpad/test/multiprocess_exec.h
@@ -18,6 +18,7 @@
 #include <string>
 #include <vector>
 
+#include "base/files/file_path.h"
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "test/multiprocess.h"
@@ -48,7 +49,7 @@
   //!     process in its `argv[]` vector. This vector must begin at `argv[1]`,
   //!     as \a command is implicitly used as `argv[0]`. This argument may be
   //!     `nullptr` if no command-line arguments are to be passed.
-  void SetChildCommand(const std::string& command,
+  void SetChildCommand(const base::FilePath& command,
                        const std::vector<std::string>* arguments);
 
  protected:
@@ -61,7 +62,7 @@
   // Multiprocess:
   void MultiprocessChild() override;
 
-  std::string command_;
+  base::FilePath command_;
   std::vector<std::string> arguments_;
 #if defined(OS_POSIX)
   std::vector<const char*> argv_;
diff --git a/third_party/crashpad/crashpad/test/multiprocess_exec_posix.cc b/third_party/crashpad/crashpad/test/multiprocess_exec_posix.cc
index 3d7212d..528e8c7 100644
--- a/third_party/crashpad/crashpad/test/multiprocess_exec_posix.cc
+++ b/third_party/crashpad/crashpad/test/multiprocess_exec_posix.cc
@@ -40,7 +40,8 @@
 }
 
 void MultiprocessExec::SetChildCommand(
-    const std::string& command, const std::vector<std::string>* arguments) {
+    const base::FilePath& command,
+    const std::vector<std::string>* arguments) {
   command_ = command;
   if (arguments) {
     arguments_ = *arguments;
@@ -62,7 +63,7 @@
   // process, building it is a hazardous operation in that process.
   ASSERT_TRUE(argv_.empty());
 
-  argv_.push_back(command_.c_str());
+  argv_.push_back(command_.value().c_str());
   for (const std::string& argument : arguments_) {
     argv_.push_back(argument.c_str());
   }
diff --git a/third_party/crashpad/crashpad/test/multiprocess_exec_test.cc b/third_party/crashpad/crashpad/test/multiprocess_exec_test.cc
index f35519a..b8a5bc194 100644
--- a/third_party/crashpad/crashpad/test/multiprocess_exec_test.cc
+++ b/third_party/crashpad/crashpad/test/multiprocess_exec_test.cc
@@ -48,17 +48,10 @@
 
 TEST(MultiprocessExec, MultiprocessExec) {
   TestMultiprocessExec multiprocess_exec;
-  base::FilePath test_executable = TestPaths::Executable();
-#if defined(OS_POSIX)
-  std::string child_test_executable = test_executable.value();
-#elif defined(OS_WIN)
-  std::string child_test_executable =
-      base::UTF16ToUTF8(test_executable.RemoveFinalExtension().value());
-#endif  // OS_POSIX
-  child_test_executable += "_multiprocess_exec_test_child";
-#if defined(OS_WIN)
-  child_test_executable += ".exe";
-#endif
+  base::FilePath child_test_executable = TestPaths::BuildArtifact(
+      FILE_PATH_LITERAL("test"),
+      FILE_PATH_LITERAL("multiprocess_exec_test_child"),
+      TestPaths::FileType::kExecutable);
   multiprocess_exec.SetChildCommand(child_test_executable, nullptr);
   multiprocess_exec.Run();
 }
diff --git a/third_party/crashpad/crashpad/test/multiprocess_exec_win.cc b/third_party/crashpad/crashpad/test/multiprocess_exec_win.cc
index 5eb5d80..f3a10c4 100644
--- a/third_party/crashpad/crashpad/test/multiprocess_exec_win.cc
+++ b/third_party/crashpad/crashpad/test/multiprocess_exec_win.cc
@@ -102,7 +102,7 @@
 }
 
 void MultiprocessExec::SetChildCommand(
-    const std::string& command,
+    const base::FilePath& command,
     const std::vector<std::string>* arguments) {
   command_ = command;
   if (arguments) {
@@ -119,7 +119,7 @@
   ASSERT_FALSE(command_.empty());
 
   command_line_.clear();
-  AppendCommandLineArgument(base::UTF8ToUTF16(command_), &command_line_);
+  AppendCommandLineArgument(command_.value(), &command_line_);
   for (size_t i = 0; i < arguments_.size(); ++i) {
     AppendCommandLineArgument(base::UTF8ToUTF16(arguments_[i]), &command_line_);
   }
@@ -154,7 +154,7 @@
   startup_info.hStdOutput = info()->pipe_c2p_write.get();
   startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
   startup_info.dwFlags = STARTF_USESTDHANDLES;
-  PCHECK(CreateProcess(base::UTF8ToUTF16(command_).c_str(),
+  PCHECK(CreateProcess(command_.value().c_str(),
                        &command_line_[0],  // This cannot be constant, per MSDN.
                        nullptr,
                        nullptr,
diff --git a/third_party/crashpad/crashpad/test/test.gyp b/third_party/crashpad/crashpad/test/test.gyp
index 931d948..4b38933 100644
--- a/third_party/crashpad/crashpad/test/test.gyp
+++ b/third_party/crashpad/crashpad/test/test.gyp
@@ -35,6 +35,8 @@
         'errors.h',
         'file.cc',
         'file.h',
+        'filesystem.cc',
+        'filesystem.h',
         'gtest_death_check.h',
         'gtest_disabled.cc',
         'gtest_disabled.h',
diff --git a/third_party/crashpad/crashpad/test/test_paths.cc b/third_party/crashpad/crashpad/test/test_paths.cc
index a601208..ce180a37 100644
--- a/third_party/crashpad/crashpad/test/test_paths.cc
+++ b/third_party/crashpad/crashpad/test/test_paths.cc
@@ -90,6 +90,23 @@
   return base::FilePath(base::FilePath::kCurrentDirectory);
 }
 
+#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
+
+// Returns the pathname of a directory containing 32-bit test build output.
+//
+// It would be better for this to be named 32BitOutputDirectory(), but that’s
+// not a legal name.
+base::FilePath Output32BitDirectory() {
+  const wchar_t* environment_value = _wgetenv(L"CRASHPAD_TEST_32_BIT_OUTPUT");
+  if (!environment_value) {
+    return base::FilePath();
+  }
+
+  return base::FilePath(environment_value);
+}
+
+#endif  // defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
+
 }  // namespace
 
 // static
@@ -100,22 +117,84 @@
 }
 
 // static
+base::FilePath TestPaths::ExpectedExecutableBasename(
+    const base::FilePath::StringType& name) {
+#if defined(CRASHPAD_IN_CHROMIUM)
+  base::FilePath::StringType executable_name(
+      FILE_PATH_LITERAL("crashpad_tests"));
+#else  // CRASHPAD_IN_CHROMIUM
+  base::FilePath::StringType executable_name(name);
+#endif  // CRASHPAD_IN_CHROMIUM
+
+#if defined(OS_WIN)
+  executable_name += FILE_PATH_LITERAL(".exe");
+#endif  // OS_WIN
+
+  return base::FilePath(executable_name);
+}
+
+// static
 base::FilePath TestPaths::TestDataRoot() {
   static base::FilePath* test_data_root =
       new base::FilePath(TestDataRootInternal());
   return *test_data_root;
 }
 
+// static
+base::FilePath TestPaths::BuildArtifact(
+    const base::FilePath::StringType& module,
+    const base::FilePath::StringType& artifact,
+    FileType file_type,
+    Architecture architecture) {
+  base::FilePath directory;
+  switch (architecture) {
+    case Architecture::kDefault:
+      directory = Executable().DirName();
+      break;
+
+#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
+    case Architecture::k32Bit:
+      directory = Output32BitDirectory();
+      CHECK(!directory.empty());
+      break;
+#endif  // OS_WIN && ARCH_CPU_64_BITS
+  }
+
+  base::FilePath::StringType test_name =
+      FILE_PATH_LITERAL("crashpad_") + module + FILE_PATH_LITERAL("_test");
+#if !defined(CRASHPAD_IN_CHROMIUM)
+  CHECK(Executable().BaseName().RemoveFinalExtension().value() == test_name);
+#endif  // !CRASHPAD_IN_CHROMIUM
+
+  base::FilePath::StringType extension;
+  switch (file_type) {
+    case FileType::kNone:
+      break;
+
+    case FileType::kExecutable:
+#if defined(OS_WIN)
+      extension = FILE_PATH_LITERAL(".exe");
+#endif  // OS_WIN
+      break;
+
+    case FileType::kLoadableModule:
+#if defined(OS_WIN)
+      extension = FILE_PATH_LITERAL(".dll");
+#else  // OS_WIN
+      extension = FILE_PATH_LITERAL(".so");
+#endif  // OS_WIN
+      break;
+  }
+
+  return directory.Append(test_name + FILE_PATH_LITERAL("_") + artifact +
+                          extension);
+}
+
 #if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
 
 // static
-base::FilePath TestPaths::Output32BitDirectory() {
-  const wchar_t* environment_value = _wgetenv(L"CRASHPAD_TEST_32_BIT_OUTPUT");
-  if (!environment_value) {
-    return base::FilePath();
-  }
-
-  return base::FilePath(environment_value);
+bool TestPaths::Has32BitBuildArtifacts() {
+  return !Output32BitDirectory().empty();
 }
 
 #endif  // defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
diff --git a/third_party/crashpad/crashpad/test/test_paths.h b/third_party/crashpad/crashpad/test/test_paths.h
index f5629ed..5540f77 100644
--- a/third_party/crashpad/crashpad/test/test_paths.h
+++ b/third_party/crashpad/crashpad/test/test_paths.h
@@ -25,11 +25,61 @@
 //! \brief Functions to obtain paths from within tests.
 class TestPaths {
  public:
+  //! \brief The type of file requested of BuildArtifact().
+  //!
+  //! This is used to establish the file extension used by the returned path.
+  enum class FileType {
+    //! \brief No file extension is requested.
+    kNone = 0,
+
+    //! \brief `.exe` will be used on Windows, and no file extension will be
+    //!     used on other platforms.
+    kExecutable,
+
+    //! \brief `.dll` will be used on Windows, and `.so` will be used on other
+    //!     platforms.
+    kLoadableModule,
+  };
+
+  //! \brief The architecture of the file requested of BuildArtifact().
+  enum class Architecture {
+    //! \brief The default architecture is requested. This is usually the same
+    //!     architecture as the running process.
+    kDefault = 0,
+
+#if (defined(OS_WIN) && defined(ARCH_CPU_64_BITS)) || DOXYGEN
+    //! \brief The 32-bit variant is requested.
+    //!
+    //! On Windows, when running 64-bit code, the 32-bit variant can be
+    //! requested. Before doing so, Has32BitBuildArtifacts() must be called and
+    //! must return `true`. Otherwise, execution will be aborted.
+    k32Bit,
+#endif  // OS_WIN && ARCH_CPU_64_BITS
+  };
+
   //! \brief Returns the pathname of the currently-running test executable.
   //!
   //! On failure, aborts execution.
   static base::FilePath Executable();
 
+  //! \brief Returns the expected basename of the currently-running test
+  //!     executable.
+  //!
+  //! In Crashpad’s standalone build, this returns \a name, with the system’s
+  //! extension for executables (`.exe`) appended if appropriate.
+  //!
+  //! When building in Chromium, \a name is ignored, and the name of the
+  //! monolithic test executable (`crashpad_tests`) is returned, with the
+  //! system’s extension for executables appended if appropriate.
+  //!
+  //! Only use this function to determine test expectations.
+  //!
+  //! Do not use this function to obtain the name of the currently running test
+  //! executable, use Executable() instead. Do not use this function to locate
+  //! other build artifacts, use BuildArtifact() instead.
+  static base::FilePath ExpectedExecutableBasename(
+      const base::FilePath::StringType& name);
+
   //! \brief Returns the pathname of the test data root.
   //!
   //! If the `CRASHPAD_TEST_DATA_ROOT` environment variable is set, its value
@@ -43,21 +93,50 @@
   //! files.
   static base::FilePath TestDataRoot();
 
+  //! \brief Returns the pathname of a build artifact.
+  //!
+  //! \param[in] module The name of the Crashpad module associated with the
+  //!     artifact, such as `"util"` or `"snapshot"`. \a module must correspond
+  //!     to the module of the calling code, or execution will be aborted.
+  //! \param[in] artifact The name of the specific artifact.
+  //! \param[in] file_type The artifact’s type, used to establish the returned
+  //!     path’s extension.
+  //! \param[in] architecture The artifact’s architecture.
+  //!
+  //! \return The computed pathname to the build artifact.
+  //!
+  //! For example, the following snippet will return a path to
+  //! `crashpad_snapshot_test_module.so` or `crashpad_snapshot_test_module.dll`
+  //! (depending on platform) in the same directory as the currently running
+  //! executable:
+  //!
+  //! \code
+  //!    base::FilePath path = TestPaths::BuildArtifact(
+  //!        FILE_PATH_LITERAL("snapshot"),
+  //!        FILE_PATH_LITERAL("module"),
+  //!        TestPaths::FileType::kLoadableModule);
+  //! \endcode
+  static base::FilePath BuildArtifact(
+      const base::FilePath::StringType& module,
+      const base::FilePath::StringType& artifact,
+      FileType file_type,
+      Architecture architecture = Architecture::kDefault);
+
 #if (defined(OS_WIN) && defined(ARCH_CPU_64_BITS)) || DOXYGEN
-  //! \brief Returns the pathname of a directory containing 32-bit test build
-  //!     output.
+  //! \return `true` if 32-bit build artifacts are available.
   //!
   //! Tests that require the use of 32-bit build output should call this
-  //! function to locate that output. This function is only provided to allow
-  //! 64-bit test code to locate 32-bit output. 32-bit test code can find 32-bit
-  //! output in its own directory, the parent of Executable().
+  //! function to determine whether that output is available. This function is
+  //! only provided to aid 64-bit test code in locating 32-bit output. Only if
+  //! this function indicates that 32-bit output is available, 64-bit test code
+  //! may call BuildArtifact() with Architecture::k32Bit to obtain a path to the
+  //! 32-bit output.
   //!
-  //! If the `CRASHPAD_TEST_32_BIT_OUTPUT` environment variable is set, its
-  //! value will be returned. Otherwise, this function will return an empty
-  //! path, and tests that require the use of 32-bit build output should disable
-  //! themselves. The DISABLED_TEST() macro may be useful for this purpose.
-  static base::FilePath Output32BitDirectory();
-#endif
+  //! 32-bit test code may assume the existence of 32-bit build output, which
+  //! can be found its own directory, and located by calling BuildArtifact()
+  //! with Architecture::kDefault.
+  static bool Has32BitBuildArtifacts();
+#endif  // OS_WIN && ARCH_CPU_64_BITS
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(TestPaths);
 };
diff --git a/third_party/crashpad/crashpad/test/win/child_launcher.cc b/third_party/crashpad/crashpad/test/win/child_launcher.cc
index c5f897c3..abd2e3d9 100644
--- a/third_party/crashpad/crashpad/test/win/child_launcher.cc
+++ b/third_party/crashpad/crashpad/test/win/child_launcher.cc
@@ -21,15 +21,14 @@
 namespace crashpad {
 namespace test {
 
-ChildLauncher::ChildLauncher(const std::wstring& executable,
+ChildLauncher::ChildLauncher(const base::FilePath& executable,
                              const std::wstring& command_line)
     : executable_(executable),
       command_line_(command_line),
       process_handle_(),
       main_thread_handle_(),
       stdout_read_handle_(),
-      stdin_write_handle_() {
-}
+      stdin_write_handle_() {}
 
 ChildLauncher::~ChildLauncher() {
   if (process_handle_.is_valid())
@@ -76,10 +75,10 @@
   startup_info.dwFlags = STARTF_USESTDHANDLES;
   PROCESS_INFORMATION process_information;
   std::wstring command_line;
-  AppendCommandLineArgument(executable_, &command_line);
+  AppendCommandLineArgument(executable_.value(), &command_line);
   command_line += L" ";
   command_line += command_line_;
-  ASSERT_TRUE(CreateProcess(executable_.c_str(),
+  ASSERT_TRUE(CreateProcess(executable_.value().c_str(),
                             &command_line[0],
                             nullptr,
                             nullptr,
diff --git a/third_party/crashpad/crashpad/test/win/child_launcher.h b/third_party/crashpad/crashpad/test/win/child_launcher.h
index 6674efe..854e124 100644
--- a/third_party/crashpad/crashpad/test/win/child_launcher.h
+++ b/third_party/crashpad/crashpad/test/win/child_launcher.h
@@ -19,6 +19,7 @@
 
 #include <string>
 
+#include "base/files/file_path.h"
 #include "util/win/scoped_handle.h"
 
 namespace crashpad {
@@ -32,7 +33,7 @@
  public:
   //! \brief Creates the object. \a executable will be escaped and prepended to
   //!     \a command_line to build the command line of the child.
-  ChildLauncher(const std::wstring& executable,
+  ChildLauncher(const base::FilePath& executable,
                 const std::wstring& command_line);
 
   ~ChildLauncher();
@@ -62,7 +63,7 @@
   HANDLE stdin_write_handle() const { return stdin_write_handle_.get(); }
 
  private:
-  std::wstring executable_;
+  base::FilePath executable_;
   std::wstring command_line_;
   ScopedKernelHANDLE process_handle_;
   ScopedKernelHANDLE main_thread_handle_;
diff --git a/third_party/crashpad/crashpad/util/file/directory_reader_test.cc b/third_party/crashpad/crashpad/util/file/directory_reader_test.cc
index 640b850..f03669e2 100644
--- a/third_party/crashpad/crashpad/util/file/directory_reader_test.cc
+++ b/third_party/crashpad/crashpad/util/file/directory_reader_test.cc
@@ -21,11 +21,11 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "gtest/gtest.h"
+#include "test/filesystem.h"
 #include "test/gtest_disabled.h"
 #include "test/scoped_temp_dir.h"
 #include "util/file/file_io.h"
 #include "util/file/filesystem.h"
-#include "util/file/filesystem_test_util.h"
 
 namespace crashpad {
 namespace test {
diff --git a/third_party/crashpad/crashpad/util/file/filesystem_test.cc b/third_party/crashpad/crashpad/util/file/filesystem_test.cc
index 8657e5b..7e28892 100644
--- a/third_party/crashpad/crashpad/util/file/filesystem_test.cc
+++ b/third_party/crashpad/crashpad/util/file/filesystem_test.cc
@@ -17,9 +17,9 @@
 #include "base/logging.h"
 #include "build/build_config.h"
 #include "gtest/gtest.h"
+#include "test/filesystem.h"
 #include "test/gtest_disabled.h"
 #include "test/scoped_temp_dir.h"
-#include "util/file/filesystem_test_util.h"
 
 namespace crashpad {
 namespace test {
diff --git a/third_party/crashpad/crashpad/util/misc/paths_test.cc b/third_party/crashpad/crashpad/util/misc/paths_test.cc
index 1f373029..f0503ddc 100644
--- a/third_party/crashpad/crashpad/util/misc/paths_test.cc
+++ b/third_party/crashpad/crashpad/util/misc/paths_test.cc
@@ -15,8 +15,8 @@
 #include "util/misc/paths.h"
 
 #include "base/files/file_path.h"
-#include "build/build_config.h"
 #include "gtest/gtest.h"
+#include "test/test_paths.h"
 
 namespace crashpad {
 namespace test {
@@ -26,12 +26,10 @@
   base::FilePath executable_path;
   ASSERT_TRUE(Paths::Executable(&executable_path));
   const base::FilePath executable_name(executable_path.BaseName());
-#if defined(OS_WIN)
-  EXPECT_EQ(executable_name.value(),
-            FILE_PATH_LITERAL("crashpad_util_test.exe"));
-#else
-  EXPECT_EQ(executable_name.value(), "crashpad_util_test");
-#endif  // OS_WIN
+  const base::FilePath expected_name(TestPaths::ExpectedExecutableBasename(
+      FILE_PATH_LITERAL("crashpad_util_test")));
+
+  EXPECT_EQ(executable_name.value(), expected_name.value());
 }
 
 }  // namespace
diff --git a/third_party/crashpad/crashpad/util/net/http_transport_test.cc b/third_party/crashpad/crashpad/util/net/http_transport_test.cc
index 3b7e7eb..fc02ba1 100644
--- a/third_party/crashpad/crashpad/util/net/http_transport_test.cc
+++ b/third_party/crashpad/crashpad/util/net/http_transport_test.cc
@@ -59,7 +59,7 @@
     base::FilePath server_path = TestPaths::TestDataRoot().Append(
         FILE_PATH_LITERAL("util/net/http_transport_test_server.py"));
 #if defined(OS_POSIX)
-    SetChildCommand(server_path.value(), nullptr);
+    SetChildCommand(server_path, nullptr);
 #elif defined(OS_WIN)
     // Explicitly invoke a shell and python so that python can be found in the
     // path, and run the test script.
@@ -67,7 +67,7 @@
     args.push_back("/c");
     args.push_back("python");
     args.push_back(base::UTF16ToUTF8(server_path.value()));
-    SetChildCommand(getenv("COMSPEC"), &args);
+    SetChildCommand(base::FilePath(_wgetenv(L"COMSPEC")), &args);
 #endif  // OS_POSIX
   }
 
diff --git a/third_party/crashpad/crashpad/util/net/http_transport_win.cc b/third_party/crashpad/crashpad/util/net/http_transport_win.cc
index 9698df3..dc3eeeb 100644
--- a/third_party/crashpad/crashpad/util/net/http_transport_win.cc
+++ b/third_party/crashpad/crashpad/util/net/http_transport_win.cc
@@ -101,6 +101,12 @@
                               GetLastError(),
                               error_code);
   }
+
+  // Most system messages end in a space. Remove the space if it’s there,
+  // because the StringPrintf() below includes one.
+  if (len >= 1 && msgbuf[len - 1] == ' ') {
+    msgbuf[len - 1] = '\0';
+  }
   return base::StringPrintf("%s: %s (0x%lx)", extra, msgbuf, error_code);
 }
 
diff --git a/third_party/crashpad/crashpad/util/stdlib/aligned_allocator.cc b/third_party/crashpad/crashpad/util/stdlib/aligned_allocator.cc
index 363022c..9aedb29 100644
--- a/third_party/crashpad/crashpad/util/stdlib/aligned_allocator.cc
+++ b/third_party/crashpad/crashpad/util/stdlib/aligned_allocator.cc
@@ -42,7 +42,6 @@
 }  // namespace
 
 namespace crashpad {
-namespace internal {
 
 void* AlignedAllocate(size_t alignment, size_t size) {
 #if defined(OS_POSIX)
@@ -74,5 +73,4 @@
 #endif  // OS_POSIX
 }
 
-}  // namespace internal
 }  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/util/stdlib/aligned_allocator.h b/third_party/crashpad/crashpad/util/stdlib/aligned_allocator.h
index c3beb74..97be27a 100644
--- a/third_party/crashpad/crashpad/util/stdlib/aligned_allocator.h
+++ b/third_party/crashpad/crashpad/util/stdlib/aligned_allocator.h
@@ -24,7 +24,6 @@
 #include <vector>
 
 namespace crashpad {
-namespace internal {
 
 //! \brief Allocates memory with the specified alignment constraint.
 //!
@@ -37,8 +36,6 @@
 //! This function wraps `free()` or `_aligned_free()`.
 void AlignedFree(void* pointer);
 
-}  // namespace internal
-
 //! \brief A standard allocator that aligns its allocations as requested,
 //!     suitable for use as an allocator in standard containers.
 //!
@@ -74,10 +71,10 @@
 
   pointer allocate(size_type n, std::allocator<void>::const_pointer hint = 0) {
     return reinterpret_cast<pointer>(
-        internal::AlignedAllocate(Alignment, sizeof(value_type) * n));
+        AlignedAllocate(Alignment, sizeof(value_type) * n));
   }
 
-  void deallocate(pointer p, size_type n) { internal::AlignedFree(p); }
+  void deallocate(pointer p, size_type n) { AlignedFree(p); }
 
   size_type max_size() const noexcept {
     return std::numeric_limits<size_type>::max() / sizeof(value_type);
diff --git a/third_party/crashpad/crashpad/util/util_test.gyp b/third_party/crashpad/crashpad/util/util_test.gyp
index ede3259..152c981 100644
--- a/third_party/crashpad/crashpad/util/util_test.gyp
+++ b/third_party/crashpad/crashpad/util/util_test.gyp
@@ -40,8 +40,6 @@
         'file/file_io_test.cc',
         'file/file_reader_test.cc',
         'file/filesystem_test.cc',
-        'file/filesystem_test_util.cc',
-        'file/filesystem_test_util.h',
         'file/string_file_test.cc',
         'linux/auxiliary_vector_test.cc',
         'linux/memory_map_test.cc',
diff --git a/third_party/crashpad/crashpad/util/win/process_info_test.cc b/third_party/crashpad/crashpad/util/win/process_info_test.cc
index 051479d..709536b 100644
--- a/third_party/crashpad/crashpad/util/win/process_info_test.cc
+++ b/third_party/crashpad/crashpad/util/win/process_info_test.cc
@@ -104,10 +104,12 @@
   std::vector<ProcessInfo::Module> modules;
   EXPECT_TRUE(process_info.Modules(&modules));
   ASSERT_GE(modules.size(), 2u);
-  static constexpr wchar_t kSelfName[] = L"\\crashpad_util_test.exe";
-  ASSERT_GE(modules[0].name.size(), wcslen(kSelfName));
-  EXPECT_EQ(modules[0].name.substr(modules[0].name.size() - wcslen(kSelfName)),
-            kSelfName);
+  std::wstring self_name =
+      std::wstring(1, '\\') +
+      TestPaths::ExpectedExecutableBasename(L"crashpad_util_test").value();
+  ASSERT_GE(modules[0].name.size(), self_name.size());
+  EXPECT_EQ(modules[0].name.substr(modules[0].name.size() - self_name.size()),
+            self_name);
   ASSERT_GE(modules[1].name.size(), wcslen(kNtdllName));
   EXPECT_EQ(modules[1].name.substr(modules[1].name.size() - wcslen(kNtdllName)),
             kNtdllName);
@@ -132,7 +134,7 @@
                             FromPointerCast<WinVMAddress>(_ReturnAddress()));
 }
 
-void TestOtherProcess(const base::FilePath& directory) {
+void TestOtherProcess(TestPaths::Architecture architecture) {
   ProcessInfo process_info;
 
   UUID done_uuid;
@@ -142,15 +144,11 @@
       CreateEvent(nullptr, true, false, done_uuid.ToString16().c_str()));
   ASSERT_TRUE(done.get()) << ErrorMessage("CreateEvent");
 
-  std::wstring child_test_executable =
-      directory
-          .Append(TestPaths::Executable()
-                      .BaseName()
-                      .RemoveFinalExtension()
-                      .value() +
-                  L"_process_info_test_child.exe")
-          .value();
-
+  base::FilePath child_test_executable =
+      TestPaths::BuildArtifact(L"util",
+                               L"process_info_test_child",
+                               TestPaths::FileType::kExecutable,
+                               architecture);
   std::wstring args;
   AppendCommandLineArgument(done_uuid.ToString16(), &args);
 
@@ -191,17 +189,16 @@
 }
 
 TEST(ProcessInfo, OtherProcess) {
-  TestOtherProcess(TestPaths::Executable().DirName());
+  TestOtherProcess(TestPaths::Architecture::kDefault);
 }
 
 #if defined(ARCH_CPU_64_BITS)
 TEST(ProcessInfo, OtherProcessWOW64) {
-  base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory();
-  if (output_32_bit_directory.empty()) {
+  if (!TestPaths::Has32BitBuildArtifacts()) {
     DISABLED_TEST();
   }
 
-  TestOtherProcess(output_32_bit_directory);
+  TestOtherProcess(TestPaths::Architecture::k32Bit);
 }
 #endif  // ARCH_CPU_64_BITS
 
diff --git a/third_party/crashpad/crashpad/util/win/safe_terminate_process_test.cc b/third_party/crashpad/crashpad/util/win/safe_terminate_process_test.cc
index e3bfde7..3aba159 100644
--- a/third_party/crashpad/crashpad/util/win/safe_terminate_process_test.cc
+++ b/third_party/crashpad/crashpad/util/win/safe_terminate_process_test.cc
@@ -163,14 +163,11 @@
 }
 
 TEST(SafeTerminateProcess, TerminateChild) {
-  base::FilePath test_executable = TestPaths::Executable();
-  std::wstring child_executable =
-      test_executable.DirName()
-          .Append(test_executable.BaseName().RemoveFinalExtension().value() +
-                  L"_safe_terminate_process_test_child.exe")
-          .value();
-
-  ChildLauncher child(child_executable, std::wstring());
+  base::FilePath child_executable =
+      TestPaths::BuildArtifact(L"util",
+                               L"safe_terminate_process_test_child",
+                               TestPaths::FileType::kExecutable);
+  ChildLauncher child(child_executable, L"");
   ASSERT_NO_FATAL_FAILURE(child.Start());
 
   constexpr DWORD kExitCode = 0x51ee9d1e;  // Sort of like “sleep and die.”
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium
index 24eb91c..ecc31e8 100644
--- a/third_party/libvpx/README.chromium
+++ b/third_party/libvpx/README.chromium
@@ -5,9 +5,9 @@
 License File: source/libvpx/LICENSE
 Security Critical: yes
 
-Date: Wednesday October 18 2017
+Date: Wednesday November 01 2017
 Branch: master
-Commit: 401e6d48bfd3cbf74a41da724d05c989e207662b
+Commit: 3ba9a2c8b2341430b001ed531f1eedf7c9b0384f
 
 Description:
 Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/libvpx_srcs.gni b/third_party/libvpx/libvpx_srcs.gni
index c3eefa2..62ae7506 100644
--- a/third_party/libvpx/libvpx_srcs.gni
+++ b/third_party/libvpx/libvpx_srcs.gni
@@ -460,6 +460,7 @@
 ]
 libvpx_srcs_x86_avx2 = [
   "//third_party/libvpx/source/libvpx/vp9/encoder/x86/vp9_error_avx2.c",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/avg_intrin_avx2.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/fwd_txfm_avx2.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_convolve_avx2.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/loopfilter_avx2.c",
@@ -930,6 +931,7 @@
 ]
 libvpx_srcs_x86_64_avx2 = [
   "//third_party/libvpx/source/libvpx/vp9/encoder/x86/vp9_error_avx2.c",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/avg_intrin_avx2.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/fwd_txfm_avx2.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_convolve_avx2.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/loopfilter_avx2.c",
diff --git a/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h
index 52c3d2c..3baa8752 100644
--- a/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h
@@ -701,18 +701,18 @@
 #define vpx_h_predictor_8x8 vpx_h_predictor_8x8_neon
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           int16_t* coeff);
 void vpx_hadamard_16x16_neon(const int16_t* src_diff,
-                             int src_stride,
+                             ptrdiff_t src_stride,
                              int16_t* coeff);
 #define vpx_hadamard_16x16 vpx_hadamard_16x16_neon
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         int16_t* coeff);
 void vpx_hadamard_8x8_neon(const int16_t* src_diff,
-                           int src_stride,
+                           ptrdiff_t src_stride,
                            int16_t* coeff);
 #define vpx_hadamard_8x8 vpx_hadamard_8x8_neon
 
diff --git a/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h
index 52c3d2c..3baa8752 100644
--- a/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h
@@ -701,18 +701,18 @@
 #define vpx_h_predictor_8x8 vpx_h_predictor_8x8_neon
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           int16_t* coeff);
 void vpx_hadamard_16x16_neon(const int16_t* src_diff,
-                             int src_stride,
+                             ptrdiff_t src_stride,
                              int16_t* coeff);
 #define vpx_hadamard_16x16 vpx_hadamard_16x16_neon
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         int16_t* coeff);
 void vpx_hadamard_8x8_neon(const int16_t* src_diff,
-                           int src_stride,
+                           ptrdiff_t src_stride,
                            int16_t* coeff);
 #define vpx_hadamard_8x8 vpx_hadamard_8x8_neon
 
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h
index c6f4ef0..552d4f2 100644
--- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h
@@ -901,23 +901,23 @@
                                         const uint8_t* left);
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           int16_t* coeff);
 void vpx_hadamard_16x16_neon(const int16_t* src_diff,
-                             int src_stride,
+                             ptrdiff_t src_stride,
                              int16_t* coeff);
 RTCD_EXTERN void (*vpx_hadamard_16x16)(const int16_t* src_diff,
-                                       int src_stride,
+                                       ptrdiff_t src_stride,
                                        int16_t* coeff);
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         int16_t* coeff);
 void vpx_hadamard_8x8_neon(const int16_t* src_diff,
-                           int src_stride,
+                           ptrdiff_t src_stride,
                            int16_t* coeff);
 RTCD_EXTERN void (*vpx_hadamard_8x8)(const int16_t* src_diff,
-                                     int src_stride,
+                                     ptrdiff_t src_stride,
                                      int16_t* coeff);
 
 void vpx_he_predictor_4x4_c(uint8_t* dst,
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h
index 52c3d2c..3baa8752 100644
--- a/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h
@@ -701,18 +701,18 @@
 #define vpx_h_predictor_8x8 vpx_h_predictor_8x8_neon
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           int16_t* coeff);
 void vpx_hadamard_16x16_neon(const int16_t* src_diff,
-                             int src_stride,
+                             ptrdiff_t src_stride,
                              int16_t* coeff);
 #define vpx_hadamard_16x16 vpx_hadamard_16x16_neon
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         int16_t* coeff);
 void vpx_hadamard_8x8_neon(const int16_t* src_diff,
-                           int src_stride,
+                           ptrdiff_t src_stride,
                            int16_t* coeff);
 #define vpx_hadamard_8x8 vpx_hadamard_8x8_neon
 
diff --git a/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h
index 8afa3b7..ddd31b1b 100644
--- a/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h
@@ -466,12 +466,12 @@
 #define vpx_h_predictor_8x8 vpx_h_predictor_8x8_c
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           int16_t* coeff);
 #define vpx_hadamard_16x16 vpx_hadamard_16x16_c
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         int16_t* coeff);
 #define vpx_hadamard_8x8 vpx_hadamard_8x8_c
 
diff --git a/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h
index 52c3d2c..3baa8752 100644
--- a/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h
@@ -701,18 +701,18 @@
 #define vpx_h_predictor_8x8 vpx_h_predictor_8x8_neon
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           int16_t* coeff);
 void vpx_hadamard_16x16_neon(const int16_t* src_diff,
-                             int src_stride,
+                             ptrdiff_t src_stride,
                              int16_t* coeff);
 #define vpx_hadamard_16x16 vpx_hadamard_16x16_neon
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         int16_t* coeff);
 void vpx_hadamard_8x8_neon(const int16_t* src_diff,
-                           int src_stride,
+                           ptrdiff_t src_stride,
                            int16_t* coeff);
 #define vpx_hadamard_8x8 vpx_hadamard_8x8_neon
 
diff --git a/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h
index 3f20ed8..474ce64 100644
--- a/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h
@@ -466,12 +466,12 @@
 #define vpx_h_predictor_8x8 vpx_h_predictor_8x8_c
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           tran_low_t* coeff);
 #define vpx_hadamard_16x16 vpx_hadamard_16x16_c
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         tran_low_t* coeff);
 #define vpx_hadamard_8x8 vpx_hadamard_8x8_c
 
diff --git a/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
index 0835030..61fd83d 100644
--- a/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
@@ -1089,23 +1089,26 @@
                                         const uint8_t* left);
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           tran_low_t* coeff);
 void vpx_hadamard_16x16_sse2(const int16_t* src_diff,
-                             int src_stride,
+                             ptrdiff_t src_stride,
+                             tran_low_t* coeff);
+void vpx_hadamard_16x16_avx2(const int16_t* src_diff,
+                             ptrdiff_t src_stride,
                              tran_low_t* coeff);
 RTCD_EXTERN void (*vpx_hadamard_16x16)(const int16_t* src_diff,
-                                       int src_stride,
+                                       ptrdiff_t src_stride,
                                        tran_low_t* coeff);
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         tran_low_t* coeff);
 void vpx_hadamard_8x8_sse2(const int16_t* src_diff,
-                           int src_stride,
+                           ptrdiff_t src_stride,
                            tran_low_t* coeff);
 RTCD_EXTERN void (*vpx_hadamard_8x8)(const int16_t* src_diff,
-                                     int src_stride,
+                                     ptrdiff_t src_stride,
                                      tran_low_t* coeff);
 
 void vpx_he_predictor_4x4_c(uint8_t* dst,
@@ -9012,6 +9015,8 @@
   vpx_hadamard_16x16 = vpx_hadamard_16x16_c;
   if (flags & HAS_SSE2)
     vpx_hadamard_16x16 = vpx_hadamard_16x16_sse2;
+  if (flags & HAS_AVX2)
+    vpx_hadamard_16x16 = vpx_hadamard_16x16_avx2;
   vpx_hadamard_8x8 = vpx_hadamard_8x8_c;
   if (flags & HAS_SSE2)
     vpx_hadamard_8x8 = vpx_hadamard_8x8_sse2;
diff --git a/third_party/libvpx/source/config/linux/mips64el/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/mips64el/vpx_dsp_rtcd.h
index a08da50..d628eab 100644
--- a/third_party/libvpx/source/config/linux/mips64el/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/mips64el/vpx_dsp_rtcd.h
@@ -466,12 +466,12 @@
 #define vpx_h_predictor_8x8 vpx_h_predictor_8x8_c
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           int16_t* coeff);
 #define vpx_hadamard_16x16 vpx_hadamard_16x16_c
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         int16_t* coeff);
 #define vpx_hadamard_8x8 vpx_hadamard_8x8_c
 
diff --git a/third_party/libvpx/source/config/linux/mipsel/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/mipsel/vpx_dsp_rtcd.h
index a08da50..d628eab 100644
--- a/third_party/libvpx/source/config/linux/mipsel/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/mipsel/vpx_dsp_rtcd.h
@@ -466,12 +466,12 @@
 #define vpx_h_predictor_8x8 vpx_h_predictor_8x8_c
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           int16_t* coeff);
 #define vpx_hadamard_16x16 vpx_hadamard_16x16_c
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         int16_t* coeff);
 #define vpx_hadamard_8x8 vpx_hadamard_8x8_c
 
diff --git a/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
index 6e8baa8..f84e7cef 100644
--- a/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
@@ -972,24 +972,29 @@
 #define vpx_h_predictor_8x8 vpx_h_predictor_8x8_sse2
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           tran_low_t* coeff);
 void vpx_hadamard_16x16_sse2(const int16_t* src_diff,
-                             int src_stride,
+                             ptrdiff_t src_stride,
                              tran_low_t* coeff);
-#define vpx_hadamard_16x16 vpx_hadamard_16x16_sse2
+void vpx_hadamard_16x16_avx2(const int16_t* src_diff,
+                             ptrdiff_t src_stride,
+                             tran_low_t* coeff);
+RTCD_EXTERN void (*vpx_hadamard_16x16)(const int16_t* src_diff,
+                                       ptrdiff_t src_stride,
+                                       tran_low_t* coeff);
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         tran_low_t* coeff);
 void vpx_hadamard_8x8_sse2(const int16_t* src_diff,
-                           int src_stride,
+                           ptrdiff_t src_stride,
                            tran_low_t* coeff);
 void vpx_hadamard_8x8_ssse3(const int16_t* src_diff,
-                            int src_stride,
+                            ptrdiff_t src_stride,
                             tran_low_t* coeff);
 RTCD_EXTERN void (*vpx_hadamard_8x8)(const int16_t* src_diff,
-                                     int src_stride,
+                                     ptrdiff_t src_stride,
                                      tran_low_t* coeff);
 
 void vpx_he_predictor_4x4_c(uint8_t* dst,
@@ -7604,6 +7609,9 @@
   vpx_get16x16var = vpx_get16x16var_sse2;
   if (flags & HAS_AVX2)
     vpx_get16x16var = vpx_get16x16var_avx2;
+  vpx_hadamard_16x16 = vpx_hadamard_16x16_sse2;
+  if (flags & HAS_AVX2)
+    vpx_hadamard_16x16 = vpx_hadamard_16x16_avx2;
   vpx_hadamard_8x8 = vpx_hadamard_8x8_sse2;
   if (flags & HAS_SSSE3)
     vpx_hadamard_8x8 = vpx_hadamard_8x8_ssse3;
diff --git a/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
index 0835030..61fd83d 100644
--- a/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
@@ -1089,23 +1089,26 @@
                                         const uint8_t* left);
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           tran_low_t* coeff);
 void vpx_hadamard_16x16_sse2(const int16_t* src_diff,
-                             int src_stride,
+                             ptrdiff_t src_stride,
+                             tran_low_t* coeff);
+void vpx_hadamard_16x16_avx2(const int16_t* src_diff,
+                             ptrdiff_t src_stride,
                              tran_low_t* coeff);
 RTCD_EXTERN void (*vpx_hadamard_16x16)(const int16_t* src_diff,
-                                       int src_stride,
+                                       ptrdiff_t src_stride,
                                        tran_low_t* coeff);
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         tran_low_t* coeff);
 void vpx_hadamard_8x8_sse2(const int16_t* src_diff,
-                           int src_stride,
+                           ptrdiff_t src_stride,
                            tran_low_t* coeff);
 RTCD_EXTERN void (*vpx_hadamard_8x8)(const int16_t* src_diff,
-                                     int src_stride,
+                                     ptrdiff_t src_stride,
                                      tran_low_t* coeff);
 
 void vpx_he_predictor_4x4_c(uint8_t* dst,
@@ -9012,6 +9015,8 @@
   vpx_hadamard_16x16 = vpx_hadamard_16x16_c;
   if (flags & HAS_SSE2)
     vpx_hadamard_16x16 = vpx_hadamard_16x16_sse2;
+  if (flags & HAS_AVX2)
+    vpx_hadamard_16x16 = vpx_hadamard_16x16_avx2;
   vpx_hadamard_8x8 = vpx_hadamard_8x8_c;
   if (flags & HAS_SSE2)
     vpx_hadamard_8x8 = vpx_hadamard_8x8_sse2;
diff --git a/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
index 6e8baa8..f84e7cef 100644
--- a/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
@@ -972,24 +972,29 @@
 #define vpx_h_predictor_8x8 vpx_h_predictor_8x8_sse2
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           tran_low_t* coeff);
 void vpx_hadamard_16x16_sse2(const int16_t* src_diff,
-                             int src_stride,
+                             ptrdiff_t src_stride,
                              tran_low_t* coeff);
-#define vpx_hadamard_16x16 vpx_hadamard_16x16_sse2
+void vpx_hadamard_16x16_avx2(const int16_t* src_diff,
+                             ptrdiff_t src_stride,
+                             tran_low_t* coeff);
+RTCD_EXTERN void (*vpx_hadamard_16x16)(const int16_t* src_diff,
+                                       ptrdiff_t src_stride,
+                                       tran_low_t* coeff);
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         tran_low_t* coeff);
 void vpx_hadamard_8x8_sse2(const int16_t* src_diff,
-                           int src_stride,
+                           ptrdiff_t src_stride,
                            tran_low_t* coeff);
 void vpx_hadamard_8x8_ssse3(const int16_t* src_diff,
-                            int src_stride,
+                            ptrdiff_t src_stride,
                             tran_low_t* coeff);
 RTCD_EXTERN void (*vpx_hadamard_8x8)(const int16_t* src_diff,
-                                     int src_stride,
+                                     ptrdiff_t src_stride,
                                      tran_low_t* coeff);
 
 void vpx_he_predictor_4x4_c(uint8_t* dst,
@@ -7604,6 +7609,9 @@
   vpx_get16x16var = vpx_get16x16var_sse2;
   if (flags & HAS_AVX2)
     vpx_get16x16var = vpx_get16x16var_avx2;
+  vpx_hadamard_16x16 = vpx_hadamard_16x16_sse2;
+  if (flags & HAS_AVX2)
+    vpx_hadamard_16x16 = vpx_hadamard_16x16_avx2;
   vpx_hadamard_8x8 = vpx_hadamard_8x8_sse2;
   if (flags & HAS_SSSE3)
     vpx_hadamard_8x8 = vpx_hadamard_8x8_ssse3;
diff --git a/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h
index 3f20ed8..474ce64 100644
--- a/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h
@@ -466,12 +466,12 @@
 #define vpx_h_predictor_8x8 vpx_h_predictor_8x8_c
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           tran_low_t* coeff);
 #define vpx_hadamard_16x16 vpx_hadamard_16x16_c
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         tran_low_t* coeff);
 #define vpx_hadamard_8x8 vpx_hadamard_8x8_c
 
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h
index 5fb3a16c..acde048 100644
--- a/third_party/libvpx/source/config/vpx_version.h
+++ b/third_party/libvpx/source/config/vpx_version.h
@@ -1,7 +1,7 @@
 #define VERSION_MAJOR  1
 #define VERSION_MINOR  6
 #define VERSION_PATCH  1
-#define VERSION_EXTRA  "1330-g401e6d48b"
+#define VERSION_EXTRA  "1352-g3ba9a2c8b"
 #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.6.1-1330-g401e6d48b"
-#define VERSION_STRING      " v1.6.1-1330-g401e6d48b"
+#define VERSION_STRING_NOSP "v1.6.1-1352-g3ba9a2c8b"
+#define VERSION_STRING      " v1.6.1-1352-g3ba9a2c8b"
diff --git a/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
index 0835030..61fd83d 100644
--- a/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
@@ -1089,23 +1089,26 @@
                                         const uint8_t* left);
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           tran_low_t* coeff);
 void vpx_hadamard_16x16_sse2(const int16_t* src_diff,
-                             int src_stride,
+                             ptrdiff_t src_stride,
+                             tran_low_t* coeff);
+void vpx_hadamard_16x16_avx2(const int16_t* src_diff,
+                             ptrdiff_t src_stride,
                              tran_low_t* coeff);
 RTCD_EXTERN void (*vpx_hadamard_16x16)(const int16_t* src_diff,
-                                       int src_stride,
+                                       ptrdiff_t src_stride,
                                        tran_low_t* coeff);
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         tran_low_t* coeff);
 void vpx_hadamard_8x8_sse2(const int16_t* src_diff,
-                           int src_stride,
+                           ptrdiff_t src_stride,
                            tran_low_t* coeff);
 RTCD_EXTERN void (*vpx_hadamard_8x8)(const int16_t* src_diff,
-                                     int src_stride,
+                                     ptrdiff_t src_stride,
                                      tran_low_t* coeff);
 
 void vpx_he_predictor_4x4_c(uint8_t* dst,
@@ -9012,6 +9015,8 @@
   vpx_hadamard_16x16 = vpx_hadamard_16x16_c;
   if (flags & HAS_SSE2)
     vpx_hadamard_16x16 = vpx_hadamard_16x16_sse2;
+  if (flags & HAS_AVX2)
+    vpx_hadamard_16x16 = vpx_hadamard_16x16_avx2;
   vpx_hadamard_8x8 = vpx_hadamard_8x8_c;
   if (flags & HAS_SSE2)
     vpx_hadamard_8x8 = vpx_hadamard_8x8_sse2;
diff --git a/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
index 6e8baa8..f84e7cef 100644
--- a/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
@@ -972,24 +972,29 @@
 #define vpx_h_predictor_8x8 vpx_h_predictor_8x8_sse2
 
 void vpx_hadamard_16x16_c(const int16_t* src_diff,
-                          int src_stride,
+                          ptrdiff_t src_stride,
                           tran_low_t* coeff);
 void vpx_hadamard_16x16_sse2(const int16_t* src_diff,
-                             int src_stride,
+                             ptrdiff_t src_stride,
                              tran_low_t* coeff);
-#define vpx_hadamard_16x16 vpx_hadamard_16x16_sse2
+void vpx_hadamard_16x16_avx2(const int16_t* src_diff,
+                             ptrdiff_t src_stride,
+                             tran_low_t* coeff);
+RTCD_EXTERN void (*vpx_hadamard_16x16)(const int16_t* src_diff,
+                                       ptrdiff_t src_stride,
+                                       tran_low_t* coeff);
 
 void vpx_hadamard_8x8_c(const int16_t* src_diff,
-                        int src_stride,
+                        ptrdiff_t src_stride,
                         tran_low_t* coeff);
 void vpx_hadamard_8x8_sse2(const int16_t* src_diff,
-                           int src_stride,
+                           ptrdiff_t src_stride,
                            tran_low_t* coeff);
 void vpx_hadamard_8x8_ssse3(const int16_t* src_diff,
-                            int src_stride,
+                            ptrdiff_t src_stride,
                             tran_low_t* coeff);
 RTCD_EXTERN void (*vpx_hadamard_8x8)(const int16_t* src_diff,
-                                     int src_stride,
+                                     ptrdiff_t src_stride,
                                      tran_low_t* coeff);
 
 void vpx_he_predictor_4x4_c(uint8_t* dst,
@@ -7604,6 +7609,9 @@
   vpx_get16x16var = vpx_get16x16var_sse2;
   if (flags & HAS_AVX2)
     vpx_get16x16var = vpx_get16x16var_avx2;
+  vpx_hadamard_16x16 = vpx_hadamard_16x16_sse2;
+  if (flags & HAS_AVX2)
+    vpx_hadamard_16x16 = vpx_hadamard_16x16_avx2;
   vpx_hadamard_8x8 = vpx_hadamard_8x8_sse2;
   if (flags & HAS_SSSE3)
     vpx_hadamard_8x8 = vpx_hadamard_8x8_ssse3;
diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py
index 0068fb7..d0106cef 100644
--- a/tools/binary_size/libsupersize/archive.py
+++ b/tools/binary_size/libsupersize/archive.py
@@ -388,7 +388,10 @@
   logging.debug('Created %d string literal symbols', sum(len(x) for x in ret))
   logging.debug('Sorting string literals')
   for symbols in ret:
-    symbols.sort(key=lambda x: (x.address, -x.size))
+    # In order to achieve a total ordering in the presense of aliases, need to
+    # include both |address| and |object_path|.
+    # In order to achieve consistent deduping, need to include |size|.
+    symbols.sort(key=lambda x: (x.address, -x.size, x.object_path))
 
   logging.debug('Deduping string literals')
   num_removed = 0
diff --git a/tools/binary_size/libsupersize/integration_test.py b/tools/binary_size/libsupersize/integration_test.py
index 7ecdf44..b427c10 100755
--- a/tools/binary_size/libsupersize/integration_test.py
+++ b/tools/binary_size/libsupersize/integration_test.py
@@ -113,19 +113,25 @@
               output_directory)
     return copy.deepcopy(IntegrationTest.cached_size_info[i])
 
+  def _DoArchive(self, archive_path, use_output_directory=True, use_elf=True,
+                 debug_measures=False):
+    args = [archive_path, '--map-file', _TEST_MAP_PATH]
+    if use_output_directory:
+      # Let autodetection find output_directory when --elf-file is used.
+      if not use_elf:
+        args += ['--output-directory', _TEST_OUTPUT_DIR]
+    else:
+      args += ['--no-source-paths']
+    if use_elf:
+      args += ['--elf-file', _TEST_ELF_PATH]
+    _RunApp('archive', args, debug_measures=debug_measures)
+
   def _DoArchiveTest(self, use_output_directory=True, use_elf=True,
                      debug_measures=False):
     with tempfile.NamedTemporaryFile(suffix='.size') as temp_file:
-      args = [temp_file.name, '--map-file', _TEST_MAP_PATH]
-      if use_output_directory:
-        # Let autodetection find output_directory when --elf-file is used.
-        if not use_elf:
-          args += ['--output-directory', _TEST_OUTPUT_DIR]
-      else:
-        args += ['--no-source-paths']
-      if use_elf:
-        args += ['--elf-file', _TEST_ELF_PATH]
-      _RunApp('archive', args, debug_measures=debug_measures)
+      self._DoArchive(
+          temp_file.name, use_output_directory=use_output_directory,
+          use_elf=use_elf, debug_measures=debug_measures)
       size_info = archive.LoadAndPostProcessSizeInfo(temp_file.name)
     # Check that saving & loading is the same as directly parsing the .map.
     expected_size_info = self._CloneSizeInfo(
@@ -200,6 +206,16 @@
       file_format.SaveSizeInfo(self._CloneSizeInfo(), temp_file.name)
       return _RunApp('diff', [temp_file.name, temp_file.name])
 
+  # Runs archive 3 times, and asserts the contents are the same each time.
+  def test_Idempotent(self):
+    prev_contents = None
+    for _ in xrange(3):
+      with tempfile.NamedTemporaryFile(suffix='.size') as temp_file:
+        self._DoArchive(temp_file.name)
+        contents = temp_file.read()
+        self.assertTrue(prev_contents is None or contents == prev_contents)
+        prev_contents = contents
+
   @_CompareWithGolden()
   def test_Diff_Basic(self):
     size_info1 = self._CloneSizeInfo(use_elf=False)
diff --git a/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_readelf.py b/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_readelf.py
index 23ac20a..1e1f006 100644
--- a/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_readelf.py
+++ b/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_readelf.py
@@ -150,10 +150,7 @@
 Section Headers:
   [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
   [ 0]                   NULL            00000000 000000 000000 00      0   0  0
-
-Section Headers:
-  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
-  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
+  [ 1] .rodata.str1.1    PROGBITS        00000000 000015 000005 01 AMS  0   0  1
 Key to Flags:
   W (write), A (alloc), X (execute), M (merge), S (strings)
   I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
@@ -165,10 +162,6 @@
 Section Headers:
   [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
   [ 0]                   NULL            00000000 000000 000000 00      0   0  0
-
-Section Headers:
-  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
-  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
 Key to Flags:
   W (write), A (alloc), X (execute), M (merge), S (strings)
   I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
@@ -183,10 +176,6 @@
 Section Headers:
   [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
   [ 0]                   NULL            00000000 000000 000000 00      0   0  0
-
-Section Headers:
-  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
-  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
 Key to Flags:
   W (write), A (alloc), X (execute), M (merge), S (strings)
   I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
@@ -199,10 +188,6 @@
 Section Headers:
   [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
   [ 0]                   NULL            00000000 000000 000000 00      0   0  0
-
-Section Headers:
-  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
-  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
 Key to Flags:
   W (write), A (alloc), X (execute), M (merge), S (strings)
   I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py
index fb3c866..af0456c 100755
--- a/tools/clang/scripts/package.py
+++ b/tools/clang/scripts/package.py
@@ -93,9 +93,7 @@
 
 
 def MaybeUpload(args, archive_name, platform):
-  # We don't want to rewrite the file, if it already exists on the server,
-  # so -n option to gsutil is used. It will warn, if the upload was aborted.
-  gsutil_args = ['cp', '-n', '-a', 'public-read',
+  gsutil_args = ['cp', '-a', 'public-read',
                   '%s.tgz' % archive_name,
                   'gs://chromium-browser-clang-staging/%s/%s.tgz' %
                  (platform, archive_name)]
@@ -183,13 +181,6 @@
   else:
     platform = 'Linux_x64'
 
-  # Check if Google Cloud Storage already has the artifacts we want to build.
-  if args.upload and GsutilArchiveExists(pdir, platform):
-    print ('Desired toolchain revision %s is already available '
-           'in Google Cloud Storage:') % expected_stamp
-    print 'gs://chromium-browser-clang-staging/%s/%s.tgz' % (platform, pdir)
-    return 0
-
   with open('buildlog.txt', 'w') as log:
     Tee('Diff in llvm:\n', log)
     TeeCmd(['svn', 'stat', LLVM_DIR], log, fail_hard=False)
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index df9722b..ee18e1e 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -539,7 +539,6 @@
       'android_clang_dbg_recipe': 'android_clang_asan_errorprone_findbugs_debug_trybot',
       'android_compile_dbg': 'android_debug_trybot',
       'android_compile_mips_dbg': 'android_debug_trybot_mipsel',
-      'android_compile_rel': 'android_release_trybot',
       'android_compile_x64_dbg': 'android_debug_trybot_x64',
       'android_compile_x86_dbg': 'android_debug_trybot_x86',
       'android_coverage': 'android_debug_trybot_java_coverage',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 320c3e7..5ff09a1 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -91633,6 +91633,17 @@
   </summary>
 </histogram>
 
+<histogram name="WebApk.Update.NumStaleUpdateRequestFiles" units="files">
+  <owner>hanxi@chromium.org</owner>
+  <owner>pkotwicz@chromium.org</owner>
+  <owner>yfriedman@chromium.org</owner>
+  <summary>
+    Records the number of zombie &quot;WebAPK update request&quot; files that
+    the update process failed to cleanup. Recorded for all WebAPKs whenever a
+    WebAPK or webapp is launched.
+  </summary>
+</histogram>
+
 <histogram name="WebApk.Update.RequestQueued" enum="WebApkUpdateRequestQueued">
   <owner>hanxi@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc
index dc7f1c6..71296ec 100644
--- a/ui/keyboard/keyboard_controller.cc
+++ b/ui/keyboard/keyboard_controller.cc
@@ -166,47 +166,30 @@
 
 // Observer for both keyboard show and hide animations. It should be owned by
 // KeyboardController.
-class CallbackAnimationObserver : public ui::LayerAnimationObserver {
+class CallbackAnimationObserver : public ui::ImplicitAnimationObserver {
  public:
-  CallbackAnimationObserver(const scoped_refptr<ui::LayerAnimator>& animator,
-                            base::OnceCallback<void(void)> callback);
-  ~CallbackAnimationObserver() override;
+  CallbackAnimationObserver(base::OnceClosure callback)
+      : callback_(std::move(callback)) {}
 
  private:
-  // Overridden from ui::LayerAnimationObserver:
-  void OnLayerAnimationEnded(ui::LayerAnimationSequence* seq) override;
-  void OnLayerAnimationAborted(ui::LayerAnimationSequence* seq) override;
-  void OnLayerAnimationScheduled(ui::LayerAnimationSequence* seq) override {}
+  // ui::ImplicitAnimationObserver:
+  void OnImplicitAnimationsCompleted() override {
+    if (WasAnimationAbortedForProperty(ui::LayerAnimationElement::TRANSFORM) ||
+        WasAnimationAbortedForProperty(ui::LayerAnimationElement::OPACITY)) {
+      return;
+    }
+    DCHECK(
+        WasAnimationCompletedForProperty(ui::LayerAnimationElement::TRANSFORM));
+    DCHECK(
+        WasAnimationCompletedForProperty(ui::LayerAnimationElement::OPACITY));
+    std::move(callback_).Run();
+  }
 
-  scoped_refptr<ui::LayerAnimator> animator_;
-  base::OnceCallback<void(void)> callback_;
+  base::OnceClosure callback_;
 
   DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver);
 };
 
-CallbackAnimationObserver::CallbackAnimationObserver(
-    const scoped_refptr<ui::LayerAnimator>& animator,
-    base::OnceCallback<void(void)> callback)
-    : animator_(animator), callback_(std::move(callback)) {}
-
-CallbackAnimationObserver::~CallbackAnimationObserver() {
-  animator_->RemoveObserver(this);
-}
-
-void CallbackAnimationObserver::OnLayerAnimationEnded(
-    ui::LayerAnimationSequence* seq) {
-  if (animator_->is_animating())
-    return;
-  animator_->RemoveObserver(this);
-  DCHECK(!callback_.is_null());
-  std::move(callback_).Run();
-}
-
-void CallbackAnimationObserver::OnLayerAnimationAborted(
-    ui::LayerAnimationSequence* seq) {
-  animator_->RemoveObserver(this);
-}
-
 // static
 KeyboardController* KeyboardController::instance_ = NULL;
 
@@ -367,13 +350,12 @@
 
       set_keyboard_locked(false);
 
-      ui::LayerAnimator* container_animator =
-          container_->layer()->GetAnimator();
-      animation_observer_.reset(new CallbackAnimationObserver(
-          container_animator,
+      animation_observer_ = std::make_unique<CallbackAnimationObserver>(
           base::BindOnce(&KeyboardController::HideAnimationFinished,
-                         base::Unretained(this))));
-      container_animator->AddObserver(animation_observer_.get());
+                         base::Unretained(this)));
+      ui::ScopedLayerAnimationSettings layer_animation_settings(
+          container_->layer()->GetAnimator());
+      layer_animation_settings.AddObserver(animation_observer_.get());
 
       aura::Window* window = container_.get();
 
@@ -625,15 +607,12 @@
   container_animator->set_preemption_strategy(
       ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
 
-  animation_observer_.reset(new CallbackAnimationObserver(
-      container_animator,
-      base::BindOnce(&KeyboardController::ShowAnimationFinished,
-                     base::Unretained(this))));
-  container_animator->AddObserver(animation_observer_.get());
-
   ui_->ShowKeyboardContainer(container_.get());
 
+  animation_observer_ = std::make_unique<CallbackAnimationObserver>(
+      base::BindOnce(&MarkKeyboardLoadFinished));
   ui::ScopedLayerAnimationSettings settings(container_animator);
+  settings.AddObserver(animation_observer_.get());
 
   container_behavior_->DoShowingAnimation(container_.get(), &settings);
 
@@ -647,10 +626,6 @@
   return res;
 }
 
-void KeyboardController::ShowAnimationFinished() {
-  MarkKeyboardLoadFinished();
-}
-
 void KeyboardController::
     NotifyKeyboardBoundsChangingAndEnsureCaretInWorkArea() {
   // Notify observers after animation finished to prevent reveal desktop
diff --git a/ui/keyboard/keyboard_controller.h b/ui/keyboard/keyboard_controller.h
index 9d38a7a26..f873899 100644
--- a/ui/keyboard/keyboard_controller.h
+++ b/ui/keyboard/keyboard_controller.h
@@ -203,9 +203,7 @@
   // Returns true if keyboard is scheduled to hide.
   bool WillHideKeyboard() const;
 
-  // Called when show and hide animation finished successfully. If the animation
-  // is aborted, it won't be called.
-  void ShowAnimationFinished();
+  // Called when the hide animation finishes.
   void HideAnimationFinished();
 
   void NotifyKeyboardBoundsChangingAndEnsureCaretInWorkArea();