diff --git a/BUILD.gn b/BUILD.gn
index e09eaea..86b18a7 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1137,7 +1137,7 @@
 if (closure_compile) {
   group("webui_closure_compile") {
     data_deps = [
-      "chrome/browser/resources/engagement:closure_compile",
+      "chrome/browser/resources:closure_compile",
       "ui/webui/resources:closure_compile",
     ]
   }
diff --git a/DEPS b/DEPS
index 99a8dcc00..445fcfcc 100644
--- a/DEPS
+++ b/DEPS
@@ -82,11 +82,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'c0528e2418e09765807f1db510733c573232f7e2',
+  'skia_revision': '42f8bc40fd3702c801c9f5b9d438fabcc77fb58b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '81094bec9a28e792d5e681fb34599638fbdcfe5a',
+  'v8_revision': '69d8b7f75df24493d549ac6ac3e989263d3d2aef',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -142,7 +142,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '1fcfd9b6d53d5e277666487bc2acb59faf237346',
+  'catapult_revision': 'e13394ffef3618bf55f99845ecf67768601fa388',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -426,7 +426,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '4725eead59243c3f1476745b58efac394df53eef',
+      'url': Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '9c3e7ed65adc533bdff4ec098a34c7bf169a99fe',
       'condition': 'checkout_linux',
   },
 
@@ -436,7 +436,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '668c1d8d1f1a6c26b088b5bff1203e35c74943a0',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'a1df57cdc6573da28eebdcac0d58941f79b176a7',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -670,7 +670,7 @@
     Var('chromium_git') + '/webm/libwebm.git' + '@' + 'b03c65468b06d097f27235d93d76bfc45f490ede',
 
   'src/third_party/libyuv':
-    Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '98a0a157dcf5dee0882b2dfcc9578ab1f44afb12',  # from r1703
+    Var('chromium_git') + '/libyuv/libyuv.git' + '@' + 'a9626b9daf62a9b260737e9c2de821ad087b19a1',  # from r1708
 
   'src/third_party/lighttpd': {
       'url': Var('chromium_git') + '/chromium/deps/lighttpd.git' + '@' + Var('lighttpd_revision'),
diff --git a/android_webview/tools/apk_merger.py b/android_webview/tools/apk_merger.py
index bfb1dad2..0c3c563 100755
--- a/android_webview/tools/apk_merger.py
+++ b/android_webview/tools/apk_merger.py
@@ -166,7 +166,7 @@
 def MergeApk(args, tmp_apk, tmp_dir_32, tmp_dir_64):
   # Expected files to copy from 32- to 64-bit APK together with whether to
   # compress within the .apk.
-  expected_files = {'snapshot_blob_32.bin': False}
+  expected_files = {'snapshot_blob_32.bin': False, 'unwind_cfi_32': False}
   if args.shared_library:
     expected_files[args.shared_library] = not args.uncompress_shared_libraries
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 948252a7..e60b6f1 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -517,6 +517,8 @@
     "system/brightness/unified_brightness_view.cc",
     "system/brightness/unified_brightness_view.h",
     "system/brightness_control_delegate.h",
+    "system/caps_lock_notification_controller.cc",
+    "system/caps_lock_notification_controller.h",
     "system/cast/tray_cast.cc",
     "system/cast/tray_cast.h",
     "system/date/clock_observer.h",
@@ -1561,6 +1563,7 @@
     "system/bluetooth/bluetooth_power_controller_unittest.cc",
     "system/bluetooth/tray_bluetooth_helper_unittest.cc",
     "system/brightness/tray_brightness_unittest.cc",
+    "system/caps_lock_notification_controller_unittest.cc",
     "system/date/date_view_unittest.cc",
     "system/date/system_info_default_view_unittest.cc",
     "system/enterprise/tray_enterprise_unittest.cc",
diff --git a/ash/components/shortcut_viewer/views/ksv_search_box_view.h b/ash/components/shortcut_viewer/views/ksv_search_box_view.h
index 913ac917..a796f6b 100644
--- a/ash/components/shortcut_viewer/views/ksv_search_box_view.h
+++ b/ash/components/shortcut_viewer/views/ksv_search_box_view.h
@@ -33,8 +33,8 @@
 
  private:
   // search_box::SearchBoxViewBase:
-  void ModelChanged() override {}
   void UpdateBackgroundColor(SkColor color) override;
+  void ModelChanged() override {}
   void UpdateKeyboardVisibility() override {}
   void UpdateModel(bool initiated_by_user) override {}
   void UpdateSearchIcon() override {}
diff --git a/ash/shell.cc b/ash/shell.cc
index 5d40a663..0009b18 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -81,6 +81,7 @@
 #include "ash/system/bluetooth/tray_bluetooth_helper.h"
 #include "ash/system/brightness/brightness_controller_chromeos.h"
 #include "ash/system/brightness_control_delegate.h"
+#include "ash/system/caps_lock_notification_controller.h"
 #include "ash/system/keyboard_brightness/keyboard_brightness_controller.h"
 #include "ash/system/keyboard_brightness_control_delegate.h"
 #include "ash/system/locale/locale_notification_controller.h"
@@ -395,7 +396,7 @@
   PaletteWelcomeBubble::RegisterProfilePrefs(registry);
   ShelfController::RegisterProfilePrefs(registry);
   TouchDevicesController::RegisterProfilePrefs(registry, for_test);
-  TrayCapsLock::RegisterProfilePrefs(registry, for_test);
+  CapsLockNotificationController::RegisterProfilePrefs(registry, for_test);
 }
 
 views::NonClientFrameView* Shell::CreateDefaultNonClientFrameView(
@@ -783,6 +784,7 @@
 
   screen_pinning_controller_.reset();
 
+  caps_lock_notification_controller_.reset();
   resolution_notification_controller_.reset();
   screen_security_notification_controller_.reset();
   screenshot_controller_.reset();
@@ -893,6 +895,8 @@
     night_light_controller_ = std::make_unique<NightLightController>();
   touch_devices_controller_ = std::make_unique<TouchDevicesController>();
   bluetooth_power_controller_ = std::make_unique<BluetoothPowerController>();
+  caps_lock_notification_controller_ =
+      std::make_unique<CapsLockNotificationController>();
   detachable_base_handler_ = std::make_unique<DetachableBaseHandler>(this);
   detachable_base_notification_controller_ =
       std::make_unique<DetachableBaseNotificationController>(
diff --git a/ash/shell.h b/ash/shell.h
index bdf1ab9..52b14ac 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -89,6 +89,7 @@
 class BluetoothNotificationController;
 class BluetoothPowerController;
 class BrightnessControlDelegate;
+class CapsLockNotificationController;
 class CastConfigController;
 class DetachableBaseHandler;
 class DetachableBaseNotificationController;
@@ -668,6 +669,8 @@
   std::unique_ptr<AshDisplayController> ash_display_controller_;
   std::unique_ptr<BacklightsForcedOffSetter> backlights_forced_off_setter_;
   std::unique_ptr<BrightnessControlDelegate> brightness_control_delegate_;
+  std::unique_ptr<CapsLockNotificationController>
+      caps_lock_notification_controller_;
   std::unique_ptr<CastConfigController> cast_config_;
   std::unique_ptr<DetachableBaseHandler> detachable_base_handler_;
   std::unique_ptr<DetachableBaseNotificationController>
diff --git a/ash/system/caps_lock_notification_controller.cc b/ash/system/caps_lock_notification_controller.cc
new file mode 100644
index 0000000..257d840
--- /dev/null
+++ b/ash/system/caps_lock_notification_controller.cc
@@ -0,0 +1,114 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/caps_lock_notification_controller.h"
+
+#include "ash/accessibility/accessibility_controller.h"
+#include "ash/public/cpp/ash_features.h"
+#include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/session/session_controller.h"
+#include "ash/shell.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/chromeos/events/modifier_key.h"
+#include "ui/chromeos/events/pref_names.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/public/cpp/notification.h"
+
+using message_center::MessageCenter;
+using message_center::Notification;
+
+namespace ash {
+
+namespace {
+
+const char kCapsLockNotificationId[] = "capslock";
+const char kNotifierCapsLock[] = "ash.caps-lock";
+
+std::unique_ptr<Notification> CreateNotification() {
+  const int string_id =
+      CapsLockNotificationController::IsSearchKeyMappedToCapsLock()
+          ? IDS_ASH_STATUS_TRAY_CAPS_LOCK_CANCEL_BY_SEARCH
+          : IDS_ASH_STATUS_TRAY_CAPS_LOCK_CANCEL_BY_ALT_SEARCH;
+  std::unique_ptr<Notification> notification =
+      Notification::CreateSystemNotification(
+          message_center::NOTIFICATION_TYPE_SIMPLE, kCapsLockNotificationId,
+          l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAPS_LOCK_ENABLED),
+          l10n_util::GetStringUTF16(string_id), gfx::Image(),
+          base::string16() /* display_source */, GURL(),
+          message_center::NotifierId(
+              message_center::NotifierId::SYSTEM_COMPONENT, kNotifierCapsLock),
+          message_center::RichNotificationData(), nullptr,
+          kNotificationCapslockIcon,
+          message_center::SystemNotificationWarningLevel::NORMAL);
+  if (features::IsSystemTrayUnifiedEnabled())
+    notification->set_pinned(true);
+  return notification;
+}
+
+}  // namespace
+
+CapsLockNotificationController::CapsLockNotificationController() {
+  Shell::Get()->ime_controller()->AddObserver(this);
+}
+
+CapsLockNotificationController::~CapsLockNotificationController() {
+  Shell::Get()->ime_controller()->RemoveObserver(this);
+}
+
+// static
+bool CapsLockNotificationController::IsSearchKeyMappedToCapsLock() {
+  PrefService* prefs =
+      Shell::Get()->session_controller()->GetLastActiveUserPrefService();
+  // Null early in mash startup.
+  if (!prefs)
+    return false;
+
+  // Don't bother to observe for the pref changing because the system tray
+  // menu is rebuilt every time it is opened and the user has to close the
+  // menu to open settings to change the pref. It's not worth the complexity
+  // to worry about sync changing the pref while the menu or notification is
+  // visible.
+  return prefs->GetInteger(prefs::kLanguageRemapSearchKeyTo) ==
+         static_cast<int>(ui::chromeos::ModifierKey::kCapsLockKey);
+}
+
+// static
+void CapsLockNotificationController::RegisterProfilePrefs(
+    PrefRegistrySimple* registry,
+    bool for_test) {
+  if (for_test) {
+    // There is no remote pref service, so pretend that ash owns the pref.
+    registry->RegisterIntegerPref(
+        prefs::kLanguageRemapSearchKeyTo,
+        static_cast<int>(ui::chromeos::ModifierKey::kSearchKey));
+    return;
+  }
+  // Pref is owned by chrome and flagged as PUBLIC.
+  registry->RegisterForeignPref(prefs::kLanguageRemapSearchKeyTo);
+}
+
+void CapsLockNotificationController::OnCapsLockChanged(bool enabled) {
+  // Send an a11y alert.
+  Shell::Get()->accessibility_controller()->TriggerAccessibilityAlert(
+      enabled ? mojom::AccessibilityAlert::CAPS_ON
+              : mojom::AccessibilityAlert::CAPS_OFF);
+
+  if (enabled) {
+    if (!notification_shown_ || features::IsSystemTrayUnifiedEnabled()) {
+      Shell::Get()->metrics()->RecordUserMetricsAction(
+          UMA_STATUS_AREA_CAPS_LOCK_POPUP);
+
+      MessageCenter::Get()->AddNotification(CreateNotification());
+      notification_shown_ = true;
+    }
+  } else if (MessageCenter::Get()->FindVisibleNotificationById(
+                 kCapsLockNotificationId)) {
+    MessageCenter::Get()->RemoveNotification(kCapsLockNotificationId, false);
+  }
+}
+
+}  // namespace ash
diff --git a/ash/system/caps_lock_notification_controller.h b/ash/system/caps_lock_notification_controller.h
new file mode 100644
index 0000000..9286e5d
--- /dev/null
+++ b/ash/system/caps_lock_notification_controller.h
@@ -0,0 +1,39 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_SYSTEM_CAPS_LOCK_NOTIFICATION_CONTROLLER_H_
+#define ASH_SYSTEM_CAPS_LOCK_NOTIFICATION_CONTROLLER_H_
+
+#include "ash/ime/ime_controller.h"
+#include "base/macros.h"
+
+class PrefRegistrySimple;
+
+namespace ash {
+
+// Controller class to manage caps lock notification.
+class ASH_EXPORT CapsLockNotificationController
+    : public ImeController::Observer {
+ public:
+  CapsLockNotificationController();
+  virtual ~CapsLockNotificationController();
+
+  static bool IsSearchKeyMappedToCapsLock();
+
+  // See Shell::RegisterProfilePrefs().
+  static void RegisterProfilePrefs(PrefRegistrySimple* registry, bool for_test);
+
+  // ImeController::Observer:
+  void OnCapsLockChanged(bool enabled) override;
+  void OnKeyboardLayoutNameChanged(const std::string&) override {}
+
+ private:
+  bool notification_shown_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(CapsLockNotificationController);
+};
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_CAPS_LOCK_NOTIFICATION_CONTROLLER_H_
diff --git a/ash/system/caps_lock_notification_controller_unittest.cc b/ash/system/caps_lock_notification_controller_unittest.cc
new file mode 100644
index 0000000..b873a64
--- /dev/null
+++ b/ash/system/caps_lock_notification_controller_unittest.cc
@@ -0,0 +1,54 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/caps_lock_notification_controller.h"
+
+#include "ash/accessibility/accessibility_controller.h"
+#include "ash/accessibility/test_accessibility_controller_client.h"
+#include "ash/shell.h"
+#include "ash/system/web_notification/web_notification_tray.h"
+#include "ash/test/ash_test_base.h"
+
+namespace ash {
+
+class CapsLockNotificationControllerTest : public AshTestBase {
+ public:
+  CapsLockNotificationControllerTest() = default;
+  ~CapsLockNotificationControllerTest() override = default;
+
+  void SetUp() override {
+    AshTestBase::SetUp();
+    WebNotificationTray::DisableAnimationsForTest(true);
+  }
+
+  void TearDown() override {
+    WebNotificationTray::DisableAnimationsForTest(false);
+    AshTestBase::TearDown();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CapsLockNotificationControllerTest);
+};
+
+// Tests that a11y alert is sent on toggling caps lock.
+TEST_F(CapsLockNotificationControllerTest, A11yAlert) {
+  auto caps_lock = std::make_unique<CapsLockNotificationController>();
+
+  TestAccessibilityControllerClient client;
+  AccessibilityController* controller =
+      Shell::Get()->accessibility_controller();
+  controller->SetClient(client.CreateInterfacePtrAndBind());
+
+  // Simulate turning on caps lock.
+  caps_lock->OnCapsLockChanged(true);
+  controller->FlushMojoForTest();
+  EXPECT_EQ(mojom::AccessibilityAlert::CAPS_ON, client.last_a11y_alert());
+
+  // Simulate turning off caps lock.
+  caps_lock->OnCapsLockChanged(false);
+  controller->FlushMojoForTest();
+  EXPECT_EQ(mojom::AccessibilityAlert::CAPS_OFF, client.last_a11y_alert());
+}
+
+}  // namespace ash
diff --git a/ash/system/tray_caps_lock.cc b/ash/system/tray_caps_lock.cc
index 27af730..124b674458 100644
--- a/ash/system/tray_caps_lock.cc
+++ b/ash/system/tray_caps_lock.cc
@@ -9,29 +9,23 @@
 #include "ash/accessibility/accessibility_controller.h"
 #include "ash/ime/ime_controller.h"
 #include "ash/metrics/user_metrics_recorder.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/config.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
+#include "ash/system/caps_lock_notification_controller.h"
 #include "ash/system/tray/actionable_view.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_item_style.h"
 #include "ash/system/tray/tray_popup_utils.h"
 #include "ash/system/tray/tri_view.h"
 #include "base/sys_info.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "ui/chromeos/events/modifier_key.h"
-#include "ui/chromeos/events/pref_names.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/paint_vector_icon.h"
-#include "ui/message_center/message_center.h"
-#include "ui/message_center/public/cpp/notification.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
@@ -39,58 +33,16 @@
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/widget/widget.h"
 
-using message_center::Notification;
-
 namespace ash {
 namespace {
 
 // Padding used to position the caption in the caps lock default view row.
 const int kCaptionRightPadding = 6;
 
-const char kCapsLockNotificationId[] = "capslock";
-const char kNotifierCapsLock[] = "ash.caps-lock";
-
 bool IsCapsLockEnabled() {
   return Shell::Get()->ime_controller()->IsCapsLockEnabled();
 }
 
-bool IsSearchKeyMappedToCapsLock() {
-  PrefService* prefs =
-      Shell::Get()->session_controller()->GetLastActiveUserPrefService();
-  // Null early in mash startup.
-  if (!prefs)
-    return false;
-
-  // Don't bother to observe for the pref changing because the system tray
-  // menu is rebuilt every time it is opened and the user has to close the
-  // menu to open settings to change the pref. It's not worth the complexity
-  // to worry about sync changing the pref while the menu or notification is
-  // visible.
-  return prefs->GetInteger(prefs::kLanguageRemapSearchKeyTo) ==
-         static_cast<int>(ui::chromeos::ModifierKey::kCapsLockKey);
-}
-
-std::unique_ptr<Notification> CreateNotification() {
-  const int string_id =
-      IsSearchKeyMappedToCapsLock()
-          ? IDS_ASH_STATUS_TRAY_CAPS_LOCK_CANCEL_BY_SEARCH
-          : IDS_ASH_STATUS_TRAY_CAPS_LOCK_CANCEL_BY_ALT_SEARCH;
-  std::unique_ptr<Notification> notification =
-      Notification::CreateSystemNotification(
-          message_center::NOTIFICATION_TYPE_SIMPLE, kCapsLockNotificationId,
-          l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAPS_LOCK_ENABLED),
-          l10n_util::GetStringUTF16(string_id), gfx::Image(),
-          base::string16() /* display_source */, GURL(),
-          message_center::NotifierId(
-              message_center::NotifierId::SYSTEM_COMPONENT, kNotifierCapsLock),
-          message_center::RichNotificationData(), nullptr,
-          kNotificationCapslockIcon,
-          message_center::SystemNotificationWarningLevel::NORMAL);
-  if (features::IsSystemTrayUnifiedEnabled())
-    notification->set_pinned(true);
-  return notification;
-}
-
 }  // namespace
 
 class CapsLockDefaultView : public ActionableView {
@@ -137,7 +89,8 @@
     text_label_->SetText(l10n_util::GetStringUTF16(text_string_id));
 
     int shortcut_string_id = 0;
-    const bool search_mapped_to_caps_lock = IsSearchKeyMappedToCapsLock();
+    const bool search_mapped_to_caps_lock =
+        CapsLockNotificationController::IsSearchKeyMappedToCapsLock();
     if (caps_lock_enabled) {
       shortcut_string_id =
           search_mapped_to_caps_lock
@@ -182,8 +135,7 @@
 TrayCapsLock::TrayCapsLock(SystemTray* system_tray)
     : TrayImageItem(system_tray, kSystemTrayCapsLockIcon, UMA_CAPS_LOCK),
       default_(nullptr),
-      caps_lock_enabled_(IsCapsLockEnabled()),
-      message_shown_(false) {
+      caps_lock_enabled_(IsCapsLockEnabled()) {
   Shell::Get()->ime_controller()->AddObserver(this);
 }
 
@@ -191,49 +143,14 @@
   Shell::Get()->ime_controller()->RemoveObserver(this);
 }
 
-// static
-void TrayCapsLock::RegisterProfilePrefs(PrefRegistrySimple* registry,
-                                        bool for_test) {
-  if (for_test) {
-    // There is no remote pref service, so pretend that ash owns the pref.
-    registry->RegisterIntegerPref(
-        prefs::kLanguageRemapSearchKeyTo,
-        static_cast<int>(ui::chromeos::ModifierKey::kSearchKey));
-    return;
-  }
-  // Pref is owned by chrome and flagged as PUBLIC.
-  registry->RegisterForeignPref(prefs::kLanguageRemapSearchKeyTo);
-}
-
 void TrayCapsLock::OnCapsLockChanged(bool enabled) {
   caps_lock_enabled_ = enabled;
 
-  // Send an a11y alert.
-  Shell::Get()->accessibility_controller()->TriggerAccessibilityAlert(
-      enabled ? mojom::AccessibilityAlert::CAPS_ON
-              : mojom::AccessibilityAlert::CAPS_OFF);
-
   if (tray_view())
     tray_view()->SetVisible(caps_lock_enabled_);
 
-  if (default_) {
+  if (default_)
     default_->Update(caps_lock_enabled_);
-  } else {
-    message_center::MessageCenter* message_center =
-        message_center::MessageCenter::Get();
-    if (caps_lock_enabled_) {
-      if (!message_shown_) {
-        Shell::Get()->metrics()->RecordUserMetricsAction(
-            UMA_STATUS_AREA_CAPS_LOCK_POPUP);
-
-        message_center->AddNotification(CreateNotification());
-        message_shown_ = true;
-      }
-    } else if (message_center->FindVisibleNotificationById(
-                   kCapsLockNotificationId)) {
-      message_center->RemoveNotification(kCapsLockNotificationId, false);
-    }
-  }
 }
 
 bool TrayCapsLock::GetInitialVisibility() {
diff --git a/ash/system/tray_caps_lock.h b/ash/system/tray_caps_lock.h
index 088747e..cf1bc7d 100644
--- a/ash/system/tray_caps_lock.h
+++ b/ash/system/tray_caps_lock.h
@@ -9,8 +9,6 @@
 #include "ash/system/tray/tray_image_item.h"
 #include "base/macros.h"
 
-class PrefRegistrySimple;
-
 namespace views {
 class View;
 }
@@ -24,9 +22,6 @@
   explicit TrayCapsLock(SystemTray* system_tray);
   ~TrayCapsLock() override;
 
-  // See Shell::RegisterProfilePrefs().
-  static void RegisterProfilePrefs(PrefRegistrySimple* registry, bool for_test);
-
   // Overridden from ImeController::Observer:
   void OnCapsLockChanged(bool enabled) override;
   void OnKeyboardLayoutNameChanged(const std::string&) override {}
@@ -40,7 +35,6 @@
   CapsLockDefaultView* default_;
 
   bool caps_lock_enabled_;
-  bool message_shown_;
 
   DISALLOW_COPY_AND_ASSIGN(TrayCapsLock);
 };
diff --git a/ash/system/tray_caps_lock_unittest.cc b/ash/system/tray_caps_lock_unittest.cc
index f7fee5b..6a04ccd 100644
--- a/ash/system/tray_caps_lock_unittest.cc
+++ b/ash/system/tray_caps_lock_unittest.cc
@@ -4,9 +4,6 @@
 
 #include "ash/system/tray_caps_lock.h"
 
-#include "ash/accessibility/accessibility_controller.h"
-#include "ash/accessibility/test_accessibility_controller_client.h"
-#include "ash/shell.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_test_api.h"
 #include "ash/system/web_notification/web_notification_tray.h"
@@ -50,25 +47,4 @@
   EXPECT_FALSE(caps_lock->tray_view()->visible());
 }
 
-// Tests that a11y alert is sent on toggling caps lock.
-TEST_F(TrayCapsLockTest, A11yAlert) {
-  SystemTray* tray = GetPrimarySystemTray();
-  TrayCapsLock* caps_lock = SystemTrayTestApi(tray).tray_caps_lock();
-
-  TestAccessibilityControllerClient client;
-  AccessibilityController* controller =
-      Shell::Get()->accessibility_controller();
-  controller->SetClient(client.CreateInterfacePtrAndBind());
-
-  // Simulate turning on caps lock.
-  caps_lock->OnCapsLockChanged(true);
-  controller->FlushMojoForTest();
-  EXPECT_EQ(mojom::AccessibilityAlert::CAPS_ON, client.last_a11y_alert());
-
-  // Simulate turning off caps lock.
-  caps_lock->OnCapsLockChanged(false);
-  controller->FlushMojoForTest();
-  EXPECT_EQ(mojom::AccessibilityAlert::CAPS_OFF, client.last_a11y_alert());
-}
-
 }  // namespace ash
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc
index 0e259259e..a12f67f 100644
--- a/ash/wm/overview/overview_window_drag_controller.cc
+++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -90,6 +90,7 @@
       SnapWindow(snap_position_);
     }
   }
+  item_ = nullptr;
 }
 
 void OverviewWindowDragController::ActivateDraggedWindow() {
@@ -117,6 +118,9 @@
   window_selector_->PositionWindows(/*animate=*/true);
   window_selector_->SetSplitViewDragIndicatorsIndicatorState(
       IndicatorState::kNone, gfx::Point());
+  // This function gets called on long press, which bypasses CompleteDrag but
+  // stops dragging as well, so reset |item_|.
+  item_ = nullptr;
 }
 
 void OverviewWindowDragController::ResetWindowSelector() {
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index b69198f..69614d41 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -963,31 +963,52 @@
 
 void WindowSelectorItem::HandlePressEvent(
     const gfx::Point& location_in_screen) {
+  // We allow switching finger while dragging, but do not allow dragging two or more items.
+  if (window_selector_->window_drag_controller() &&
+      window_selector_->window_drag_controller()->item()) {
+    return;
+  }
+
   StartDrag();
   window_selector_->InitiateDrag(this, location_in_screen);
 }
 
 void WindowSelectorItem::HandleReleaseEvent(
     const gfx::Point& location_in_screen) {
+  if (!IsDragItem())
+    return;
+
   EndDrag();
   window_selector_->CompleteDrag(this, location_in_screen);
 }
 
 void WindowSelectorItem::HandleDragEvent(const gfx::Point& location_in_screen) {
+  if (!IsDragItem())
+    return;
+
   window_selector_->Drag(this, location_in_screen);
 }
 
 void WindowSelectorItem::ActivateDraggedWindow() {
-  DCHECK_EQ(this, window_selector_->window_drag_controller()->item());
+  if (!IsDragItem())
+    return;
+
   window_selector_->ActivateDraggedWindow();
 }
 
 void WindowSelectorItem::ResetDraggedWindowGesture() {
   OnSelectorItemDragEnded();
-  DCHECK_EQ(this, window_selector_->window_drag_controller()->item());
+  if (!IsDragItem())
+    return;
+
   window_selector_->ResetDraggedWindowGesture();
 }
 
+bool WindowSelectorItem::IsDragItem() {
+  return window_selector_->window_drag_controller() &&
+         window_selector_->window_drag_controller()->item() == this;
+}
+
 void WindowSelectorItem::SetShadowBounds(
     base::Optional<gfx::Rect> bounds_in_screen) {
   if (!IsNewOverviewUi())
diff --git a/ash/wm/overview/window_selector_item.h b/ash/wm/overview/window_selector_item.h
index 9ce65d7..50e2462 100644
--- a/ash/wm/overview/window_selector_item.h
+++ b/ash/wm/overview/window_selector_item.h
@@ -185,6 +185,9 @@
   void ActivateDraggedWindow();
   void ResetDraggedWindowGesture();
 
+  // Checks if this item is current being dragged.
+  bool IsDragItem();
+
   // Sets the bounds of the window shadow. If |bounds_in_screen| is nullopt,
   // the shadow is hidden.
   void SetShadowBounds(base::Optional<gfx::Rect> bounds_in_screen);
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 06ad709..8ade514 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -2907,6 +2907,61 @@
   ToggleOverview();
 }
 
+// Verify that attempting to drag with a secondary finger works as expected.
+TEST_F(WindowSelectorTest, DraggingWithTwoFingers) {
+  std::unique_ptr<aura::Window> window1 = CreateTestWindow();
+  std::unique_ptr<aura::Window> window2 = CreateTestWindow();
+
+  // Dragging is only allowed in tablet mode.
+  RunAllPendingInMessageLoop();
+  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  RunAllPendingInMessageLoop();
+
+  ToggleOverview();
+  RunAllPendingInMessageLoop();
+  WindowSelectorItem* item1 = GetWindowItemForWindow(0, window1.get());
+  WindowSelectorItem* item2 = GetWindowItemForWindow(0, window2.get());
+
+  const gfx::Rect original_bounds1 = item1->target_bounds();
+  const gfx::Rect original_bounds2 = item2->target_bounds();
+
+  constexpr int kTouchId1 = 1;
+  constexpr int kTouchId2 = 2;
+
+  // Verify that the bounds of the tapped window expand when touched.
+  ui::test::EventGenerator& generator = GetEventGenerator();
+  generator.set_current_location(original_bounds1.CenterPoint());
+  generator.PressTouchId(kTouchId1);
+  EXPECT_GT(item1->target_bounds().width(), original_bounds1.width());
+  EXPECT_GT(item1->target_bounds().height(), original_bounds1.height());
+
+  // Verify that attempting to touch the second window with a second finger does
+  // nothing to the second window. The first window remains the window to be
+  // dragged.
+  generator.set_current_location(original_bounds2.CenterPoint());
+  generator.PressTouchId(kTouchId2);
+  EXPECT_GT(item1->target_bounds().width(), original_bounds1.width());
+  EXPECT_GT(item1->target_bounds().height(), original_bounds1.height());
+  EXPECT_EQ(item2->target_bounds(), original_bounds2);
+
+  // Verify the first window moves on drag.
+  gfx::Point last_center_point = item1->target_bounds().CenterPoint();
+  generator.MoveTouchIdBy(kTouchId1, 40, 40);
+  EXPECT_NE(last_center_point, item1->target_bounds().CenterPoint());
+  EXPECT_EQ(original_bounds2.CenterPoint(),
+            item2->target_bounds().CenterPoint());
+
+  // Verify the first window moves on drag, even if we switch to a second
+  // finger.
+  last_center_point = item1->target_bounds().CenterPoint();
+  generator.ReleaseTouchId(kTouchId2);
+  generator.PressTouchId(kTouchId2);
+  generator.MoveTouchIdBy(kTouchId2, 40, 40);
+  EXPECT_NE(last_center_point, item1->target_bounds().CenterPoint());
+  EXPECT_EQ(original_bounds2.CenterPoint(),
+            item2->target_bounds().CenterPoint());
+}
+
 class SplitViewWindowSelectorTest : public WindowSelectorTest {
  public:
   SplitViewWindowSelectorTest() = default;
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 686f25d8..d61370b 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1808,6 +1808,7 @@
     "ENABLE_PROFILING=$enable_profiling",
     "CAN_UNWIND_WITH_FRAME_POINTERS=$can_unwind_with_frame_pointers",
     "UNSAFE_DEVELOPER_BUILD=$is_unsafe_developer_build",
+    "CAN_UNWIND_WITH_CFI_TABLE=$can_unwind_with_cfi_table",
   ]
 }
 
diff --git a/base/metrics/persistent_histogram_storage.cc b/base/metrics/persistent_histogram_storage.cc
index cbacca8..20922888 100644
--- a/base/metrics/persistent_histogram_storage.cc
+++ b/base/metrics/persistent_histogram_storage.cc
@@ -39,6 +39,9 @@
   PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
   allocator->UpdateTrackingHistograms();
 
+  if (disabled_)
+    return;
+
   // Stop if the storage base directory has not been properly set.
   if (storage_base_dir_.empty()) {
     LOG(ERROR)
@@ -50,22 +53,28 @@
 
   FilePath storage_dir = storage_base_dir_.AppendASCII(allocator->Name());
 
-  if (storage_dir_create_action_ == StorageDirCreation::kEnable) {
-    // Stop if |storage_dir| does not exist and cannot be created after an
-    // attempt.
-    if (!CreateDirectory(storage_dir)) {
-      LOG(ERROR) << "Could not write \"" << allocator->Name()
-                 << "\" persistent histograms to file as the storage directory "
-                    "cannot be created.";
-      return;
-    }
-  } else if (!DirectoryExists(storage_dir)) {
-    // Stop if |storage_dir| does not exist. That can happen if the product
-    // hasn't been installed yet or if it has been uninstalled.
-    // TODO(chengx): Investigate if there is a need to update setup_main.cc or
-    // test_installer.py so that a LOG(ERROR) statement can be added here
-    // without breaking the test.
-    return;
+  switch (storage_dir_create_action_) {
+    case StorageDirCreation::kEnable:
+      if (!CreateDirectory(storage_dir)) {
+        LOG(ERROR)
+            << "Could not write \"" << allocator->Name()
+            << "\" persistent histograms to file as the storage directory "
+               "cannot be created.";
+        return;
+      }
+      break;
+    case StorageDirCreation::kDisable:
+      if (!DirectoryExists(storage_dir)) {
+        // When the consumer of this class disables storage directory creation
+        // by the class instance, it should ensure the directory's existence if
+        // it's essential.
+        LOG(ERROR)
+            << "Could not write \"" << allocator->Name()
+            << "\" persistent histograms to file as the storage directory "
+               "does not exist.";
+        return;
+      }
+      break;
   }
 
   // Save data using the current time as the filename. The actual filename
diff --git a/base/metrics/persistent_histogram_storage.h b/base/metrics/persistent_histogram_storage.h
index f5883b7..e101a2605 100644
--- a/base/metrics/persistent_histogram_storage.h
+++ b/base/metrics/persistent_histogram_storage.h
@@ -31,7 +31,8 @@
   // well as the leaf directory name for the file to which the histograms are
   // persisted. The string must be ASCII.
   // |storage_dir_create_action| determines that if this instance is
-  // responsible for creating the storage directory.
+  // responsible for creating the storage directory. If kDisable is supplied,
+  // it's the consumer's responsibility to create the storage directory.
   PersistentHistogramStorage(StringPiece allocator_name,
                              StorageDirCreation storage_dir_create_action);
 
@@ -44,6 +45,9 @@
     storage_base_dir_ = storage_base_dir;
   }
 
+  // Disables histogram storage.
+  void Disable() { disabled_ = true; }
+
  private:
   // Metrics files are written into directory
   // |storage_base_dir_|/|allocator_name| (see the ctor for allocator_name).
@@ -53,6 +57,11 @@
   // storage directory.
   const StorageDirCreation storage_dir_create_action_;
 
+  // A flag indicating if histogram storage is disabled. It starts with false,
+  // but can be set to true by the caller who decides to throw away its
+  // histogram data.
+  bool disabled_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(PersistentHistogramStorage);
 };
 
diff --git a/base/threading/thread_local_storage.cc b/base/threading/thread_local_storage.cc
index de5fd26..265f505 100644
--- a/base/threading/thread_local_storage.cc
+++ b/base/threading/thread_local_storage.cc
@@ -69,6 +69,45 @@
 base::subtle::Atomic32 g_native_tls_key =
     PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES;
 
+// The OS TLS slot has three states:
+//   * kUninitialized: Any call to Slot::Get()/Set() will create the base
+//     per-thread TLS state. On POSIX, kUninitialized must be 0.
+//   * [Memory Address]: Raw pointer to the base per-thread TLS state.
+//   * kDestroyed: The base per-thread TLS state has been freed.
+//
+// Final States:
+//   * Windows: kDestroyed. Windows does not iterate through the OS TLS to clean
+//     up the values.
+//   * POSIX: kUninitialized. POSIX iterates through TLS until all slots contain
+//     nullptr.
+//
+// More details on this design:
+//   We need some type of thread-local state to indicate that the TLS system has
+//   been destroyed. To do so, we leverage the multi-pass nature of destruction
+//   of pthread_key.
+//
+//    a) After destruction of TLS system, we set the pthread_key to a sentinel
+//       kDestroyed.
+//    b) All calls to Slot::Get() DCHECK that the state is not kDestroyed, and
+//       any system which might potentially invoke Slot::Get() after destruction
+//       of TLS must check ThreadLOcalStorage::ThreadIsBeingDestroyed().
+//    c) After a full pass of the pthread_keys, on the next invocation of
+//       ConstructTlsVector(), we'll then set the key to nullptr.
+//    d) At this stage, the TLS system is back in its uninitialized state.
+//    e) If in the second pass of destruction of pthread_keys something were to
+//       re-initialize TLS [this should never happen! Since the only code which
+//       uses Chrome TLS is Chrome controlled, we should really be striving for
+//       single-pass destruction], then TLS will be re-initialized and then go
+//       through the 2-pass destruction system again. Everything should just
+//       work (TM).
+
+// The consumers of kUninitialized and kDestroyed expect void*, since that's
+// what the API exposes on both POSIX and Windows.
+void* const kUninitialized = nullptr;
+
+// A sentinel value to indicate that the TLS system has been destroyed.
+void* const kDestroyed = reinterpret_cast<void*>(-3);
+
 // The maximum number of slots in our thread local storage stack.
 constexpr int kThreadLocalStorageSize = 256;
 
@@ -139,7 +178,7 @@
       key = base::subtle::NoBarrier_Load(&g_native_tls_key);
     }
   }
-  CHECK(!PlatformThreadLocalStorage::GetTLSValue(key));
+  CHECK_EQ(PlatformThreadLocalStorage::GetTLSValue(key), kUninitialized);
 
   // Some allocators, such as TCMalloc, make use of thread local storage. As a
   // result, any attempt to call new (or malloc) will lazily cause such a system
@@ -162,6 +201,16 @@
 }
 
 void OnThreadExitInternal(TlsVectorEntry* tls_data) {
+  // This branch is for POSIX, where this function is called twice. The first
+  // pass calls dtors and sets state to kDestroyed. The second pass sets
+  // kDestroyed to kUninitialized.
+  if (tls_data == kDestroyed) {
+    PlatformThreadLocalStorage::TLSKey key =
+        base::subtle::NoBarrier_Load(&g_native_tls_key);
+    PlatformThreadLocalStorage::SetTLSValue(key, kUninitialized);
+    return;
+  }
+
   DCHECK(tls_data);
   // Some allocators, such as TCMalloc, use TLS. As a result, when a thread
   // terminates, one of the destructor calls we make may be to shut down an
@@ -221,7 +270,7 @@
   }
 
   // Remove our stack allocated vector.
-  PlatformThreadLocalStorage::SetTLSValue(key, nullptr);
+  PlatformThreadLocalStorage::SetTLSValue(key, kDestroyed);
 }
 
 }  // namespace
@@ -237,8 +286,13 @@
   if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES)
     return;
   void *tls_data = GetTLSValue(key);
+
+  // On Windows, thread destruction callbacks are only invoked once per module,
+  // so there should be no way that this could be invoked twice.
+  DCHECK_NE(tls_data, kDestroyed);
+
   // Maybe we have never initialized TLS for this thread.
-  if (!tls_data)
+  if (tls_data == kUninitialized)
     return;
   OnThreadExitInternal(static_cast<TlsVectorEntry*>(tls_data));
 }
@@ -250,11 +304,19 @@
 
 }  // namespace internal
 
+bool ThreadLocalStorage::HasBeenDestroyed() {
+  PlatformThreadLocalStorage::TLSKey key =
+      base::subtle::NoBarrier_Load(&g_native_tls_key);
+  if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES)
+    return false;
+  return PlatformThreadLocalStorage::GetTLSValue(key) == kDestroyed;
+}
+
 void ThreadLocalStorage::Slot::Initialize(TLSDestructorFunc destructor) {
   PlatformThreadLocalStorage::TLSKey key =
       base::subtle::NoBarrier_Load(&g_native_tls_key);
   if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES ||
-      !PlatformThreadLocalStorage::GetTLSValue(key)) {
+      PlatformThreadLocalStorage::GetTLSValue(key) == kUninitialized) {
     ConstructTlsVector();
   }
 
@@ -300,6 +362,7 @@
   TlsVectorEntry* tls_data = static_cast<TlsVectorEntry*>(
       PlatformThreadLocalStorage::GetTLSValue(
           base::subtle::NoBarrier_Load(&g_native_tls_key)));
+  DCHECK_NE(tls_data, kDestroyed);
   if (!tls_data)
     tls_data = ConstructTlsVector();
   DCHECK_NE(slot_, kInvalidSlotValue);
@@ -314,6 +377,7 @@
   TlsVectorEntry* tls_data = static_cast<TlsVectorEntry*>(
       PlatformThreadLocalStorage::GetTLSValue(
           base::subtle::NoBarrier_Load(&g_native_tls_key)));
+  DCHECK_NE(tls_data, kDestroyed);
   if (!tls_data)
     tls_data = ConstructTlsVector();
   DCHECK_NE(slot_, kInvalidSlotValue);
diff --git a/base/threading/thread_local_storage.h b/base/threading/thread_local_storage.h
index 4f2b7f18..df6eb065 100644
--- a/base/threading/thread_local_storage.h
+++ b/base/threading/thread_local_storage.h
@@ -18,10 +18,20 @@
 #include <pthread.h>
 #endif
 
+namespace profiling {
+class MemlogAllocatorShimInternal;
+}  // namespace profiling
+
 namespace base {
 
+namespace trace_event {
+class MallocDumpProvider;
+}  // namespace trace_event
+
 namespace internal {
 
+class ThreadLocalStorageTestInternal;
+
 // WARNING: You should *NOT* use this class directly.
 // PlatformThreadLocalStorage is a low-level abstraction of the OS's TLS
 // interface. Instead, you should use one of the following:
@@ -90,7 +100,6 @@
 // an API for portability.
 class BASE_EXPORT ThreadLocalStorage {
  public:
-
   // Prototype for the TLS destructor function, which can be optionally used to
   // cleanup thread local storage on thread exit.  'value' is the data that is
   // stored in thread local storage.
@@ -134,6 +143,19 @@
   };
 
  private:
+  // In most cases, most callers should not need access to HasBeenDestroyed().
+  // If you are working in code that runs during thread destruction, contact the
+  // base OWNERs for advice and then make a friend request.
+  //
+  // Returns |true| if Chrome's implementation of TLS has been destroyed during
+  // thread destruction. Attempting to call Slot::Get() during destruction is
+  // disallowed and will hit a DCHECK. Any code that relies on TLS during thread
+  // destruction must first check this method before calling Slot::Get().
+  friend class base::internal::ThreadLocalStorageTestInternal;
+  friend class base::trace_event::MallocDumpProvider;
+  friend class profiling::MemlogAllocatorShimInternal;
+  static bool HasBeenDestroyed();
+
   DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorage);
 };
 
diff --git a/base/threading/thread_local_storage_unittest.cc b/base/threading/thread_local_storage_unittest.cc
index 02794b4..3c5a30c 100644
--- a/base/threading/thread_local_storage_unittest.cc
+++ b/base/threading/thread_local_storage_unittest.cc
@@ -23,6 +23,22 @@
 
 namespace base {
 
+#if defined(OS_POSIX)
+
+namespace internal {
+
+// This class is friended by ThreadLocalStorage.
+class ThreadLocalStorageTestInternal {
+ public:
+  static bool HasBeenDestroyed() {
+    return ThreadLocalStorage::HasBeenDestroyed();
+  }
+};
+
+}  // namespace internal
+
+#endif
+
 namespace {
 
 const int kInitialTlsValue = 0x5555;
@@ -80,6 +96,97 @@
   TLSSlot().Set(value);
 }
 
+#if defined(OS_POSIX)
+constexpr intptr_t kDummyValue = 0xABCD;
+constexpr size_t kKeyCount = 20;
+
+// The order in which pthread keys are destructed is non-deterministic.
+// Hopefully, of the 20 keys we create, some of them should be destroyed
+class UseTLSDuringDestructionThread : public SimpleThread {
+ public:
+  UseTLSDuringDestructionThread() : SimpleThread("prefix") {}
+
+  // The order in which pthread_key destructors are called is not well defined.
+  // Hopefully, by creating 10 both before and after initializing TLS on the
+  // thread, at least 1 will be called after TLS destruction.
+  void Run() override {
+    ASSERT_FALSE(internal::ThreadLocalStorageTestInternal::HasBeenDestroyed());
+
+    // Create 10 pthread keys before initializing TLS on the thread.
+    size_t slot_index = 0;
+    for (; slot_index < 10; ++slot_index) {
+      CreateTlsKeyWithDestructor(slot_index);
+    }
+
+    // Initialize the Chrome TLS system. It's possible that base::Thread has
+    // already initialized Chrome TLS, but we don't rely on that.
+    slot_.Set(reinterpret_cast<void*>(kDummyValue));
+
+    // Create 10 pthread keys after initializing TLS on the thread.
+    for (; slot_index < kKeyCount; ++slot_index) {
+      CreateTlsKeyWithDestructor(slot_index);
+    }
+  }
+
+  bool teardown_works_correctly() { return teardown_works_correctly_; }
+
+ private:
+  struct TLSState {
+    pthread_key_t key;
+    bool* teardown_works_correctly;
+  };
+
+  // The POSIX TLS destruction API takes as input a single C-function, which is
+  // called with the current |value| of a (key, value) pair. We need this
+  // function to do two things: set the |value| to nullptr, which requires
+  // knowing the associated |key|, and update the |teardown_works_correctly_|
+  // state.
+  //
+  // To accomplish this, we set the value to an instance of TLSState, which
+  // contains |key| as well as a pointer to |teardown_works_correctly|.
+  static void ThreadLocalDestructor(void* value) {
+    TLSState* state = static_cast<TLSState*>(value);
+    int result = pthread_setspecific(state->key, nullptr);
+    ASSERT_EQ(result, 0);
+
+    // If this path is hit, then the thread local destructor was called after
+    // the Chrome-TLS destructor and the internal state was updated correctly.
+    // No further checks are necessary.
+    if (internal::ThreadLocalStorageTestInternal::HasBeenDestroyed()) {
+      *(state->teardown_works_correctly) = true;
+      return;
+    }
+
+    // If this path is hit, then the thread local destructor was called before
+    // the Chrome-TLS destructor is hit. The ThreadLocalStorage::Slot should
+    // still function correctly.
+    ASSERT_EQ(reinterpret_cast<intptr_t>(slot_.Get()), kDummyValue);
+  }
+
+  void CreateTlsKeyWithDestructor(size_t index) {
+    ASSERT_LT(index, kKeyCount);
+
+    tls_states_[index].teardown_works_correctly = &teardown_works_correctly_;
+    int result = pthread_key_create(
+        &(tls_states_[index].key),
+        UseTLSDuringDestructionThread::ThreadLocalDestructor);
+    ASSERT_EQ(result, 0);
+
+    result = pthread_setspecific(tls_states_[index].key, &tls_states_[index]);
+    ASSERT_EQ(result, 0);
+  }
+
+  static base::ThreadLocalStorage::Slot slot_;
+  bool teardown_works_correctly_ = false;
+  TLSState tls_states_[kKeyCount];
+
+  DISALLOW_COPY_AND_ASSIGN(UseTLSDuringDestructionThread);
+};
+
+base::ThreadLocalStorage::Slot UseTLSDuringDestructionThread::slot_;
+
+#endif  // defined(OS_POSIX)
+
 }  // namespace
 
 TEST(ThreadLocalStorageTest, Basics) {
@@ -142,4 +249,17 @@
   }
 }
 
+#if defined(OS_POSIX)
+// Unlike POSIX, Windows does not iterate through the OS TLS to cleanup any
+// values there. Instead a per-module thread destruction function is called.
+// However, it is not possible to perform a check after this point (as the code
+// is detached from the thread), so this check remains POSIX only.
+TEST(ThreadLocalStorageTest, UseTLSDuringDestruction) {
+  UseTLSDuringDestructionThread thread;
+  thread.Start();
+  thread.Join();
+  EXPECT_TRUE(thread.teardown_works_correctly());
+}
+#endif
+
 }  // namespace base
diff --git a/base/trace_event/cfi_backtrace_android.cc b/base/trace_event/cfi_backtrace_android.cc
index 04faf13361..54ed5fd 100644
--- a/base/trace_event/cfi_backtrace_android.cc
+++ b/base/trace_event/cfi_backtrace_android.cc
@@ -137,7 +137,7 @@
   executable_start_addr_ = reinterpret_cast<uintptr_t>(&__executable_start);
 
   // This file name is defined by extract_unwind_tables.gni.
-  static constexpr char kCfiFileName[] = "assets/unwind_cfi";
+  static constexpr char kCfiFileName[] = "assets/unwind_cfi_32";
   MemoryMappedFile::Region cfi_region;
   int fd = base::android::OpenApkAsset(kCfiFileName, &cfi_region);
   if (fd < 0)
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.cc b/base/trace_event/heap_profiler_allocation_context_tracker.cc
index a375d3b9..eb5f128 100644
--- a/base/trace_event/heap_profiler_allocation_context_tracker.cc
+++ b/base/trace_event/heap_profiler_allocation_context_tracker.cc
@@ -15,6 +15,11 @@
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread_local_storage.h"
 #include "base/trace_event/heap_profiler_allocation_context.h"
+#include "build/build_config.h"
+
+#if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE)
+#include "base/trace_event/cfi_backtrace_android.h"
+#endif
 
 #if defined(OS_LINUX) || defined(OS_ANDROID)
 #include <sys/prctl.h>
@@ -214,20 +219,26 @@
 // kMaxFrameCount + 1 frames, so that we know if there are more frames
 // than our backtrace capacity.
 #if !defined(OS_NACL)  // We don't build base/debug/stack_trace.cc for NaCl.
-#if BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
+#if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE)
+        const void* frames[Backtrace::kMaxFrameCount + 1];
+        static_assert(arraysize(frames) >= Backtrace::kMaxFrameCount,
+                      "not requesting enough frames to fill Backtrace");
+        size_t frame_count = CFIBacktraceAndroid::GetInstance()->Unwind(
+            frames, arraysize(frames));
+#elif BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
         const void* frames[Backtrace::kMaxFrameCount + 1];
         static_assert(arraysize(frames) >= Backtrace::kMaxFrameCount,
                       "not requesting enough frames to fill Backtrace");
         size_t frame_count = debug::TraceStackFramePointers(
             frames, arraysize(frames),
             1 /* exclude this function from the trace */);
-#else   // BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
+#else
         // Fall-back to capturing the stack with base::debug::StackTrace,
         // which is likely slower, but more reliable.
         base::debug::StackTrace stack_trace(Backtrace::kMaxFrameCount + 1);
         size_t frame_count = 0u;
         const void* const* frames = stack_trace.Addresses(&frame_count);
-#endif  // BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
+#endif
 
         // If there are too many frames, keep the ones furthest from main().
         size_t backtrace_capacity = backtrace_end - backtrace;
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc
index 98b2101..7a9fbfcd 100644
--- a/base/trace_event/malloc_dump_provider.cc
+++ b/base/trace_event/malloc_dump_provider.cc
@@ -12,6 +12,7 @@
 #include "base/allocator/allocator_shim.h"
 #include "base/allocator/buildflags.h"
 #include "base/debug/profiler.h"
+#include "base/threading/thread_local_storage.h"
 #include "base/trace_event/heap_profiler_allocation_context.h"
 #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
 #include "base/trace_event/heap_profiler_heap_dump_writer.h"
@@ -333,6 +334,9 @@
 }
 
 void MallocDumpProvider::InsertAllocation(void* address, size_t size) {
+  if (UNLIKELY(base::ThreadLocalStorage::HasBeenDestroyed()))
+    return;
+
   // CurrentId() can be a slow operation (crbug.com/497226). This apparently
   // redundant condition short circuits the CurrentID() calls when unnecessary.
   if (tid_dumping_heap_ != kInvalidThreadId &&
@@ -358,6 +362,9 @@
 }
 
 void MallocDumpProvider::RemoveAllocation(void* address) {
+  if (UNLIKELY(base::ThreadLocalStorage::HasBeenDestroyed()))
+    return;
+
   // No re-entrancy is expected here as none of the calls below should
   // cause a free()-s (|allocation_register_| does its own heap management).
   if (tid_dumping_heap_ != kInvalidThreadId &&
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 71f4ce4..2514536 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -41,8 +41,13 @@
 
 #if defined(OS_ANDROID)
 #include "base/trace_event/java_heap_dump_provider_android.h"
+
+#if BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE)
+#include "base/trace_event/cfi_backtrace_android.h"
 #endif
 
+#endif  // defined(OS_ANDROID)
+
 namespace base {
 namespace trace_event {
 
@@ -273,8 +278,15 @@
       break;
 
     case kHeapProfilingModeNative:
-      // If we don't have frame pointers then native tracing falls-back to
-      // using base::debug::StackTrace, which may be slow.
+#if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE)
+    {
+      bool can_unwind =
+          CFIBacktraceAndroid::GetInstance()->can_unwind_stack_frames();
+      DCHECK(can_unwind);
+    }
+#endif
+      // If we don't have frame pointers and unwind tables then native tracing
+      // falls-back to using base::debug::StackTrace, which may be slow.
       AllocationContextTracker::SetCaptureMode(
           AllocationContextTracker::CaptureMode::NATIVE_STACK);
       break;
diff --git a/build/android/gyp/extract_unwind_tables.py b/build/android/gyp/extract_unwind_tables.py
index 37a8421..b0b119e 100755
--- a/build/android/gyp/extract_unwind_tables.py
+++ b/build/android/gyp/extract_unwind_tables.py
@@ -57,6 +57,9 @@
 Usage:
   extract_unwind_tables.py --input_path [root path to unstripped chrome.so]
       --output_path [output path] --dump_syms_path [path to dump_syms binary]
+  [OR]
+  extract_unwind_tables.py --generate-empty-tables
+      --output_path [output path] --dump_syms_path [path to dump_syms binary]
 """
 
 import argparse
@@ -265,17 +268,28 @@
 def main():
   parser = argparse.ArgumentParser()
   parser.add_argument(
-      '--input_path', required=True,
-      help='The input path of the unstripped binary')
-  parser.add_argument(
       '--output_path', required=True,
       help='The path of the output file')
   parser.add_argument(
       '--dump_syms_path', required=True,
       help='The path of the dump_syms binary')
 
+  group = parser.add_mutually_exclusive_group(required=True)
+  group.add_argument(
+      '--input_path', required=False,
+      help='The input path of the unstripped binary')
+  group.add_argument(
+      '--generate-empty-tables', required=False,
+      help='Generates an empty valid unwind table file.',
+      action="store_true")
+
   args = parser.parse_args()
 
+  if args.generate_empty_tables:
+    with open(args.output_path, 'wb') as out_file:
+      _WriteCfiData({}, out_file)
+    return 0
+
   with tempfile.NamedTemporaryFile() as sym_file:
     out = subprocess.call(
         ['./' +args.dump_syms_path, args.input_path], stdout=sym_file)
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
index 50ced4b..e9b47cb8 100644
--- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -219,8 +219,9 @@
       @trace_event.traced
       def edit_shared_prefs(dev):
         for setting in self._test_instance.edit_shared_prefs:
-          shared_pref = shared_prefs.SharedPrefs(dev, setting['package'],
-                                                 setting['filename'])
+          shared_pref = shared_prefs.SharedPrefs(
+              dev, setting['package'], setting['filename'],
+              use_encrypted_path=setting.get('supports_encrypted_path', False))
           shared_preference_utils.ApplySharedPreferenceSetting(
               shared_pref, setting)
 
diff --git a/build/android/pylib/utils/shared_preference_utils.py b/build/android/pylib/utils/shared_preference_utils.py
index c42163c..ae0d31b 100644
--- a/build/android/pylib/utils/shared_preference_utils.py
+++ b/build/android/pylib/utils/shared_preference_utils.py
@@ -52,6 +52,7 @@
   {
     "package": "com.example.package",
     "filename": "AppSettingsFile.xml",
+    "supports_encrypted_path": true,
     "set": {
       "SomeBoolToSet": true,
       "SomeStringToSet": "StringValue",
diff --git a/build/config/android/extract_unwind_tables.gni b/build/config/android/extract_unwind_tables.gni
index 70f2d331..00e324b 100644
--- a/build/config/android/extract_unwind_tables.gni
+++ b/build/config/android/extract_unwind_tables.gni
@@ -3,10 +3,19 @@
 # found in the LICENSE file.
 
 import("//build/config/android/rules.gni")
+import("//build/config/compiler/compiler.gni")
 
 template("unwind_table_asset") {
   _unwind_action = "${target_name}__extract"
-  _asset_path = "${target_gen_dir}/${target_name}/unwind_cfi"
+
+  # Monochrome 64 bit apk needs to include an empty unwind file with different
+  # name so that the resource table matches when merging monochrome apk.
+  if (can_unwind_with_cfi_table) {
+    assert(current_cpu == "arm")
+    _asset_path = "${target_gen_dir}/${target_name}/unwind_cfi_32"
+  } else {
+    _asset_path = "${target_gen_dir}/${target_name}/unwind_cfi_empty"
+  }
 
   action(_unwind_action) {
     if (defined(invoker.testonly)) {
@@ -17,25 +26,32 @@
     outputs = [
       _asset_path,
     ]
-    inputs = [
-      "$root_out_dir/lib.unstripped/$shlib_prefix${invoker.library_target}$shlib_extension",
-    ]
 
     args = [
-      "--input_path",
-      rebase_path(
-          "$root_out_dir/lib.unstripped/$shlib_prefix${invoker.library_target}$shlib_extension",
-          root_build_dir),
       "--output_path",
       rebase_path(_asset_path, root_build_dir),
       "--dump_syms_path",
       rebase_path("$root_out_dir/dump_syms", root_build_dir),
     ]
-    deps = [
-      ":${invoker.library_target}",
-      "//third_party/breakpad:dump_syms",
-    ]
+
+    if (can_unwind_with_cfi_table) {
+      _input_lib = "$root_out_dir/lib.unstripped/$shlib_prefix${invoker.library_target}$shlib_extension"
+      inputs = [
+        _input_lib,
+      ]
+
+      args += [
+        "--input_path",
+        rebase_path(_input_lib, root_build_dir),
+      ]
+    } else {
+      args += [ "--generate-empty-tables" ]
+    }
+
+    deps = invoker.deps
+    deps += [ "//third_party/breakpad:dump_syms" ]
   }
+
   android_assets(target_name) {
     if (defined(invoker.testonly)) {
       testonly = invoker.testonly
diff --git a/build/toolchain/win/setup_toolchain.py b/build/toolchain/win/setup_toolchain.py
index 00ae570..fce62521 100644
--- a/build/toolchain/win/setup_toolchain.py
+++ b/build/toolchain/win/setup_toolchain.py
@@ -50,7 +50,7 @@
           # path. Add the path to this python here so that if it's not in the
           # path when ninja is run later, python will still be found.
           setting = os.path.dirname(sys.executable) + os.pathsep + setting
-        env[var.upper()] = setting.lower()
+        env[var.upper()] = setting
         break
   if sys.platform in ('win32', 'cygwin'):
     for required in ('SYSTEMROOT', 'TEMP', 'TMP'):
@@ -117,8 +117,10 @@
     # Check that the json file contained the same environment as the .cmd file.
     if sys.platform in ('win32', 'cygwin'):
       script = os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.cmd'))
-      assert _ExtractImportantEnvironment(variables) == \
-             _ExtractImportantEnvironment(_LoadEnvFromBat([script, '/' + cpu]))
+      arg = '/' + cpu
+      json_env = _ExtractImportantEnvironment(variables)
+      cmd_env = _ExtractImportantEnvironment(_LoadEnvFromBat([script, arg]))
+      assert _LowercaseDict(json_env) == _LowercaseDict(cmd_env)
   else:
     if 'GYP_MSVS_OVERRIDE_PATH' not in os.environ:
       os.environ['GYP_MSVS_OVERRIDE_PATH'] = _DetectVisualStudioPath()
@@ -167,6 +169,18 @@
   return block
 
 
+def _LowercaseDict(d):
+  """Returns a copy of `d` with both key and values lowercased.
+
+  Args:
+    d: dict to lowercase (e.g. {'A': 'BcD'}).
+
+  Returns:
+    A dict with both keys and values lowercased (e.g.: {'a': 'bcd'}).
+  """
+  return {k.lower(): d[k].lower() for k in d}
+
+
 def main():
   if len(sys.argv) != 8:
     print('Usage setup_toolchain.py '
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index 57e6f13..6fc3fe81 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -369,7 +369,7 @@
           base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared,
                      base::Unretained(this))),
       signals_check_notifier_(task_runner_,
-                              base::Bind(&TileManager::CheckAndIssueSignals,
+                              base::Bind(&TileManager::FlushAndIssueSignals,
                                          base::Unretained(this))),
       has_scheduled_tile_tasks_(false),
       prepare_tiles_count_(0u),
@@ -497,7 +497,7 @@
 
   // Ensure that we don't schedule any decode work for checkered images until
   // the raster work for visible tiles is complete. This is done in
-  // CheckAndIssueSignals when the ready to activate/draw signals are dispatched
+  // FlushAndIssueSignals when the ready to activate/draw signals are dispatched
   // to the client.
   checker_image_tracker_.SetNoDecodesAllowed();
 
@@ -536,7 +536,7 @@
   tile_task_manager_->CheckForCompletedTasks();
   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
 
-  CheckPendingGpuWorkTiles(true /* issue_signals */);
+  CheckPendingGpuWorkAndIssueSignals();
 
   TRACE_EVENT_INSTANT1(
       "cc", "TileManager::CheckForCompletedTasksFinished",
@@ -1352,21 +1352,23 @@
              RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
 }
 
-void TileManager::CheckAndIssueSignals() {
-  TRACE_EVENT0("cc", "TileManager::CheckAndIssueSignals");
+void TileManager::FlushAndIssueSignals() {
+  TRACE_EVENT0("cc", "TileManager::FlushAndIssueSignals");
   tile_task_manager_->CheckForCompletedTasks();
   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
 
   raster_buffer_provider_->Flush();
-  CheckPendingGpuWorkTiles(false /* issue_signals */);
+  CheckPendingGpuWorkAndIssueSignals();
+}
 
+void TileManager::IssueSignals() {
   // Ready to activate.
   if (signals_.activate_tile_tasks_completed &&
       signals_.activate_gpu_work_completed &&
       !signals_.did_notify_ready_to_activate) {
     if (IsReadyToActivate()) {
       TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
-                   "TileManager::CheckAndIssueSignals - ready to activate");
+                   "TileManager::IssueSignals - ready to activate");
       signals_.did_notify_ready_to_activate = true;
       client_->NotifyReadyToActivate();
     }
@@ -1377,7 +1379,7 @@
       !signals_.did_notify_ready_to_draw) {
     if (IsReadyToDraw()) {
       TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
-                   "TileManager::CheckAndIssueSignals - ready to draw");
+                   "TileManager::IssueSignals - ready to draw");
       signals_.did_notify_ready_to_draw = true;
       client_->NotifyReadyToDraw();
     }
@@ -1387,9 +1389,8 @@
   if (signals_.all_tile_tasks_completed &&
       !signals_.did_notify_all_tile_tasks_completed) {
     if (!has_scheduled_tile_tasks_) {
-      TRACE_EVENT0(
-          TRACE_DISABLED_BY_DEFAULT("cc.debug"),
-          "TileManager::CheckAndIssueSignals - all tile tasks completed");
+      TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+                   "TileManager::IssueSignals - all tile tasks completed");
       signals_.did_notify_all_tile_tasks_completed = true;
       client_->NotifyAllTileTasksCompleted();
     }
@@ -1542,8 +1543,8 @@
          raster_buffer_provider_->CanPartialRasterIntoProvidedResource();
 }
 
-void TileManager::CheckPendingGpuWorkTiles(bool issue_signals) {
-  TRACE_EVENT2("cc", "TileManager::CheckPendingGpuWorkTiles",
+void TileManager::CheckPendingGpuWorkAndIssueSignals() {
+  TRACE_EVENT2("cc", "TileManager::CheckPendingGpuWorkAndIssueSignals",
                "pending_gpu_work_tiles", pending_gpu_work_tiles_.size(),
                "tree_priority",
                TreePriorityToString(global_state_.tree_priority));
@@ -1585,9 +1586,8 @@
     pending_required_for_activation_callback_id_ =
         raster_buffer_provider_->SetReadyToDrawCallback(
             required_for_activation,
-            base::Bind(&TileManager::CheckPendingGpuWorkTiles,
-                       ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr(),
-                       true /* issue_signals */),
+            base::Bind(&TileManager::CheckPendingGpuWorkAndIssueSignals,
+                       ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr()),
             pending_required_for_activation_callback_id_);
   }
 
@@ -1597,9 +1597,8 @@
     pending_required_for_draw_callback_id_ =
         raster_buffer_provider_->SetReadyToDrawCallback(
             required_for_draw,
-            base::Bind(&TileManager::CheckPendingGpuWorkTiles,
-                       ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr(),
-                       true /* issue_signals */),
+            base::Bind(&TileManager::CheckPendingGpuWorkAndIssueSignals,
+                       ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr()),
             pending_required_for_draw_callback_id_);
   }
 
@@ -1612,15 +1611,7 @@
   // We've just updated all pending tile requirements if necessary.
   pending_tile_requirements_dirty_ = false;
 
-  if (!issue_signals)
-    return;
-
-  bool can_activate = signals_.activate_gpu_work_completed &&
-                      signals_.activate_tile_tasks_completed;
-  bool can_draw =
-      signals_.draw_gpu_work_completed && signals_.draw_tile_tasks_completed;
-  if (can_activate || can_draw)
-    signals_check_notifier_.Schedule();
+  IssueSignals();
 }
 
 // Utility function that can be used to create a "Task set finished" task that
diff --git a/cc/tiles/tile_manager.h b/cc/tiles/tile_manager.h
index bb930e6c..32e9a1ea 100644
--- a/cc/tiles/tile_manager.h
+++ b/cc/tiles/tile_manager.h
@@ -358,7 +358,6 @@
   bool TilePriorityViolatesMemoryPolicy(const TilePriority& priority);
   bool AreRequiredTilesReadyToDraw(RasterTilePriorityQueue::Type type) const;
   void CheckIfMoreTilesNeedToBePrepared();
-  void CheckAndIssueSignals();
   void MarkTilesOutOfMemory(
       std::unique_ptr<RasterTilePriorityQueue> queue) const;
 
@@ -391,7 +390,9 @@
 
   bool UsePartialRaster() const;
 
-  void CheckPendingGpuWorkTiles(bool issue_signals);
+  void FlushAndIssueSignals();
+  void CheckPendingGpuWorkAndIssueSignals();
+  void IssueSignals();
 
   TileManagerClient* client_;
   base::SequencedTaskRunner* task_runner_;
@@ -434,7 +435,7 @@
   uint64_t pending_required_for_activation_callback_id_ = 0;
   uint64_t pending_required_for_draw_callback_id_ = 0;
   // If true, we should re-compute tile requirements in
-  // CheckPendingGpuWorkTiles.
+  // CheckPendingGpuWorkAndIssueSignals.
   bool pending_tile_requirements_dirty_ = false;
 
   std::unordered_map<Tile::Id, std::vector<DrawImage>> scheduled_draw_images_;
diff --git a/chrome/VERSION b/chrome/VERSION
index 0ae08691..fba744f 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=67
 MINOR=0
-BUILD=3388
+BUILD=3389
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index da38538a..16728cee 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1092,11 +1092,24 @@
   }
 }
 
+# Unwind tables are added to only official builds (public_apk(s)) so that
+# developer builds are not affected. In monochrome we add the asset file to both
+# 32 and 64 bit versions so that the resources.arsc is same, as workaround for
+# https://crbug.com/828528. The extract script assigns different names for these
+# versions.
+_add_unwind_tables_in_chrome_public_apk =
+    can_unwind_with_cfi_table && is_official_build
+_add_unwind_tables_in_monochrome_public_apk = is_official_build
+
 chrome_public_apk_tmpl_shared("chrome_public_apk") {
   android_manifest = chrome_public_android_manifest
   android_manifest_dep = ":chrome_public_android_manifest"
   apk_name = "ChromePublic"
   shared_libraries = [ ":libchrome" ]
+  add_unwind_tables_in_apk = _add_unwind_tables_in_chrome_public_apk
+  if (_add_unwind_tables_in_chrome_public_apk) {
+    shared_library_for_unwind_asset = "chrome"
+  }
 }
 
 chrome_public_apk_tmpl_shared("chrome_public_apk_for_test") {
@@ -1105,6 +1118,10 @@
   android_manifest_dep = ":chrome_public_android_manifest"
   apk_name = "ChromePublicForTest"
   shared_libraries = [ ":libchromefortest" ]
+  add_unwind_tables_in_apk = _add_unwind_tables_in_chrome_public_apk
+  if (_add_unwind_tables_in_chrome_public_apk) {
+    shared_library_for_unwind_asset = "chromefortest"
+  }
   deps = [
     "//chrome/browser/profiling_host:profiling_host_java_test_support",
   ]
@@ -1115,6 +1132,10 @@
   android_manifest_dep = ":chrome_modern_public_android_manifest"
   apk_name = "ChromeModernPublic"
   shared_libraries = [ ":libchrome" ]
+  add_unwind_tables_in_apk = _add_unwind_tables_in_chrome_public_apk
+  if (_add_unwind_tables_in_chrome_public_apk) {
+    shared_library_for_unwind_asset = "chrome"
+  }
 
   if (!is_java_debug) {
     png_to_webp = true
@@ -1155,6 +1176,11 @@
     "//chrome/android:chrome_java",
     "//chrome/android:class_register_java",
   ]
+
+  add_unwind_tables_in_apk = _add_unwind_tables_in_monochrome_public_apk
+  if (_add_unwind_tables_in_monochrome_public_apk && can_unwind_with_cfi_table) {
+    shared_library_for_unwind_asset = "monochrome"
+  }
 }
 
 chrome_public_apk_tmpl_shared("chrome_sync_shell_apk") {
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index ebabc6b..3440a3c 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -5,6 +5,8 @@
 import("//base/android/linker/config.gni")
 import("//build/config/android/rules.gni")
 import("//build/config/locales.gni")
+import("//build/config/android/extract_unwind_tables.gni")
+import("//build/config/compiler/compiler.gni")
 import("//chrome/common/features.gni")
 import("//third_party/leakcanary/config.gni")
 import("channel.gni")
@@ -24,6 +26,25 @@
 ]
 
 template("chrome_public_apk_tmpl") {
+  # Adds unwind table asset to the chrome apk for the given library target. This
+  # is not part of generic apk assets target since it depends on the main shared
+  # library of the apk, to extract unwind tables.
+  if (defined(invoker.add_unwind_tables_in_apk) &&
+      invoker.add_unwind_tables_in_apk) {
+    _unwind_asset = "${target_name}_unwind_assets"
+    unwind_table_asset(_unwind_asset) {
+      if (defined(invoker.testonly)) {
+        testonly = invoker.testonly
+      }
+
+      # This value is only used when unwinding is possible.
+      if (can_unwind_with_cfi_table) {
+        library_target = invoker.shared_library_for_unwind_asset
+      }
+      deps = invoker.shared_libraries
+    }
+  }
+
   android_apk(target_name) {
     forward_variables_from(invoker, "*")
     exclude_xxxhdpi = true
@@ -98,6 +119,11 @@
           !use_lld && (use_chromium_linker || requires_sdk_api_level_23)
     }
     command_line_flags_file = "chrome-command-line"
+
+    if (defined(invoker.add_unwind_tables_in_apk) &&
+        invoker.add_unwind_tables_in_apk) {
+      deps += [ ":$_unwind_asset" ]
+    }
   }
 }
 
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 f4b13d1..5ddf723d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -208,6 +208,7 @@
     public static final String FULLSCREEN_ACTIVITY = "FullscreenActivity";
     public static final String GRANT_NOTIFICATIONS_TO_DSE = "GrantNotificationsToDSE";
     public static final String HOME_PAGE_BUTTON_FORCE_ENABLED = "HomePageButtonForceEnabled";
+    public static final String HORIZONTAL_TAB_SWITCHER_ANDROID = "HorizontalTabSwitcherAndroid";
     // Whether we show an important sites dialog in the "Clear Browsing Data" flow.
     public static final String IMPORTANT_SITES_IN_CBD = "ImportantSitesInCBD";
     public static final String INTEREST_FEED_CONTENT_SUGGESTIONS = "InterestFeedContentSuggestions";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
index 95b17eb..ba8d6ec 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
@@ -15,6 +15,7 @@
 import android.widget.FrameLayout;
 
 import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.LayerTitleCache;
 import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
@@ -214,7 +215,7 @@
             if (mInputMode == SWIPE_MODE_SEND_TO_STACK) {
                 mStacks.get(getTabStackIndex()).drag(time, x, y, amountX, amountY);
             } else if (mInputMode == SWIPE_MODE_SWITCH_STACK) {
-                scrollStacks(getOrientation() == Orientation.PORTRAIT ? amountX : amountY);
+                scrollStacks(isUsingHorizontalLayout() ? amountY : amountX);
             }
         }
 
@@ -249,10 +250,9 @@
             if (mInputMode == SWIPE_MODE_SEND_TO_STACK) {
                 mStacks.get(getTabStackIndex()).fling(time, x, y, vx, vy);
             } else if (mInputMode == SWIPE_MODE_SWITCH_STACK) {
-                final float velocity = getOrientation() == Orientation.PORTRAIT ? vx : vy;
-                final float origin = getOrientation() == Orientation.PORTRAIT ? x : y;
-                final float max =
-                        getOrientation() == Orientation.PORTRAIT ? getWidth() : getHeight();
+                final float velocity = isUsingHorizontalLayout() ? vy : vx;
+                final float origin = isUsingHorizontalLayout() ? y : x;
+                final float max = isUsingHorizontalLayout() ? getHeight() : getWidth();
                 final float predicted = origin + velocity * SWITCH_STACK_FLING_DT;
                 final float delta = MathUtils.clamp(predicted, 0, max) - origin;
                 scrollStacks(delta);
@@ -318,6 +318,15 @@
     }
 
     /**
+     * Whether or not we're currently having the tabs scroll horizontally (as opposed to
+     * vertically).
+     */
+    private boolean isUsingHorizontalLayout() {
+        return getOrientation() == Orientation.LANDSCAPE
+                || ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID);
+    }
+
+    /**
      * Updates this layout to show one tab stack for each of the passed-in TabLists. Takes a
      * reference to the lists param and expects it not to change.
      * @param lists The list of TabLists to use.
@@ -808,14 +817,13 @@
             }
         }
 
-        if ((mDragDirection == DRAG_DIRECTION_VERTICAL)
-                ^ (getOrientation() == Orientation.LANDSCAPE)) {
+        if ((mDragDirection == DRAG_DIRECTION_VERTICAL) ^ isUsingHorizontalLayout()) {
             return SWIPE_MODE_SEND_TO_STACK;
         }
 
         float relativeX = mLastOnDownX - (x + dx);
         float relativeY = mLastOnDownY - (y + dy);
-        float switchDelta = getOrientation() == Orientation.PORTRAIT ? relativeX : relativeY;
+        float switchDelta = isUsingHorizontalLayout() ? relativeY : relativeX;
 
         // In LTR portrait mode, the first stack can be swiped to the left to switch to the second
         // stack, and the last stack can be swiped to the right to switch to the first stack. We
@@ -826,7 +834,7 @@
         // Landscape mode is like LTR portrait mode (increasing the stack index corresponds to a
         // positive switchDelta).
         final boolean isRtlPortraitMode =
-                (getOrientation() == Orientation.PORTRAIT && LocalizationUtils.isLayoutRtl());
+                (!isUsingHorizontalLayout() && LocalizationUtils.isLayoutRtl());
         final boolean onLeftmostStack = (currentIndex == 0 && !isRtlPortraitMode)
                 || (currentIndex == mStacks.size() - 1 && isRtlPortraitMode);
         final boolean onRightmostStack = (currentIndex == 0 && isRtlPortraitMode)
@@ -1008,16 +1016,16 @@
     }
 
     private PortraitViewport getViewportParameters() {
-        if (getOrientation() == Orientation.PORTRAIT) {
-            if (mCachedPortraitViewport == null) {
-                mCachedPortraitViewport = new PortraitViewport();
-            }
-            return mCachedPortraitViewport;
-        } else {
+        if (isUsingHorizontalLayout()) {
             if (mCachedLandscapeViewport == null) {
                 mCachedLandscapeViewport = new LandscapeViewport();
             }
             return mCachedLandscapeViewport;
+        } else {
+            if (mCachedPortraitViewport == null) {
+                mCachedPortraitViewport = new PortraitViewport();
+            }
+            return mCachedPortraitViewport;
         }
     }
 
@@ -1032,7 +1040,7 @@
         cancelAnimation(this, Property.STACK_SNAP);
         float fullDistance = getFullScrollDistance();
         mScrollIndexOffset += MathUtils.flipSignIf(delta / fullDistance,
-                getOrientation() == Orientation.PORTRAIT && LocalizationUtils.isLayoutRtl());
+                !isUsingHorizontalLayout() && LocalizationUtils.isLayoutRtl());
         mRenderedScrollOffset =
                 MathUtils.clamp(mScrollIndexOffset, 0, getMinRenderedScrollOffset());
         requestStackUpdate();
@@ -1203,8 +1211,7 @@
      * @return The distance between two neighboring tab stacks.
      */
     private float getFullScrollDistance() {
-        float distance = getOrientation() == Orientation.PORTRAIT ? getWidth()
-                                                                  : getHeightMinusBrowserControls();
+        float distance = isUsingHorizontalLayout() ? getHeightMinusBrowserControls() : getWidth();
         if (mStacks.size() > 2) {
             return distance - getViewportParameters().getInnerMargin();
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
index 76b5beb..b7c5e5d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
@@ -14,6 +14,7 @@
 
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
 import org.chromium.chrome.browser.compositor.layouts.Layout.Orientation;
@@ -2315,7 +2316,12 @@
     }
 
     private void updateCurrentMode(int orientation) {
-        mCurrentMode = orientation;
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)) {
+            mCurrentMode = Orientation.LANDSCAPE;
+        } else {
+            mCurrentMode = orientation;
+        }
+
         mDiscardDirection = getDefaultDiscardDirection();
         setWarpState(true, false);
         final float opaqueTopPadding = mBorderTopPadding - mBorderTransparentTop;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
index 42281ad..fd929055 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
@@ -12,6 +12,7 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.LayerTitleCache;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
 import org.chromium.chrome.browser.compositor.layouts.Layout.Orientation;
@@ -66,6 +67,10 @@
             assert t.isVisible() : "LayoutTab in that list should be visible";
             final float decoration = t.getDecorationAlpha();
 
+            boolean isPortrait =
+                    !ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)
+                    && layout.getOrientation() == Orientation.PORTRAIT;
+
             boolean useModernDesign = FeatureUtilities.isChromeModernDesignEnabled();
 
             float shadowAlpha = decoration;
@@ -96,11 +101,10 @@
                     R.drawable.tabswitcher_border_frame_inner_shadow, t.canUseLiveTexture(),
                     FeatureUtilities.isChromeModernDesignEnabled(), t.getBackgroundColor(),
                     ApiCompatibilityUtils.getColor(res, borderColorResource), t.isIncognito(),
-                    layout.getOrientation() == Orientation.PORTRAIT, t.getRenderX() * dpToPx,
-                    t.getRenderY() * dpToPx, t.getScaledContentWidth() * dpToPx,
-                    t.getScaledContentHeight() * dpToPx, t.getOriginalContentWidth() * dpToPx,
-                    t.getOriginalContentHeight() * dpToPx, contentViewport.height(),
-                    t.getClippedX() * dpToPx, t.getClippedY() * dpToPx,
+                    isPortrait, t.getRenderX() * dpToPx, t.getRenderY() * dpToPx,
+                    t.getScaledContentWidth() * dpToPx, t.getScaledContentHeight() * dpToPx,
+                    t.getOriginalContentWidth() * dpToPx, t.getOriginalContentHeight() * dpToPx,
+                    contentViewport.height(), t.getClippedX() * dpToPx, t.getClippedY() * dpToPx,
                     Math.min(t.getClippedWidth(), t.getScaledContentWidth()) * dpToPx,
                     Math.min(t.getClippedHeight(), t.getScaledContentHeight()) * dpToPx,
                     t.getTiltXPivotOffset() * dpToPx, t.getTiltYPivotOffset() * dpToPx,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
index c2ec827..04573d7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
@@ -458,8 +458,15 @@
     }
 
     /**
-     * Callback from the native code to publish a page.  This will take the page, now in
-     * a public directory, and share it.
+     * Called when publishing is done.  Continues with processing to share.
+     */
+    public static void publishCompleted(OfflinePageItem page, final Activity activity,
+            final Callback<ShareParams> shareCallback) {
+        sharePublishedPage(page, activity, shareCallback);
+    }
+
+    /**
+     * This will take a page in a public directory, and share it.
      */
     public static void sharePublishedPage(OfflinePageItem page, final Activity activity,
             final Callback<ShareParams> shareCallback) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java
index d2569b3a..0fa180af 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java
@@ -45,6 +45,6 @@
 
         // TODO(petewil): Sharing seems out of place here. Move the call to sharing
         // back to OfflinePageUtils.
-        OfflinePageUtils.sharePublishedPage(page, mActivity, mShareCallback);
+        OfflinePageUtils.publishCompleted(page, mActivity, mShareCallback);
     }
 }
diff --git a/chrome/android/monochrome/scripts/monochrome_apk_checker.py b/chrome/android/monochrome/scripts/monochrome_apk_checker.py
index f90dbe4..c1e60920 100755
--- a/chrome/android/monochrome/scripts/monochrome_apk_checker.py
+++ b/chrome/android/monochrome/scripts/monochrome_apk_checker.py
@@ -54,6 +54,7 @@
     r'resources\.arsc',
     r'classes\.dex',
     r'res/.*\.xml', # Resource id isn't same
+    r'assets/unwind_cfi_32', # Generated from apk's shared library
      # All pak files except chrome_100_percent.pak are different
     r'assets/resources\.pak',
     r'assets/am\.pak',
diff --git a/chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json b/chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json
index 49172fc..b72c69d 100644
--- a/chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json
+++ b/chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json
@@ -2,12 +2,14 @@
   {
     "package": "com.google.vr.vrcore",
     "filename": "VrCoreSettings.xml",
+    "supports_encrypted_path": true,
     "set": {
       "VrSkipDon": true,
       "DaydreamSetupComplete": true,
       "VrDeviceParams": "CgZHb29nbGUSCUNhcmRib2FyZB0J-SA9JQHegj0qEAAAcEIAAHBCAABwQgAAcEI1KVwPPToIV_GrPmKxDT9QAFgAYAM",
       "UseAutomatedController": false,
-      "GvrPlatformLibraryPref": false
+      "GvrPlatformLibraryPref": false,
+      "EnableVrCoreHeadTracking": true
     }
   }
 ]
diff --git a/chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json b/chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json
index c554ba2c..11dd340 100644
--- a/chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json
+++ b/chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json
@@ -2,6 +2,7 @@
   {
     "package": "com.google.vr.vrcore",
     "filename": "VrCoreSettings.xml",
+    "supports_encrypted_path": true,
     "set": {
       "VrSkipDon": true,
       "DaydreamSetupComplete": true,
@@ -9,7 +10,8 @@
       "UseAutomatedController": true,
       "PairedControllerDriver": "DRIVER_AUTOMATED",
       "PairedControllerAddress": "FOO",
-      "GvrPlatformLibraryPref": false
+      "GvrPlatformLibraryPref": false,
+      "EnableVrCoreHeadTracking": true
     }
   }
 ]
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 9315fe9..cfa3bb74 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -2302,12 +2302,12 @@
   <message name="IDS_SETTINGS_RESET" desc="Title for an item in the 'Reset and clean up' section of Chrome Settings. If the user clicks this option, browser settings will be returned to their default values, after a confirmation by the user." meaning="Chrome Cleanup feature. Try to use the same translation for 'Reset' in 'Reset and cleanup' string.">
     Reset settings
   </message>
+  <message name="IDS_SETTINGS_RESET_SETTINGS_TRIGGER" desc="The label describing the 'reset profile setting' feature">
+    Restore settings to their original defaults
+  </message>
   <message name="IDS_SETTINGS_RESET_AUTOMATED_DIALOG_TITLE" desc="The title of the dialog informing the user that automated resetting of some settings occurred.">
     Some settings were reset
   </message>
-  <message name="IDS_SETTINGS_RESET_PROFILE_SETTINGS_DESCRIPTION" desc="The label describing the 'reset profile setting' feature">
-    Restore settings to their original defaults
-  </message>
   <message name="IDS_SETTINGS_RESET_BANNER_TEXT" desc="The text to show in a banner at the top of the chrome://settings page. The banner is displayed when Chrome detects that some settings have been tampered with and were reset to factory defaults.">
     Chrome detected that some of your settings were corrupted by another program and reset them to their original defaults.
   </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index b991cae..58a6ff12 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3723,6 +3723,8 @@
       "offline_pages/prefetch/prefetch_service_factory.h",
       "offline_pages/prefetch/prefetched_pages_notifier.cc",
       "offline_pages/prefetch/prefetched_pages_notifier.h",
+      "offline_pages/prefetch/thumbnail_fetcher_impl.cc",
+      "offline_pages/prefetch/thumbnail_fetcher_impl.h",
       "offline_pages/recent_tab_helper.cc",
       "offline_pages/recent_tab_helper.h",
       "offline_pages/request_coordinator_factory.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 9c9f598..4a9d3b0e 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3798,6 +3798,13 @@
      kOsAll,
      FEATURE_VALUE_TYPE(features::kSupervisedUserCommittedInterstitials)},
 
+#if defined(OS_ANDROID)
+    {"enable-horizontal-tab-switcher",
+     flag_descriptions::kHorizontalTabSwitcherAndroidName,
+     flag_descriptions::kHorizontalTabSwitcherAndroidDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kHorizontalTabSwitcherAndroid)},
+#endif  // OS_ANDROID
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 4a8134a0..d38d18a 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -96,6 +96,7 @@
     &data_reduction_proxy::features::kDataReductionMainMenu,
     &kFullscreenActivity,
     &kHomePageButtonForceEnabled,
+    &kHorizontalTabSwitcherAndroid,
     &kImprovedA2HS,
     &kLanguagesPreference,
     &kModalPermissionDialogView,
@@ -278,6 +279,9 @@
 const base::Feature kHomePageButtonForceEnabled{
     "HomePageButtonForceEnabled", base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kHorizontalTabSwitcherAndroid{
+    "HorizontalTabSwitcherAndroid", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Makes "Add to Home screen" in the app menu generate an APK for the shortcut
 // URL which opens Chrome in fullscreen.
 // This feature is kept around so that we have a kill-switch in case of server
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index 7671177..e1ca621 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -48,6 +48,7 @@
 extern const base::Feature kDownloadHomeShowStorageInfo;
 extern const base::Feature kFullscreenActivity;
 extern const base::Feature kHomePageButtonForceEnabled;
+extern const base::Feature kHorizontalTabSwitcherAndroid;
 extern const base::Feature kImprovedA2HS;
 extern const base::Feature kLanguagesPreference;
 extern const base::Feature kModalPermissionDialogView;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 4ba51bd..10d30e19 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -30,6 +30,7 @@
     "//chrome/app/theme:theme_resources",
     "//chromeos:concierge_proto",
     "//chromeos:power_manager_proto",
+    "//chromeos:vm_applications_apps_proto",
     "//components/policy/proto",
     "//content/app/resources",
     "//ui/chromeos/resources",
@@ -533,6 +534,8 @@
     "dbus/kiosk_info_service_provider.h",
     "dbus/screen_lock_service_provider.cc",
     "dbus/screen_lock_service_provider.h",
+    "dbus/vm_applications_service_provider_delegate.cc",
+    "dbus/vm_applications_service_provider_delegate.h",
     "display/display_configuration_observer.cc",
     "display/display_configuration_observer.h",
     "display/display_prefs.cc",
@@ -923,8 +926,6 @@
     "login/easy_unlock/easy_unlock_types.h",
     "login/easy_unlock/easy_unlock_user_login_flow.cc",
     "login/easy_unlock/easy_unlock_user_login_flow.h",
-    "login/easy_unlock/secure_message_delegate_chromeos.cc",
-    "login/easy_unlock/secure_message_delegate_chromeos.h",
     "login/easy_unlock/short_lived_user_context.cc",
     "login/easy_unlock/short_lived_user_context.h",
     "login/enrollment/auto_enrollment_check_screen.cc",
diff --git a/chrome/browser/chromeos/apps/intent_helper/OWNERS b/chrome/browser/chromeos/apps/intent_helper/OWNERS
index 576b4995..8db6e277 100644
--- a/chrome/browser/chromeos/apps/intent_helper/OWNERS
+++ b/chrome/browser/chromeos/apps/intent_helper/OWNERS
@@ -1,3 +1,4 @@
-# For ARC++ related code
+# For ARC related code
 djacobo@chromium.org
-yusukes@chromium.org
+# For ARC related code, backup reviewers
+file://chrome/browser/chromeos/arc/OWNERS
diff --git a/chrome/browser/chromeos/arc/intent_helper/OWNERS b/chrome/browser/chromeos/arc/intent_helper/OWNERS
new file mode 100644
index 0000000..3f30794
--- /dev/null
+++ b/chrome/browser/chromeos/arc/intent_helper/OWNERS
@@ -0,0 +1 @@
+djacobo@chromium.org
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 390a499..5ef27bf 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -51,6 +51,7 @@
 #include "chrome/browser/chromeos/dbus/finch_features_service_provider_delegate.h"
 #include "chrome/browser/chromeos/dbus/kiosk_info_service_provider.h"
 #include "chrome/browser/chromeos/dbus/screen_lock_service_provider.h"
+#include "chrome/browser/chromeos/dbus/vm_applications_service_provider_delegate.h"
 #include "chrome/browser/chromeos/display/quirks_manager_delegate_impl.h"
 #include "chrome/browser/chromeos/events/event_rewriter_controller.h"
 #include "chrome/browser/chromeos/events/event_rewriter_delegate_impl.h"
@@ -131,6 +132,7 @@
 #include "chromeos/dbus/services/liveness_service_provider.h"
 #include "chromeos/dbus/services/proxy_resolution_service_provider.h"
 #include "chromeos/dbus/services/virtual_file_request_service_provider.h"
+#include "chromeos/dbus/services/vm_applications_service_provider.h"
 #include "chromeos/dbus/session_manager_client.h"
 #include "chromeos/disks/disk_mount_manager.h"
 #include "chromeos/login/login_state.h"
@@ -402,6 +404,13 @@
             std::make_unique<ChromeFeaturesServiceProvider>(
                 std::make_unique<FinchFeaturesServiceProviderDelegate>())));
 
+    vm_applications_service_ = CrosDBusService::Create(
+        vm_tools::apps::kVmApplicationsServiceName,
+        dbus::ObjectPath(vm_tools::apps::kVmApplicationsServicePath),
+        CrosDBusService::CreateServiceProviderList(
+            std::make_unique<VmApplicationsServiceProvider>(
+                std::make_unique<VmApplicationsServiceProviderDelegate>())));
+
     // Initialize PowerDataCollector after DBusThreadManager is initialized.
     PowerDataCollector::Initialize();
 
@@ -446,6 +455,7 @@
     virtual_file_request_service_.reset();
     component_updater_service_.reset();
     finch_features_service_.reset();
+    vm_applications_service_.reset();
     PowerDataCollector::Shutdown();
     PowerPolicyController::Shutdown();
     device::BluetoothAdapterFactory::Shutdown();
@@ -472,6 +482,7 @@
   std::unique_ptr<CrosDBusService> virtual_file_request_service_;
   std::unique_ptr<CrosDBusService> component_updater_service_;
   std::unique_ptr<CrosDBusService> finch_features_service_;
+  std::unique_ptr<CrosDBusService> vm_applications_service_;
 
   ChromeConsoleServiceProviderDelegate console_service_provider_delegate_;
 
diff --git a/chrome/browser/chromeos/crostini/crostini_registry_service.cc b/chrome/browser/chromeos/crostini/crostini_registry_service.cc
index 94b3b24..4cf43b77 100644
--- a/chrome/browser/chromeos/crostini/crostini_registry_service.cc
+++ b/chrome/browser/chromeos/crostini/crostini_registry_service.cc
@@ -6,11 +6,14 @@
 
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chromeos/dbus/vm_applications/apps.pb.h"
 #include "components/crx_file/id_util.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 
+using vm_tools::apps::App;
+
 namespace chromeos {
 
 namespace {
@@ -57,17 +60,38 @@
                                         name->GetString());
 }
 
-void CrostiniRegistryService::SetRegistration(
-    const Registration& registration) {
-  base::Value pref_registration(base::Value::Type::DICTIONARY);
-  pref_registration.SetKey(kAppDesktopFileIdKey,
-                           base::Value(registration.desktop_file_id));
-  pref_registration.SetKey(kAppNameKey, base::Value(registration.name));
-
+void CrostiniRegistryService::UpdateApplicationList(
+    const vm_tools::apps::ApplicationList& app_list) {
   DictionaryPrefUpdate update(prefs_, kCrostiniRegistryPref);
   base::DictionaryValue* apps = update.Get();
-  apps->SetKey(GenerateAppId(registration.desktop_file_id),
-               std::move(pref_registration));
+  apps->Clear();
+
+  for (const App& app : app_list.apps()) {
+    if (app.desktop_file_id().empty()) {
+      LOG(WARNING) << "Received app with missing desktop file id";
+      continue;
+    }
+
+    std::string default_name;
+    for (const App::LocaleString::Entry& localized_name : app.name().values()) {
+      if (localized_name.locale().empty()) {
+        default_name = localized_name.value();
+        break;
+      }
+    }
+    if (default_name.empty()) {
+      LOG(WARNING) << "Received app '" << app.desktop_file_id()
+                   << "' with missing unlocalized name";
+      continue;
+    }
+
+    base::Value pref_registration(base::Value::Type::DICTIONARY);
+    pref_registration.SetKey(kAppDesktopFileIdKey,
+                             base::Value(app.desktop_file_id()));
+    pref_registration.SetKey(kAppNameKey, base::Value(default_name));
+    apps->SetKey(GenerateAppId(app.desktop_file_id()),
+                 std::move(pref_registration));
+  }
 }
 
 // static
diff --git a/chrome/browser/chromeos/crostini/crostini_registry_service.h b/chrome/browser/chromeos/crostini/crostini_registry_service.h
index f8459d5..b1ce493 100644
--- a/chrome/browser/chromeos/crostini/crostini_registry_service.h
+++ b/chrome/browser/chromeos/crostini/crostini_registry_service.h
@@ -15,6 +15,12 @@
 class PrefRegistrySimple;
 class PrefService;
 
+namespace vm_tools {
+namespace apps {
+class ApplicationList;
+}  // namespace apps
+}  // namespace vm_tools
+
 namespace chromeos {
 
 // The CrostiniRegistryService stores information about Desktop Entries (apps)
@@ -46,9 +52,8 @@
   std::unique_ptr<CrostiniRegistryService::Registration> GetRegistration(
       const std::string& app_id) const;
 
-  // If an app has already been registered for the given desktop file id, it
-  // will be overriden.
-  void SetRegistration(const Registration& registration);
+  // The existing list of apps is replaced by |application_list|.
+  void UpdateApplicationList(const vm_tools::apps::ApplicationList& app_list);
 
   static void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
diff --git a/chrome/browser/chromeos/crostini/crostini_registry_service_unittest.cc b/chrome/browser/chromeos/crostini/crostini_registry_service_unittest.cc
index e1b306b..7f912ba 100644
--- a/chrome/browser/chromeos/crostini/crostini_registry_service_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_registry_service_unittest.cc
@@ -8,10 +8,14 @@
 
 #include "base/macros.h"
 #include "chrome/test/base/testing_profile.h"
+#include "chromeos/dbus/vm_applications/apps.pb.h"
 #include "components/crx_file/id_util.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using vm_tools::apps::App;
+using vm_tools::apps::ApplicationList;
+
 namespace chromeos {
 
 class CrostiniRegistryServiceTest : public testing::Test {
@@ -45,8 +49,15 @@
   std::string app_id = GenerateAppId(desktop_file_id);
   EXPECT_EQ(nullptr, service()->GetRegistration(app_id));
 
-  CrostiniRegistryService::Registration registration(desktop_file_id, name);
-  service()->SetRegistration(registration);
+  ApplicationList app_list;
+  App* app = app_list.add_apps();
+  app->set_desktop_file_id(desktop_file_id);
+  App::LocaleString::Entry* name_with_locale =
+      app->mutable_name()->add_values();
+  name_with_locale->set_locale("");
+  name_with_locale->set_value(name);
+
+  service()->UpdateApplicationList(app_list);
   auto result = service()->GetRegistration(app_id);
   ASSERT_NE(nullptr, result);
   EXPECT_EQ(result->desktop_file_id, desktop_file_id);
diff --git a/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc b/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc
index 53de9d7..40cd00dd 100644
--- a/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc
+++ b/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/chromeos/cryptauth/cryptauth_device_id_provider_impl.h"
 #include "chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.h"
-#include "chrome/browser/chromeos/login/easy_unlock/secure_message_delegate_chromeos.h"
 #include "chrome/browser/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
@@ -31,7 +30,7 @@
 #include "components/cryptauth/cryptauth_gcm_manager_impl.h"
 #include "components/cryptauth/device_classifier_util.h"
 #include "components/cryptauth/proto/cryptauth_api.pb.h"
-#include "components/cryptauth/secure_message_delegate.h"
+#include "components/cryptauth/secure_message_delegate_impl.h"
 #include "components/gcm_driver/gcm_profile_service.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
@@ -55,11 +54,6 @@
       cryptauth::device_classifier_util::GetDeviceClassifier());
 }
 
-std::unique_ptr<cryptauth::SecureMessageDelegate>
-CreateSecureMessageDelegateImpl() {
-  return std::make_unique<chromeos::SecureMessageDelegateChromeOS>();
-}
-
 class CryptAuthEnrollerFactoryImpl
     : public cryptauth::CryptAuthEnrollerFactory {
  public:
@@ -68,7 +62,7 @@
   std::unique_ptr<cryptauth::CryptAuthEnroller> CreateInstance() override {
     return std::make_unique<cryptauth::CryptAuthEnrollerImpl>(
         CreateCryptAuthClientFactoryImpl(profile_),
-        CreateSecureMessageDelegateImpl());
+        cryptauth::SecureMessageDelegateImpl::Factory::NewInstance());
   }
 
  private:
@@ -95,7 +89,7 @@
       cryptauth::CryptAuthEnrollmentManagerImpl::Factory::NewInstance(
           base::DefaultClock::GetInstance(),
           std::make_unique<CryptAuthEnrollerFactoryImpl>(profile),
-          CreateSecureMessageDelegateImpl(),
+          cryptauth::SecureMessageDelegateImpl::Factory::NewInstance(),
           GcmDeviceInfoProviderImpl::GetInstance()->GetGcmDeviceInfo(),
           gcm_manager.get(), profile->GetPrefs());
 
@@ -188,18 +182,11 @@
   return signin_manager_->GetAuthenticatedAccountId();
 }
 
-std::unique_ptr<cryptauth::SecureMessageDelegate>
-ChromeCryptAuthService::CreateSecureMessageDelegate() {
-  return CreateSecureMessageDelegateImpl();
-}
-
 std::unique_ptr<cryptauth::CryptAuthClientFactory>
 ChromeCryptAuthService::CreateCryptAuthClientFactory() {
   return CreateCryptAuthClientFactoryImpl(profile_);
 }
 
-void ChromeCryptAuthService::OnEnrollmentStarted() {}
-
 void ChromeCryptAuthService::OnEnrollmentFinished(bool success) {
   if (success)
     device_manager_->Start();
diff --git a/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.h b/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.h
index 0574daf..a5b7568 100644
--- a/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.h
+++ b/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.h
@@ -48,12 +48,7 @@
   std::unique_ptr<cryptauth::CryptAuthClientFactory>
   CreateCryptAuthClientFactory() override;
 
-  // cryptauth::SecureMessageDelegate::Factory:
-  std::unique_ptr<cryptauth::SecureMessageDelegate>
-  CreateSecureMessageDelegate() override;
-
   // cryptauth::CryptAuthEnrollmentManager::Observer:
-  void OnEnrollmentStarted() override;
   void OnEnrollmentFinished(bool success) override;
 
  protected:
diff --git a/chrome/browser/chromeos/dbus/vm_applications_service_provider_delegate.cc b/chrome/browser/chromeos/dbus/vm_applications_service_provider_delegate.cc
new file mode 100644
index 0000000..fe4107a
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/vm_applications_service_provider_delegate.cc
@@ -0,0 +1,31 @@
+// Copyright 2018 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/chromeos/dbus/vm_applications_service_provider_delegate.h"
+
+#include "chrome/browser/chromeos/crostini/crostini_registry_service.h"
+#include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile_manager.h"
+
+namespace chromeos {
+
+VmApplicationsServiceProviderDelegate::VmApplicationsServiceProviderDelegate() =
+    default;
+
+VmApplicationsServiceProviderDelegate::
+    ~VmApplicationsServiceProviderDelegate() = default;
+
+void VmApplicationsServiceProviderDelegate::UpdateApplicationList(
+    const vm_tools::apps::ApplicationList& app_list) {
+  Profile* profile = ProfileManager::GetPrimaryUserProfile();
+  if (!ProfileHelper::IsPrimaryProfile(profile))
+    return;
+
+  CrostiniRegistryService* registry_service =
+      CrostiniRegistryServiceFactory::GetForProfile(profile);
+  registry_service->UpdateApplicationList(app_list);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/dbus/vm_applications_service_provider_delegate.h b/chrome/browser/chromeos/dbus/vm_applications_service_provider_delegate.h
new file mode 100644
index 0000000..5194f72
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/vm_applications_service_provider_delegate.h
@@ -0,0 +1,29 @@
+// Copyright 2018 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_CHROMEOS_DBUS_VM_APPLICATIONS_SERVICE_PROVIDER_DELEGATE_H_
+#define CHROME_BROWSER_CHROMEOS_DBUS_VM_APPLICATIONS_SERVICE_PROVIDER_DELEGATE_H_
+
+#include "base/macros.h"
+#include "chromeos/dbus/services/vm_applications_service_provider.h"
+
+namespace chromeos {
+
+class VmApplicationsServiceProviderDelegate
+    : public VmApplicationsServiceProvider::Delegate {
+ public:
+  VmApplicationsServiceProviderDelegate();
+  ~VmApplicationsServiceProviderDelegate() override;
+
+  // VmApplicationsServiceProvider::Delegate:
+  void UpdateApplicationList(
+      const vm_tools::apps::ApplicationList& app_list) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(VmApplicationsServiceProviderDelegate);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_DBUS_VM_APPLICATIONS_SERVICE_PROVIDER_DELEGATE_H_
diff --git a/chrome/browser/chromeos/file_manager/gallery_browsertest.cc b/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
index a3d634b..cc280cf 100644
--- a/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
@@ -170,14 +170,7 @@
   StartTest();
 }
 
-// http://crbug.com/508949
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_RenameImageOnDownloads DISABLED_RenameImageOnDownloads
-#else
-#define MAYBE_RenameImageOnDownloads RenameImageOnDownloads
-#endif
-IN_PROC_BROWSER_TEST_F(GalleryBrowserTestInGuestMode,
-                       MAYBE_RenameImageOnDownloads) {
+IN_PROC_BROWSER_TEST_F(GalleryBrowserTestInGuestMode, RenameImageOnDownloads) {
   set_test_case_name("renameImageOnDownloads");
   StartTest();
 }
@@ -233,7 +226,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GalleryBrowserTestInGuestMode,
-                       MAYBE_CheckAvailabilityOfShareButtonOnDownloads) {
+                       CheckAvailabilityOfShareButtonOnDownloads) {
   set_test_case_name("checkAvailabilityOfShareButtonOnDownloads");
   StartTest();
 }
@@ -343,8 +336,7 @@
   StartTest();
 }
 
-IN_PROC_BROWSER_TEST_F(GalleryBrowserTestInGuestMode,
-                       MAYBE_ResizeImageOnDownloads) {
+IN_PROC_BROWSER_TEST_F(GalleryBrowserTestInGuestMode, ResizeImageOnDownloads) {
   set_test_case_name("resizeImageOnDownloads");
   StartTest();
 }
diff --git a/chrome/browser/chromeos/login/easy_unlock/chrome_proximity_auth_client.cc b/chrome/browser/chromeos/login/easy_unlock/chrome_proximity_auth_client.cc
index b646911..84245a1 100644
--- a/chrome/browser/chromeos/login/easy_unlock/chrome_proximity_auth_client.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/chrome_proximity_auth_client.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.h"
-#include "chrome/browser/chromeos/login/easy_unlock/secure_message_delegate_chromeos.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_window.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
@@ -25,7 +24,6 @@
 #include "components/cryptauth/cryptauth_device_manager.h"
 #include "components/cryptauth/cryptauth_enrollment_manager.h"
 #include "components/cryptauth/local_device_data_provider.h"
-#include "components/cryptauth/secure_message_delegate.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_manager_base.h"
@@ -93,14 +91,6 @@
   return nullptr;
 }
 
-std::unique_ptr<cryptauth::SecureMessageDelegate>
-ChromeProximityAuthClient::CreateSecureMessageDelegate() {
-  // Note: Although CryptAuthService::CreateSecureMessageDelegate() exists, we
-  // don't use it here (as opposed to other methods in this class) because the
-  // CryptAuthService is not available on the ChromeOS login screen.
-  return std::make_unique<SecureMessageDelegateChromeOS>();
-}
-
 std::unique_ptr<cryptauth::CryptAuthClientFactory>
 ChromeProximityAuthClient::CreateCryptAuthClientFactory() {
   return GetCryptAuthService()->CreateCryptAuthClientFactory();
diff --git a/chrome/browser/chromeos/login/easy_unlock/chrome_proximity_auth_client.h b/chrome/browser/chromeos/login/easy_unlock/chrome_proximity_auth_client.h
index 44a433f..1275e40b 100644
--- a/chrome/browser/chromeos/login/easy_unlock/chrome_proximity_auth_client.h
+++ b/chrome/browser/chromeos/login/easy_unlock/chrome_proximity_auth_client.h
@@ -28,8 +28,6 @@
   void UpdateScreenlockState(proximity_auth::ScreenlockState state) override;
   void FinalizeUnlock(bool success) override;
   proximity_auth::ProximityAuthPrefManager* GetPrefManager() override;
-  std::unique_ptr<cryptauth::SecureMessageDelegate>
-  CreateSecureMessageDelegate() override;
   std::unique_ptr<cryptauth::CryptAuthClientFactory>
   CreateCryptAuthClientFactory() override;
   cryptauth::DeviceClassifier GetDeviceClassifier() override;
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
index a47ed9c8..cfae874 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
@@ -29,7 +29,6 @@
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_observer.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.h"
-#include "chrome/browser/chromeos/login/easy_unlock/secure_message_delegate_chromeos.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
@@ -50,7 +49,6 @@
 #include "components/cryptauth/cryptauth_client_impl.h"
 #include "components/cryptauth/cryptauth_device_manager.h"
 #include "components/cryptauth/cryptauth_enrollment_manager.h"
-#include "components/cryptauth/secure_message_delegate.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc
index 438ae73..30ef969 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc
@@ -51,7 +51,7 @@
 #include "components/cryptauth/cryptauth_gcm_manager_impl.h"
 #include "components/cryptauth/local_device_data_provider.h"
 #include "components/cryptauth/remote_device_loader.h"
-#include "components/cryptauth/secure_message_delegate.h"
+#include "components/cryptauth/secure_message_delegate_impl.h"
 #include "components/gcm_driver/gcm_profile_service.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
@@ -124,7 +124,7 @@
       GetCryptAuthDeviceManager()->GetUnlockKeys(),
       proximity_auth_client()->GetAccountId(),
       GetCryptAuthEnrollmentManager()->GetUserPrivateKey(),
-      proximity_auth_client()->CreateSecureMessageDelegate()));
+      cryptauth::SecureMessageDelegateImpl::Factory::NewInstance()));
   remote_device_loader_->Load(
       true /* should_load_beacon_seeds */,
       base::Bind(&EasyUnlockServiceRegular::OnRemoteDevicesLoaded,
diff --git a/chrome/browser/chromeos/login/easy_unlock/secure_message_delegate_chromeos.h b/chrome/browser/chromeos/login/easy_unlock/secure_message_delegate_chromeos.h
deleted file mode 100644
index a5a5a96..0000000
--- a/chrome/browser/chromeos/login/easy_unlock/secure_message_delegate_chromeos.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_SECURE_MESSAGE_DELEGATE_CHROMEOS_H_
-#define CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_SECURE_MESSAGE_DELEGATE_CHROMEOS_H_
-
-#include "base/macros.h"
-#include "components/cryptauth/secure_message_delegate.h"
-
-namespace chromeos {
-
-class EasyUnlockClient;
-
-// SecureMessageDelegate implementation for ChromeOS.
-class SecureMessageDelegateChromeOS : public cryptauth::SecureMessageDelegate {
- public:
-  SecureMessageDelegateChromeOS();
-  ~SecureMessageDelegateChromeOS() override;
-
-  // SecureMessageDelegate:
-  void GenerateKeyPair(const GenerateKeyPairCallback& callback) override;
-  void DeriveKey(const std::string& private_key,
-                 const std::string& public_key,
-                 const DeriveKeyCallback& callback) override;
-  void CreateSecureMessage(
-      const std::string& payload,
-      const std::string& key,
-      const CreateOptions& create_options,
-      const CreateSecureMessageCallback& callback) override;
-  void UnwrapSecureMessage(
-      const std::string& serialized_message,
-      const std::string& key,
-      const UnwrapOptions& unwrap_options,
-      const UnwrapSecureMessageCallback& callback) override;
-
- private:
-  EasyUnlockClient* dbus_client_;
-
-  DISALLOW_COPY_AND_ASSIGN(SecureMessageDelegateChromeOS);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_SECURE_MESSAGE_DELEGATE_CHROMEOS_H_
diff --git a/chrome/browser/chromeos/login/session/chrome_session_manager.cc b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
index 570a813..d318e0a 100644
--- a/chrome/browser/chromeos/login/session/chrome_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
@@ -28,6 +28,7 @@
 #include "chrome/browser/chromeos/tether/tether_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/ui/app_list/app_list_service_impl.h"
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
@@ -164,6 +165,9 @@
     TetherService* tether_service = TetherService::Get(user_profile);
     if (tether_service)
       tether_service->StartTetherIfPossible();
+
+    // Associates AppListClient with the current active profile.
+    AppListServiceImpl::GetInstance()->GetAppListClient();
   }
 
   UserSessionManager::GetInstance()->CheckEolStatus(user_profile);
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 45b00b9a..4ef72890 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -7,8 +7,10 @@
 #include <stddef.h>
 
 #include <algorithm>
+#include <map>
 #include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/base_paths.h"
@@ -81,7 +83,8 @@
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/supervised_user/child_accounts/child_account_service.h"
 #include "chrome/browser/supervised_user/child_accounts/child_account_service_factory.h"
-#include "chrome/browser/ui/app_list/app_list_service.h"
+#include "chrome/browser/ui/app_list/app_list_client_impl.h"
+#include "chrome/browser/ui/app_list/app_list_service_impl.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "chrome/common/channel_info.h"
@@ -1961,6 +1964,9 @@
     profile->GetPrefs()->ClearPref(prefs::kShowSyncSettingsOnSessionStart);
     chrome::ShowSettingsSubPageForProfile(profile, "syncSetup");
   }
+
+  // Associates AppListClient with the current active profile.
+  AppListServiceImpl::GetInstance()->GetAppListClient();
 }
 
 void UserSessionManager::RespectLocalePreferenceWrapper(
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager.cc b/chrome/browser/chromeos/printing/cups_printers_manager.cc
index 34f3569..f316af9 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager.cc
@@ -25,6 +25,8 @@
 #include "chrome/common/pref_names.h"
 #include "components/policy/policy_constants.h"
 #include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_member.h"
+#include "components/prefs/pref_service.h"
 
 namespace chromeos {
 namespace {
@@ -94,7 +96,8 @@
                           std::unique_ptr<PrinterDetector> usb_detector,
                           std::unique_ptr<PrinterDetector> zeroconf_detector,
                           scoped_refptr<PpdProvider> ppd_provider,
-                          PrinterEventTracker* event_tracker)
+                          PrinterEventTracker* event_tracker,
+                          PrefService* pref_service)
       : synced_printers_manager_(synced_printers_manager),
         synced_printers_manager_observer_(this),
         usb_detector_(std::move(usb_detector)),
@@ -120,6 +123,9 @@
         std::make_unique<PrinterDetectorObserverProxy>(
             this, kZeroconfDetector, zeroconf_detector_.get());
     OnPrintersFound(kZeroconfDetector, zeroconf_detector_->GetPrinters());
+
+    native_printers_allowed_.Init(prefs::kUserNativePrintersAllowed,
+                                  pref_service);
   }
 
   ~CupsPrintersManagerImpl() override = default;
@@ -127,6 +133,12 @@
   // Public API function.
   std::vector<Printer> GetPrinters(PrinterClass printer_class) const override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
+    if (!native_printers_allowed_.GetValue() && printer_class != kEnterprise) {
+      // If native printers are disabled then simply return an empty vector.
+      LOG(WARNING) << "Attempting to retrieve native printers when "
+                      "UserNativePrintersAllowed is set to false";
+      return {};
+    }
     return printers_.at(printer_class);
   }
 
@@ -142,6 +154,11 @@
   // Public API function.
   void UpdateConfiguredPrinter(const Printer& printer) override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
+    if (!native_printers_allowed_.GetValue()) {
+      LOG(WARNING) << "UpdateConfiguredPrinter() called when "
+                      "UserNativePrintersAllowed is set to false";
+      return;
+    }
     // If this is an 'add' instead of just an update, record the event.
     MaybeRecordInstallation(printer);
     synced_printers_manager_->UpdateConfiguredPrinter(printer);
@@ -176,6 +193,11 @@
   // Public API function.
   void PrinterInstalled(const Printer& printer) override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
+    if (!native_printers_allowed_.GetValue()) {
+      LOG(WARNING) << "PrinterInstalled() called when "
+                      "UserNativePrintersAllowed is  set to false";
+      return;
+    }
     MaybeRecordInstallation(printer);
     synced_printers_manager_->PrinterInstalled(printer);
   }
@@ -192,6 +214,12 @@
   // more than just this function.
   std::unique_ptr<Printer> GetPrinter(const std::string& id) const override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
+    if (!native_printers_allowed_.GetValue()) {
+      LOG(WARNING) << "UserNativePrintersAllowed is disabled - only searching "
+                      "enterprise printers";
+      return GetEnterprisePrinter(id);
+    }
+
     for (const auto& printer_list : printers_) {
       for (const auto& printer : printer_list) {
         if (printer.id() == id) {
@@ -246,6 +274,15 @@
   }
 
  private:
+  std::unique_ptr<Printer> GetEnterprisePrinter(const std::string& id) const {
+    for (const auto& printer : printers_[kEnterprise]) {
+      if (printer.id() == id) {
+        return std::make_unique<Printer>(printer);
+      }
+    }
+    return nullptr;
+  }
+
   // Notify observers on the given classes the the relevant lists have changed.
   void NotifyObservers(
       const std::vector<CupsPrintersManager::PrinterClass>& printer_classes) {
@@ -508,6 +545,9 @@
 
   base::ObserverList<CupsPrintersManager::Observer> observer_list_;
 
+  // Holds the current value of the pref |UserNativePrintersAllowed|.
+  BooleanPrefMember native_printers_allowed_;
+
   base::WeakPtrFactory<CupsPrintersManagerImpl> weak_ptr_factory_;
 };
 
@@ -527,7 +567,8 @@
           profile),
       UsbPrinterDetector::Create(), ZeroconfPrinterDetector::Create(),
       CreatePpdProvider(profile),
-      PrinterEventTrackerFactory::GetInstance()->GetForBrowserContext(profile));
+      PrinterEventTrackerFactory::GetInstance()->GetForBrowserContext(profile),
+      profile->GetPrefs());
 }
 
 // static
@@ -536,10 +577,12 @@
     std::unique_ptr<PrinterDetector> usb_detector,
     std::unique_ptr<PrinterDetector> zeroconf_detector,
     scoped_refptr<PpdProvider> ppd_provider,
-    PrinterEventTracker* event_tracker) {
+    PrinterEventTracker* event_tracker,
+    PrefService* pref_service) {
   return std::make_unique<CupsPrintersManagerImpl>(
       synced_printers_manager, std::move(usb_detector),
-      std::move(zeroconf_detector), std::move(ppd_provider), event_tracker);
+      std::move(zeroconf_detector), std::move(ppd_provider), event_tracker,
+      pref_service);
 }
 
 // static
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager.h b/chrome/browser/chromeos/printing/cups_printers_manager.h
index 1bd9220..d6a18670 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager.h
+++ b/chrome/browser/chromeos/printing/cups_printers_manager.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/chromeos/printing/printer_event_tracker.h"
 #include "chromeos/printing/printer_configuration.h"
+#include "components/prefs/pref_service.h"
 
 class Profile;
 
@@ -57,7 +58,8 @@
       std::unique_ptr<PrinterDetector> usb_printer_detector,
       std::unique_ptr<PrinterDetector> zeroconf_printer_detector,
       scoped_refptr<PpdProvider> ppd_provider,
-      PrinterEventTracker* event_tracker);
+      PrinterEventTracker* event_tracker,
+      PrefService* pref_service);
 
   // Register the printing preferences with the |registry|.
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc b/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
index 2308028..02f3992 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
@@ -16,6 +16,8 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "chrome/browser/chromeos/printing/synced_printers_manager.h"
 #include "chrome/browser/chromeos/printing/usb_printer_detector.h"
+#include "chrome/common/pref_names.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
@@ -257,9 +259,14 @@
     zeroconf_detector_ = zeroconf_detector.get();
     auto usb_detector = std::make_unique<FakePrinterDetector>();
     usb_detector_ = usb_detector.get();
+
+    // Register the pref |UserNativePrintersAllowed|
+    CupsPrintersManager::RegisterProfilePrefs(pref_service_.registry());
+
     manager_ = CupsPrintersManager::Create(
         &synced_printers_manager_, std::move(usb_detector),
-        std::move(zeroconf_detector), ppd_provider_, &event_tracker_);
+        std::move(zeroconf_detector), ppd_provider_, &event_tracker_,
+        &pref_service_);
     manager_->AddObserver(this);
   }
 
@@ -280,6 +287,12 @@
     ExpectPrinterIdsAre(observed_printers_.at(printer_class), ids);
   }
 
+  void UpdatePolicyValue(const char* name, bool value) {
+    auto value_ptr = std::make_unique<base::Value>(value);
+    // TestingPrefSyncableService assumes ownership of |value_ptr|.
+    pref_service_.SetManagedPref(name, std::move(value_ptr));
+  }
+
  protected:
   base::test::ScopedTaskEnvironment scoped_task_environment_;
 
@@ -295,6 +308,10 @@
   // This is unused, it's just here for memory ownership.
   PrinterEventTracker event_tracker_;
 
+  // PrefService used to register the |UserNativePrintersAllowed| pref and
+  // change its value for testing.
+  sync_preferences::TestingPrefServiceSyncable pref_service_;
+
   // The manager being tested.  This must be declared after the fakes, as its
   // initialization must come after that of the fakes.
   std::unique_ptr<CupsPrintersManager> manager_;
@@ -474,5 +491,108 @@
   EXPECT_EQ(printer, nullptr);
 }
 
+// Test that if |UserNativePrintersAllowed| pref is set to false, then
+// GetPrinters() will only return printers from
+// |CupsPrintersManager::kEnterprise|.
+TEST_F(CupsPrintersManagerTest, GetPrintersUserNativePrintersDisabled) {
+  synced_printers_manager_.AddConfiguredPrinters({Printer("Configured")});
+  synced_printers_manager_.AddEnterprisePrinters({Printer("Enterprise")});
+  scoped_task_environment_.RunUntilIdle();
+
+  // Disable the use of non-enterprise printers.
+  UpdatePolicyValue(prefs::kUserNativePrintersAllowed, false);
+
+  // Verify that non-enterprise printers are not returned by GetPrinters()
+  std::vector<Printer> configured_printers =
+      manager_->GetPrinters(CupsPrintersManager::kConfigured);
+  ExpectPrinterIdsAre(configured_printers, {});
+
+  // Verify that enterprise printers are returned by GetPrinters()
+  std::vector<Printer> enterprise_printers =
+      manager_->GetPrinters(CupsPrintersManager::kEnterprise);
+  ExpectPrinterIdsAre(enterprise_printers, {"Enterprise"});
+}
+
+// Test that if |UserNativePrintersAllowed| pref is set to false, then
+// UpdateConfiguredPrinter() will simply do nothing.
+TEST_F(CupsPrintersManagerTest,
+       UpdateConfiguredPrinterUserNativePrintersDisabled) {
+  // Start by installing a configured printer to be used to test than any
+  // changes made to the printer will not be propogated.
+  Printer existing_configured("Configured");
+  synced_printers_manager_.AddConfiguredPrinters({existing_configured});
+  usb_detector_->AddDetections({MakeDiscoveredPrinter("Discovered")});
+  zeroconf_detector_->AddDetections({MakeAutomaticPrinter("Automatic")});
+  scoped_task_environment_.RunUntilIdle();
+
+  // Sanity check that we do, indeed, have one printer in each class.
+  ExpectPrintersInClassAre(CupsPrintersManager::kConfigured, {"Configured"});
+  ExpectPrintersInClassAre(CupsPrintersManager::kAutomatic, {"Automatic"});
+  ExpectPrintersInClassAre(CupsPrintersManager::kDiscovered, {"Discovered"});
+
+  // Disable the use of non-enterprise printers.
+  UpdatePolicyValue(prefs::kUserNativePrintersAllowed, false);
+
+  // Update the existing configured printer. Verify that the changes did not
+  // progogate.
+  existing_configured.set_display_name("New Display Name");
+  manager_->UpdateConfiguredPrinter(existing_configured);
+  scoped_task_environment_.RunUntilIdle();
+
+  // Reenable user printers in order to do checking.
+  UpdatePolicyValue(prefs::kUserNativePrintersAllowed, true);
+  ExpectPrintersInClassAre(CupsPrintersManager::kConfigured, {"Configured"});
+  EXPECT_EQ(
+      manager_->GetPrinters(CupsPrintersManager::kConfigured)[0].display_name(),
+      "");
+  UpdatePolicyValue(prefs::kUserNativePrintersAllowed, false);
+
+  // Attempt to update the Automatic and Discovered printers. In both cases
+  // check that the printers do not move into the configured category.
+  manager_->UpdateConfiguredPrinter(Printer("Automatic"));
+  scoped_task_environment_.RunUntilIdle();
+  UpdatePolicyValue(prefs::kUserNativePrintersAllowed, true);
+  ExpectPrintersInClassAre(CupsPrintersManager::kAutomatic, {"Automatic"});
+  ExpectPrintersInClassAre(CupsPrintersManager::kConfigured, {"Configured"});
+  UpdatePolicyValue(prefs::kUserNativePrintersAllowed, false);
+
+  manager_->UpdateConfiguredPrinter(Printer("Discovered"));
+  scoped_task_environment_.RunUntilIdle();
+  UpdatePolicyValue(prefs::kUserNativePrintersAllowed, true);
+  ExpectPrintersInClassAre(CupsPrintersManager::kDiscovered, {"Discovered"});
+  ExpectPrintersInClassAre(CupsPrintersManager::kConfigured, {"Configured"});
+  UpdatePolicyValue(prefs::kUserNativePrintersAllowed, false);
+
+  // Attempt to update a printer that we haven't seen before, check that nothing
+  // changed.
+  manager_->UpdateConfiguredPrinter(Printer("NewFangled"));
+  scoped_task_environment_.RunUntilIdle();
+  UpdatePolicyValue(prefs::kUserNativePrintersAllowed, true);
+  ExpectPrintersInClassAre(CupsPrintersManager::kConfigured, {"Configured"});
+}
+
+// Test that if |UserNativePrintersAllowed| pref is set to false GetPrinter only
+// returns a printer when the given printer id corresponds to an enterprise
+// printer. Otherwise, it returns nothing.
+TEST_F(CupsPrintersManagerTest, GetPrinterUserNativePrintersDisabled) {
+  synced_printers_manager_.AddConfiguredPrinters({Printer("Configured")});
+  synced_printers_manager_.AddEnterprisePrinters({Printer("Enterprise")});
+  scoped_task_environment_.RunUntilIdle();
+
+  // Sanity check that the printers were added.
+  ExpectPrintersInClassAre(CupsPrintersManager::kConfigured, {"Configured"});
+  ExpectPrintersInClassAre(CupsPrintersManager::kEnterprise, {"Enterprise"});
+
+  // Diable the use of non-enterprise printers.
+  UpdatePolicyValue(prefs::kUserNativePrintersAllowed, false);
+
+  std::unique_ptr<Printer> configured_ptr = manager_->GetPrinter("Configured");
+  EXPECT_EQ(configured_ptr, nullptr);
+
+  std::unique_ptr<Printer> enterprise_ptr = manager_->GetPrinter("Enterprise");
+  ASSERT_NE(enterprise_ptr, nullptr);
+  EXPECT_EQ(enterprise_ptr->id(), "Enterprise");
+}
+
 }  // namespace
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/tether/tether_service.cc b/chrome/browser/chromeos/tether/tether_service.cc
index c3113d3..034c800 100644
--- a/chrome/browser/chromeos/tether/tether_service.cc
+++ b/chrome/browser/chromeos/tether/tether_service.cc
@@ -145,8 +145,7 @@
               cryptauth_service->GetCryptAuthDeviceManager(),
               cryptauth_service->GetAccountId(),
               cryptauth_service->GetCryptAuthEnrollmentManager()
-                  ->GetUserPrivateKey(),
-              cryptauth_service)),
+                  ->GetUserPrivateKey())),
       tether_host_fetcher_(
           chromeos::tether::TetherHostFetcherImpl::Factory::NewInstance(
               remote_device_provider_.get())),
diff --git a/chrome/browser/chromeos/tether/tether_service_unittest.cc b/chrome/browser/chromeos/tether/tether_service_unittest.cc
index 3e60035..33ec3cdf 100644
--- a/chrome/browser/chromeos/tether/tether_service_unittest.cc
+++ b/chrome/browser/chromeos/tether/tether_service_unittest.cc
@@ -205,9 +205,7 @@
   std::unique_ptr<cryptauth::RemoteDeviceProvider> BuildInstance(
       cryptauth::CryptAuthDeviceManager* device_manager,
       const std::string& user_id,
-      const std::string& user_private_key,
-      cryptauth::SecureMessageDelegate::Factory*
-          secure_message_delegate_factory) override {
+      const std::string& user_private_key) override {
     return std::make_unique<cryptauth::FakeRemoteDeviceProvider>();
   }
 };
diff --git a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate_unittest.cc b/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate_unittest.cc
index 6b67ace..a2deb810 100644
--- a/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate_unittest.cc
+++ b/chrome/browser/data_use_measurement/page_load_capping/page_load_capping_infobar_delegate_unittest.cc
@@ -26,10 +26,7 @@
   ~PageLoadCappingInfoBarDelegateTest() override = default;
 
   void SetUpTest() {
-    InfoBarService* mock_infobar_service =
-        new MockInfoBarService(web_contents());
-    ASSERT_EQ(infobar_service(), mock_infobar_service);
-    ASSERT_TRUE(infobar_service());
+    MockInfoBarService::CreateForWebContents(web_contents());
     NavigateAndCommit(GURL(kTestURL));
   }
 
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index 88b3bf3..94ba3b7 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -64,6 +64,7 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/storage_partition.h"
 #include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui_controller.h"
@@ -86,6 +87,7 @@
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_filter.h"
 #include "net/url_request/url_request_http_job.h"
+#include "services/network/public/cpp/features.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
 #include "ui/compositor/compositor_switches.h"
 #include "ui/gl/gl_switches.h"
@@ -2085,12 +2087,23 @@
   https_test_server.ServeFilesFromSourceDirectory("chrome/test/data");
   ASSERT_TRUE(https_test_server.Start());
   GURL https_url = https_test_server.GetURL("localhost", "/devtools/image.png");
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::BindOnce(
-          AddHSTSHost,
-          base::RetainedRef(browser()->profile()->GetRequestContext()),
-          https_url.host()));
+  if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::BindOnce(
+            AddHSTSHost,
+            base::RetainedRef(browser()->profile()->GetRequestContext()),
+            https_url.host()));
+  } else {
+    base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000);
+    bool include_subdomains = false;
+    mojo::ScopedAllowSyncCallForTesting allow_sync_call;
+    content::StoragePartition* partition =
+        content::BrowserContext::GetDefaultStoragePartition(
+            browser()->profile());
+    partition->GetNetworkContext()->AddHSTSForTesting(https_url.host(), expiry,
+                                                      include_subdomains);
+  }
   ASSERT_TRUE(embedded_test_server()->Start());
 
   OpenDevToolsWindow(std::string(), false);
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
index fa880ab..3c5d791 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
@@ -44,7 +44,7 @@
 #include "components/cryptauth/cryptauth_enrollment_utils.h"
 #include "components/cryptauth/proto/cryptauth_api.pb.h"
 #include "components/cryptauth/remote_device.h"
-#include "components/cryptauth/secure_message_delegate.h"
+#include "components/cryptauth/secure_message_delegate_impl.h"
 #include "components/signin/core/account_id/account_id.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/user_manager/user_manager.h"
@@ -673,7 +673,8 @@
       easy_unlock_service->proximity_auth_client();
 
   permit_id_ = "permit://google.com/easyunlock/v1/" + client->GetAccountId();
-  secure_message_delegate_ = client->CreateSecureMessageDelegate();
+  secure_message_delegate_ =
+      cryptauth::SecureMessageDelegateImpl::Factory::NewInstance();
   std::vector<cryptauth::ExternalDeviceInfo> unlock_keys = GetUnlockKeys();
   expected_devices_count_ = unlock_keys.size();
 
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 20dab80..ca72276 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -804,6 +804,12 @@
 const char kHyperlinkAuditingName[] = "Hyperlink auditing";
 const char kHyperlinkAuditingDescription[] = "Sends hyperlink auditing pings.";
 
+const char kHorizontalTabSwitcherAndroidName[] =
+    "Enable horizontal tab switcher";
+const char kHorizontalTabSwitcherAndroidDescription[] =
+    "Changes the layout of the Android tab switcher so tabs scroll "
+    "horizontally instead of vertically.";
+
 const char kHostedAppQuitNotificationName[] =
     "Quit notification for hosted apps";
 const char kHostedAppQuitNotificationDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index c5b65ea..2fe3c70 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -501,6 +501,9 @@
 extern const char kHarfbuzzRendertextName[];
 extern const char kHarfbuzzRendertextDescription[];
 
+extern const char kHorizontalTabSwitcherAndroidName[];
+extern const char kHorizontalTabSwitcherAndroidDescription[];
+
 extern const char kViewsCastDialogName[];
 extern const char kViewsCastDialogDescription[];
 
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc
index e3f95123..d1333f95 100644
--- a/chrome/browser/infobars/infobars_browsertest.cc
+++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -577,11 +577,11 @@
   ShowAndVerifyUi();
 }
 
-IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_page_load_capping) {
+IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_automation) {
   ShowAndVerifyUi();
 }
 
-IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_automation) {
+IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_page_load_capping) {
   ShowAndVerifyUi();
 }
 
diff --git a/chrome/browser/infobars/mock_infobar_service.cc b/chrome/browser/infobars/mock_infobar_service.cc
index 6454c23c..c1d9eb5b 100644
--- a/chrome/browser/infobars/mock_infobar_service.cc
+++ b/chrome/browser/infobars/mock_infobar_service.cc
@@ -7,16 +7,20 @@
 #include "components/infobars/core/confirm_infobar_delegate.h"
 #include "components/infobars/core/infobar.h"
 
-MockInfoBarService::MockInfoBarService(content::WebContents* web_contents)
-    : InfoBarService(web_contents) {
+// static
+void MockInfoBarService::CreateForWebContents(
+    content::WebContents* web_contents) {
+  DCHECK(web_contents);
   void* user_data_key = UserDataKey();
   DCHECK(!web_contents->GetUserData(user_data_key));
-  web_contents->SetUserData(user_data_key, base::WrapUnique(this));
+  web_contents->SetUserData(
+      user_data_key, base::WrapUnique(new MockInfoBarService(web_contents)));
 }
 
-MockInfoBarService::~MockInfoBarService() = default;
-
 std::unique_ptr<infobars::InfoBar> MockInfoBarService::CreateConfirmInfoBar(
     std::unique_ptr<ConfirmInfoBarDelegate> delegate) {
   return std::make_unique<infobars::InfoBar>(std::move(delegate));
 }
+
+MockInfoBarService::MockInfoBarService(content::WebContents* web_contents)
+    : InfoBarService(web_contents) {}
diff --git a/chrome/browser/infobars/mock_infobar_service.h b/chrome/browser/infobars/mock_infobar_service.h
index 44faf037..c51e7ec 100644
--- a/chrome/browser/infobars/mock_infobar_service.h
+++ b/chrome/browser/infobars/mock_infobar_service.h
@@ -13,11 +13,15 @@
 // infobars.
 class MockInfoBarService : public InfoBarService {
  public:
-  explicit MockInfoBarService(content::WebContents* web_contents);
-  ~MockInfoBarService() override;
+  // Creates a MockInfoBarService and attaches it as the InfoBarService for
+  // |web_contents|.
+  static void CreateForWebContents(content::WebContents* web_contents);
 
   std::unique_ptr<infobars::InfoBar> CreateConfirmInfoBar(
       std::unique_ptr<ConfirmInfoBarDelegate> delegate) override;
+
+ private:
+  explicit MockInfoBarService(content::WebContents* web_contents);
 };
 
 #endif  // CHROME_BROWSER_INFOBARS_MOCK_INFOBAR_SERVICE_H_
diff --git a/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc b/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc
index 7e654d7..b029655 100644
--- a/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc
@@ -71,8 +71,8 @@
  protected:
   bool LaunchApprtcInstanceOnLocalhost(const std::string& port) {
     base::FilePath appengine_dev_appserver =
-        GetSourceDir().Append(
-            FILE_PATH_LITERAL("../google_appengine/dev_appserver.py"));
+        GetSourceDir().Append(FILE_PATH_LITERAL(
+            "out/apprtc/temp/google-cloud-sdk/bin/dev_appserver.py"));
     if (!base::PathExists(appengine_dev_appserver)) {
       LOG(ERROR) << "Missing appengine sdk at " <<
           appengine_dev_appserver.value() << ".\n" <<
@@ -88,10 +88,9 @@
       return false;
     }
     if (!base::PathExists(apprtc_dir.Append(FILE_PATH_LITERAL("app.yaml")))) {
-      LOG(ERROR) << "The AppRTC AppEngine app at " <<
-          apprtc_dir.value() << " appears to have not been built." <<
-          "This should have been done by webrtc.DEPS scripts which invoke " <<
-          "'grunt build' on AppRTC.";
+      LOG(ERROR) << "The AppRTC AppEngine app at " << apprtc_dir.value()
+                 << " appears to have not been built."
+                 << "This should have been done by webrtc.DEPS scripts.";
       return false;
     }
 
@@ -116,10 +115,10 @@
     // runhooks stage when webrtc.DEPS/build_apprtc_collider.py runs.
 #if defined(OS_WIN)
     base::FilePath collider_server = GetSourceDir().Append(
-        FILE_PATH_LITERAL("out/go-workspace/bin/collidermain.exe"));
+        FILE_PATH_LITERAL("out/collider/collidermain.exe"));
 #else
-    base::FilePath collider_server = GetSourceDir().Append(
-        FILE_PATH_LITERAL("out/go-workspace/bin/collidermain"));
+    base::FilePath collider_server =
+        GetSourceDir().Append(FILE_PATH_LITERAL("out/collider/collidermain"));
 #endif
     if (!base::PathExists(collider_server)) {
       LOG(ERROR) << "Missing Collider server binary at " <<
diff --git a/chrome/browser/net/trial_comparison_cert_verifier.cc b/chrome/browser/net/trial_comparison_cert_verifier.cc
index d77b9fb1..2b0a3ec 100644
--- a/chrome/browser/net/trial_comparison_cert_verifier.cc
+++ b/chrome/browser/net/trial_comparison_cert_verifier.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/location.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/task_scheduler/post_task.h"
 #include "chrome/browser/browser_process.h"
@@ -160,15 +161,38 @@
 
   void CompareTrialResults(int trial_result_error) {
     cert_verifier_ = nullptr;
-    bool trial_success = trial_result_error == primary_error_ &&
-                         CertVerifyResultEqual(trial_result_, primary_result_);
+    bool errors_equal = trial_result_error == primary_error_;
+    bool details_equal = CertVerifyResultEqual(trial_result_, primary_result_);
+    bool trial_success = errors_equal && details_equal;
 
     net_log_.EndEvent(net::NetLogEventType::TRIAL_CERT_VERIFIER_JOB,
                       base::BindRepeating(&TrialVerificationJobResultCallback,
                                           trial_success));
+
+    TrialComparisonResult result_code = kInvalid;
+    if (trial_success) {
+      result_code = kEqual;
+    } else if (errors_equal) {
+      if (primary_error_ == net::OK)
+        result_code = kBothValidDifferentDetails;
+      else
+        result_code = kBothErrorDifferentDetails;
+    } else if (primary_error_ == net::OK) {
+      result_code = kPrimaryValidSecondaryError;
+    } else {
+      result_code = kPrimaryErrorSecondaryValid;
+    }
+    UMA_HISTOGRAM_ENUMERATION("Net.CertVerifier_TrialComparisonResult",
+                              result_code);
+
     if (trial_success)
       return;
 
+    if (base::GetFieldTrialParamByFeatureAsBool(
+            features::kCertDualVerificationTrialFeature, "uma_only", false)) {
+      return;
+    }
+
     content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
         ->PostTask(FROM_HERE, base::BindOnce(&SendReport, profile_id_, params_,
                                              primary_result_, trial_result_));
diff --git a/chrome/browser/net/trial_comparison_cert_verifier.h b/chrome/browser/net/trial_comparison_cert_verifier.h
index 19a6f69..f7a05a7 100644
--- a/chrome/browser/net/trial_comparison_cert_verifier.h
+++ b/chrome/browser/net/trial_comparison_cert_verifier.h
@@ -19,6 +19,18 @@
 
 class NET_EXPORT TrialComparisonCertVerifier : public net::CertVerifier {
  public:
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
+  enum TrialComparisonResult {
+    kInvalid = 0,
+    kEqual = 1,
+    kPrimaryValidSecondaryError = 2,
+    kPrimaryErrorSecondaryValid = 3,
+    kBothValidDifferentDetails = 4,
+    kBothErrorDifferentDetails = 5,
+    kMaxValue = kBothErrorDifferentDetails
+  };
+
   TrialComparisonCertVerifier(
       void* profile_id,
       scoped_refptr<net::CertVerifyProc> primary_verify_proc,
diff --git a/chrome/browser/net/trial_comparison_cert_verifier_unittest.cc b/chrome/browser/net/trial_comparison_cert_verifier_unittest.cc
index 8a86fc5..6c80be0 100644
--- a/chrome/browser/net/trial_comparison_cert_verifier_unittest.cc
+++ b/chrome/browser/net/trial_comparison_cert_verifier_unittest.cc
@@ -296,6 +296,7 @@
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 0);
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
                                0);
+  histograms_.ExpectTotalCount("Net.CertVerifier_TrialComparisonResult", 0);
 }
 
 TEST_F(TrialComparisonCertVerifierTest, NotScoutOptIn) {
@@ -337,6 +338,7 @@
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 0);
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
                                0);
+  histograms_.ExpectTotalCount("Net.CertVerifier_TrialComparisonResult", 0);
 }
 
 TEST_F(TrialComparisonCertVerifierTest, FeatureDisabled) {
@@ -375,6 +377,7 @@
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 0);
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
                                0);
+  histograms_.ExpectTotalCount("Net.CertVerifier_TrialComparisonResult", 0);
 }
 
 TEST_F(TrialComparisonCertVerifierTest, SameResult) {
@@ -411,6 +414,8 @@
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1);
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
                                1);
+  histograms_.ExpectUniqueSample("Net.CertVerifier_TrialComparisonResult",
+                                 TrialComparisonCertVerifier::kEqual, 1);
 }
 
 TEST_F(TrialComparisonCertVerifierTest, Incognito) {
@@ -444,6 +449,7 @@
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 0);
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
                                0);
+  histograms_.ExpectTotalCount("Net.CertVerifier_TrialComparisonResult", 0);
 }
 
 TEST_F(TrialComparisonCertVerifierTest, PrimaryVerifierErrorSecondaryOk) {
@@ -510,6 +516,9 @@
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1);
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
                                1);
+  histograms_.ExpectUniqueSample(
+      "Net.CertVerifier_TrialComparisonResult",
+      TrialComparisonCertVerifier::kPrimaryErrorSecondaryValid, 1);
 }
 
 TEST_F(TrialComparisonCertVerifierTest, PrimaryVerifierOkSecondaryError) {
@@ -576,6 +585,9 @@
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1);
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
                                1);
+  histograms_.ExpectUniqueSample(
+      "Net.CertVerifier_TrialComparisonResult",
+      TrialComparisonCertVerifier::kPrimaryValidSecondaryError, 1);
 }
 
 TEST_F(TrialComparisonCertVerifierTest,
@@ -640,6 +652,9 @@
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1);
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
                                1);
+  histograms_.ExpectUniqueSample(
+      "Net.CertVerifier_TrialComparisonResult",
+      TrialComparisonCertVerifier::kBothValidDifferentDetails, 1);
 }
 
 TEST_F(TrialComparisonCertVerifierTest, BothVerifiersOkDifferentCertStatus) {
@@ -719,6 +734,9 @@
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1);
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
                                1);
+  histograms_.ExpectUniqueSample(
+      "Net.CertVerifier_TrialComparisonResult",
+      TrialComparisonCertVerifier::kBothValidDifferentDetails, 1);
 }
 
 TEST_F(TrialComparisonCertVerifierTest, Coalescing) {
@@ -804,6 +822,9 @@
   // Only one verification should be done by secondary verifier.
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
                                1);
+  histograms_.ExpectUniqueSample(
+      "Net.CertVerifier_TrialComparisonResult",
+      TrialComparisonCertVerifier::kPrimaryErrorSecondaryValid, 1);
 }
 
 TEST_F(TrialComparisonCertVerifierTest, CancelledDuringPrimaryVerification) {
@@ -874,6 +895,9 @@
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1);
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
                                1);
+  histograms_.ExpectUniqueSample(
+      "Net.CertVerifier_TrialComparisonResult",
+      TrialComparisonCertVerifier::kPrimaryErrorSecondaryValid, 1);
 }
 
 TEST_F(TrialComparisonCertVerifierTest, DeletedDuringPrimaryVerification) {
@@ -917,6 +941,7 @@
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 0);
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
                                0);
+  histograms_.ExpectTotalCount("Net.CertVerifier_TrialComparisonResult", 0);
 }
 
 TEST_F(TrialComparisonCertVerifierTest, DeletedDuringTrialVerification) {
@@ -971,4 +996,61 @@
   // Histograms for trial verifier should not be recorded.
   histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
                                0);
+  histograms_.ExpectTotalCount("Net.CertVerifier_TrialComparisonResult", 0);
+}
+
+TEST_F(TrialComparisonCertVerifierTest,
+       PrimaryVerifierOkSecondaryErrorUmaOnly) {
+  // Enable feature with uma_only flag.
+  scoped_feature_.reset();
+  scoped_feature_ = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_->InitAndEnableFeatureWithParameters(
+      features::kCertDualVerificationTrialFeature, {{"uma_only", "true"}});
+
+  net::CertVerifyResult primary_result;
+  primary_result.verified_cert = cert_chain_1_;
+  scoped_refptr<MockCertVerifyProc> verify_proc1 =
+      base::MakeRefCounted<MockCertVerifyProc>(net::OK, primary_result);
+
+  // Trial verifier returns an error status.
+  net::CertVerifyResult secondary_result;
+  secondary_result.cert_status = net::CERT_STATUS_REVOKED;
+  secondary_result.verified_cert = cert_chain_1_;
+  scoped_refptr<MockCertVerifyProc> verify_proc2 =
+      base::MakeRefCounted<MockCertVerifyProc>(net::ERR_CERT_REVOKED,
+                                               secondary_result);
+
+  TrialComparisonCertVerifier verifier(profile(), verify_proc1, verify_proc2);
+
+  net::CertVerifier::RequestParams params(
+      leaf_cert_1_, "127.0.0.1", 0 /* flags */,
+      std::string() /* ocsp_response */, {} /* additional_trust_anchors */);
+  net::CertVerifyResult result;
+  net::TestCompletionCallback callback;
+  std::unique_ptr<net::CertVerifier::Request> request;
+  int error =
+      verifier.Verify(params, nullptr /* crl_set */, &result,
+                      callback.callback(), &request, net::NetLogWithSource());
+  ASSERT_THAT(error, IsError(net::ERR_IO_PENDING));
+  EXPECT_TRUE(request);
+
+  error = callback.WaitForResult();
+  EXPECT_THAT(error, IsError(net::OK));
+
+  verify_proc2->WaitForVerifyCall();
+
+  // Wait for any tasks to finish.
+  content::RunAllTasksUntilIdle();
+
+  // Expect no report.
+  reporting_service_test_helper()->ExpectNoRequests(service());
+
+  // Should still have UMA logs.
+  histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency", 1);
+  histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialPrimary", 1);
+  histograms_.ExpectTotalCount("Net.CertVerifier_Job_Latency_TrialSecondary",
+                               1);
+  histograms_.ExpectUniqueSample(
+      "Net.CertVerifier_TrialComparisonResult",
+      TrialComparisonCertVerifier::kPrimaryValidSecondaryError, 1);
 }
diff --git a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
index 82f1e97a..2162265 100644
--- a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
+++ b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
@@ -177,14 +177,12 @@
   service->RegisterProvider(std::move(provider));
 }
 
-void RegisterPrefetchingObserver(ContentSuggestionsService* service,
-                                 Profile* profile) {
-  // The observer is always there, but the Prefetch Dispatcher will do nothing
-  // if the feature (or preference) is off.
-  offline_pages::SuggestedArticlesObserver* observer =
-      offline_pages::PrefetchServiceFactory::GetForBrowserContext(profile)
-          ->GetSuggestedArticlesObserver();
-  observer->SetContentSuggestionsServiceAndObserve(service);
+void RegisterWithPrefetching(ContentSuggestionsService* service,
+                             Profile* profile) {
+  // There's a circular dependency between ContentSuggestionsService and
+  // PrefetchService. This closes the circle.
+  offline_pages::PrefetchServiceFactory::GetForBrowserContext(profile)
+      ->SetContentSuggestionsService(service);
 }
 
 #endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
@@ -525,7 +523,7 @@
 
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
   RegisterRecentTabProviderIfEnabled(service, profile, offline_page_model);
-  RegisterPrefetchingObserver(service, profile);
+  RegisterWithPrefetching(service, profile);
 #endif
 
   return service;
diff --git a/chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc b/chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc
index 8b7f57cb7..b7f5d20d 100644
--- a/chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc
+++ b/chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc
@@ -13,11 +13,13 @@
 #include "base/sequenced_task_runner.h"
 #include "base/task_scheduler/post_task.h"
 #include "chrome/browser/download/download_service_factory.h"
+#include "chrome/browser/ntp_snippets/content_suggestions_service_factory.h"
 #include "chrome/browser/offline_pages/offline_page_model_factory.h"
 #include "chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.h"
 #include "chrome/browser/offline_pages/prefetch/prefetch_background_task_handler_impl.h"
 #include "chrome/browser/offline_pages/prefetch/prefetch_configuration_impl.h"
 #include "chrome/browser/offline_pages/prefetch/prefetch_instance_id_proxy.h"
+#include "chrome/browser/offline_pages/prefetch/thumbnail_fetcher_impl.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_constants.h"
@@ -99,13 +101,16 @@
   auto configuration =
       std::make_unique<PrefetchConfigurationImpl>(profile->GetPrefs());
 
+  auto thumbnail_fetcher = std::make_unique<ThumbnailFetcherImpl>();
+
   return new PrefetchServiceImpl(
       std::move(offline_metrics_collector), std::move(prefetch_dispatcher),
       std::move(prefetch_gcm_app_handler),
-      std::move(prefetch_network_request_factory), std::move(prefetch_store),
-      std::move(suggested_articles_observer), std::move(prefetch_downloader),
-      std::move(prefetch_importer), std::move(prefetch_background_task_handler),
-      std::move(configuration));
+      std::move(prefetch_network_request_factory), offline_page_model,
+      std::move(prefetch_store), std::move(suggested_articles_observer),
+      std::move(prefetch_downloader), std::move(prefetch_importer),
+      std::move(prefetch_background_task_handler), std::move(configuration),
+      std::move(thumbnail_fetcher));
 }
 
 }  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/prefetch/thumbnail_fetcher_impl.cc b/chrome/browser/offline_pages/prefetch/thumbnail_fetcher_impl.cc
new file mode 100644
index 0000000..a2f1fb7
--- /dev/null
+++ b/chrome/browser/offline_pages/prefetch/thumbnail_fetcher_impl.cc
@@ -0,0 +1,36 @@
+// Copyright 2018 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/offline_pages/prefetch/thumbnail_fetcher_impl.h"
+
+#include "components/ntp_snippets/content_suggestions_service.h"
+#include "components/offline_pages/core/client_id.h"
+#include "components/offline_pages/core/client_namespace_constants.h"
+
+namespace offline_pages {
+
+ThumbnailFetcherImpl::ThumbnailFetcherImpl() = default;
+ThumbnailFetcherImpl::~ThumbnailFetcherImpl() = default;
+
+void ThumbnailFetcherImpl::SetContentSuggestionsService(
+    ntp_snippets::ContentSuggestionsService* content_suggestions) {
+  DCHECK(!content_suggestions_);  // Called once.
+  content_suggestions_ = content_suggestions;
+}
+
+void ThumbnailFetcherImpl::FetchSuggestionImageData(
+    const ClientId& client_id,
+    ImageDataFetchedCallback callback) {
+  DCHECK(client_id.name_space == kSuggestedArticlesNamespace);
+  DCHECK(content_suggestions_);
+
+  content_suggestions_->FetchSuggestionImageData(
+      ntp_snippets::ContentSuggestion::ID(
+          ntp_snippets::Category::FromKnownCategory(
+              ntp_snippets::KnownCategories::ARTICLES),
+          client_id.id),
+      std::move(callback));
+}
+
+}  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/prefetch/thumbnail_fetcher_impl.h b/chrome/browser/offline_pages/prefetch/thumbnail_fetcher_impl.h
new file mode 100644
index 0000000..0db3371
--- /dev/null
+++ b/chrome/browser/offline_pages/prefetch/thumbnail_fetcher_impl.h
@@ -0,0 +1,38 @@
+// Copyright 2018 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_OFFLINE_PAGES_PREFETCH_THUMBNAIL_FETCHER_IMPL_H_
+#define CHROME_BROWSER_OFFLINE_PAGES_PREFETCH_THUMBNAIL_FETCHER_IMPL_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/prefetch/thumbnail_fetcher.h"
+
+namespace ntp_snippets {
+class ContentSuggestionsService;
+}
+
+namespace offline_pages {
+
+// Fetches thumbnails through ContentSuggestionsService.
+class ThumbnailFetcherImpl : public ThumbnailFetcher {
+ public:
+  ThumbnailFetcherImpl();
+  ~ThumbnailFetcherImpl() override;
+
+  void SetContentSuggestionsService(
+      ntp_snippets::ContentSuggestionsService* content_suggestions) override;
+
+  void FetchSuggestionImageData(const ClientId& client_id,
+                                ImageDataFetchedCallback callback) override;
+
+ private:
+  ntp_snippets::ContentSuggestionsService* content_suggestions_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(ThumbnailFetcherImpl);
+};
+
+}  // namespace offline_pages
+
+#endif  // CHROME_BROWSER_OFFLINE_PAGES_PREFETCH_THUMBNAIL_FETCHER_IMPL_H_
diff --git a/chrome/browser/offline_pages/prefetch/thumbnail_fetcher_impl_unittest.cc b/chrome/browser/offline_pages/prefetch/thumbnail_fetcher_impl_unittest.cc
new file mode 100644
index 0000000..cb794c1
--- /dev/null
+++ b/chrome/browser/offline_pages/prefetch/thumbnail_fetcher_impl_unittest.cc
@@ -0,0 +1,128 @@
+// Copyright 2018 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/offline_pages/prefetch/thumbnail_fetcher_impl.h"
+
+#include "base/test/bind_test_util.h"
+#include "base/test/mock_callback.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "components/ntp_snippets/category_rankers/fake_category_ranker.h"
+#include "components/ntp_snippets/content_suggestion.h"
+#include "components/ntp_snippets/content_suggestions_service.h"
+#include "components/ntp_snippets/logger.h"
+#include "components/ntp_snippets/mock_content_suggestions_provider.h"
+#include "components/offline_pages/core/client_id.h"
+#include "components/offline_pages/core/client_namespace_constants.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gmock_mutant.h"
+
+namespace offline_pages {
+namespace {
+using testing::_;
+const char kClientID1[] = "client-id-1";
+
+ntp_snippets::Category ArticlesCategory() {
+  return ntp_snippets::Category::FromKnownCategory(
+      ntp_snippets::KnownCategories::ARTICLES);
+}
+ntp_snippets::ContentSuggestion::ID SuggestionID1() {
+  return ntp_snippets::ContentSuggestion::ID(ArticlesCategory(), kClientID1);
+}
+
+class TestContentSuggestionsService
+    : public ntp_snippets::ContentSuggestionsService {
+ public:
+  explicit TestContentSuggestionsService(PrefService* pref_service)
+      : ContentSuggestionsService(
+            State::ENABLED,
+            /*identity_manager=*/nullptr,
+            /*history_service=*/nullptr,
+            /*large_icon_cache=*/nullptr,
+            pref_service,
+            std::make_unique<ntp_snippets::FakeCategoryRanker>(),
+            /*user_classifier=*/nullptr,
+            /*remote_suggestions_scheduler=*/nullptr,
+            std::make_unique<ntp_snippets::Logger>()) {}
+
+  ntp_snippets::MockContentSuggestionsProvider* MakeRegisteredMockProvider(
+      const std::vector<ntp_snippets::Category>& provided_categories) {
+    auto provider = std::make_unique<
+        testing::StrictMock<ntp_snippets::MockContentSuggestionsProvider>>(
+        this, provided_categories);
+    ntp_snippets::MockContentSuggestionsProvider* result = provider.get();
+    RegisterProvider(std::move(provider));
+    // Before fetching a suggestion thumbnail, the suggestion provider must
+    // have previously provided ContentSuggestionsService a suggestion.
+    ntp_snippets::ContentSuggestionsProvider::Observer* observer = this;
+    std::vector<ntp_snippets::ContentSuggestion> suggestions;
+    suggestions.emplace_back(SuggestionID1(), GURL("http://suggestion1"));
+    observer->OnNewSuggestions(result, ArticlesCategory(),
+                               std::move(suggestions));
+
+    return result;
+  }
+};
+
+class ThumbnailFetcherImplTest : public testing::Test {
+ public:
+  ~ThumbnailFetcherImplTest() override = default;
+
+  void SetUp() override {
+    ntp_snippets::ContentSuggestionsService::RegisterProfilePrefs(
+        pref_service_.registry());
+
+    content_suggestions_ =
+        std::make_unique<TestContentSuggestionsService>(&pref_service_);
+    suggestions_provider_ =
+        content_suggestions_->MakeRegisteredMockProvider({ArticlesCategory()});
+  }
+
+ protected:
+  TestContentSuggestionsService* content_suggestions() {
+    return content_suggestions_.get();
+  }
+  ntp_snippets::MockContentSuggestionsProvider* suggestions_provider() {
+    return suggestions_provider_;
+  }
+
+  void ExpectFetchThumbnail(const std::string& thumbnail_data) {
+    EXPECT_CALL(*suggestions_provider(),
+                FetchSuggestionImageDataMock(SuggestionID1(), _))
+        .WillOnce(
+            testing::Invoke(testing::CallbackToFunctor(base::BindRepeating(
+                [](const std::string& thumbnail_data,
+                   scoped_refptr<base::TestMockTimeTaskRunner> task_runner,
+                   const ntp_snippets::ContentSuggestion::ID& id,
+                   ntp_snippets::ImageDataFetchedCallback* callback) {
+                  task_runner->PostTask(
+                      FROM_HERE,
+                      base::BindOnce(std::move(*callback), thumbnail_data));
+                },
+                thumbnail_data, task_runner_))));
+  }
+
+  std::unique_ptr<TestContentSuggestionsService> content_suggestions_;
+  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_ =
+      new base::TestMockTimeTaskRunner;
+
+ private:
+  TestingPrefServiceSimple pref_service_;
+  ntp_snippets::MockContentSuggestionsProvider* suggestions_provider_;
+};
+
+TEST_F(ThumbnailFetcherImplTest, FetchSuggestionImageData) {
+  // Successfully fetch an image.
+  ThumbnailFetcherImpl fetcher;
+  fetcher.SetContentSuggestionsService(content_suggestions_.get());
+  ExpectFetchThumbnail("abcdefg");
+  base::MockCallback<ThumbnailFetcher::ImageDataFetchedCallback> callback;
+  EXPECT_CALL(callback, Run("abcdefg"));
+
+  fetcher.FetchSuggestionImageData(
+      ClientId(kSuggestedArticlesNamespace, kClientID1), callback.Get());
+  task_runner_->RunUntilIdle();
+}
+
+}  // namespace
+}  // namespace offline_pages
diff --git a/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer_unittest.cc
index 7f59b380..473180bb 100644
--- a/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/page_capping_page_load_metrics_observer_unittest.cc
@@ -31,16 +31,9 @@
     NavigateAndCommit(GURL(kTestURL));
   }
 
-  size_t InfoBarCount() {
-    // Don't show multiple infobars.
-    return infobar_service() ? infobar_service()->infobar_count() : 0;
-  }
+  size_t InfoBarCount() { return infobar_service()->infobar_count(); }
 
-  void RemoveAllInfoBars() {
-    // Don't show multiple infobars.
-    if (infobar_service())
-      infobar_service()->RemoveAllInfoBars(false);
-  }
+  void RemoveAllInfoBars() { infobar_service()->RemoveAllInfoBars(false); }
 
   InfoBarService* infobar_service() {
     return InfoBarService::FromWebContents(web_contents());
diff --git a/chrome/browser/previews/previews_infobar_delegate_unittest.cc b/chrome/browser/previews/previews_infobar_delegate_unittest.cc
index 9783fc4..e7bf64f8 100644
--- a/chrome/browser/previews/previews_infobar_delegate_unittest.cc
+++ b/chrome/browser/previews/previews_infobar_delegate_unittest.cc
@@ -25,7 +25,7 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/android/android_theme_resources.h"
-#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/infobars/mock_infobar_service.h"
 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h"
 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h"
 #include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h"
@@ -160,7 +160,7 @@
 
   void SetUp() override {
     PageLoadMetricsObserverTestHarness::SetUp();
-    InfoBarService::CreateForWebContents(web_contents());
+    MockInfoBarService::CreateForWebContents(web_contents());
     PreviewsInfoBarTabHelper::CreateForWebContents(web_contents());
     TestPreviewsWebContentsObserver::CreateForWebContents(web_contents());
 
@@ -220,12 +220,10 @@
                    base::Unretained(this)),
         previews_ui_service_.get());
 
-    InfoBarService* infobar_service =
-        InfoBarService::FromWebContents(web_contents());
-    EXPECT_EQ(1U, infobar_service->infobar_count());
+    EXPECT_EQ(1U, infobar_service()->infobar_count());
 
     return static_cast<PreviewsInfoBarDelegate*>(
-        infobar_service->infobar_at(0)->delegate());
+        infobar_service()->infobar_at(0)->delegate());
   }
 
   void EnableStalePreviewsTimestamp(
@@ -261,7 +259,7 @@
     tester_->ExpectBucketCount(kUMAPreviewsInfoBarTimestamp, expected_bucket,
                                1);
     // Dismiss the infobar.
-    InfoBarService::FromWebContents(web_contents())->RemoveAllInfoBars(false);
+    infobar_service()->RemoveAllInfoBars(false);
     PreviewsInfoBarTabHelper::FromWebContents(web_contents())
         ->set_displayed_preview_infobar(false);
   }
diff --git a/chrome/browser/previews/previews_infobar_tab_helper_unittest.cc b/chrome/browser/previews/previews_infobar_tab_helper_unittest.cc
index 7e32674..a8742a5 100644
--- a/chrome/browser/previews/previews_infobar_tab_helper_unittest.cc
+++ b/chrome/browser/previews/previews_infobar_tab_helper_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/infobars/mock_infobar_service.h"
 #include "chrome/browser/loader/chrome_navigation_data.h"
 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h"
 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h"
@@ -52,7 +52,7 @@
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
     offline_pages::OfflinePageTabHelper::CreateForWebContents(web_contents());
 #endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
-    InfoBarService::CreateForWebContents(web_contents());
+    MockInfoBarService::CreateForWebContents(web_contents());
     PreviewsInfoBarTabHelper::CreateForWebContents(web_contents());
     test_handle_ = content::NavigationHandle::CreateNavigationHandleForTesting(
         GURL(kTestUrl), main_rfh());
@@ -137,6 +137,10 @@
         ->SetNavigationData(test_handle_.get(), std::move(navigation_data));
   }
 
+  InfoBarService* infobar_service() {
+    return InfoBarService::FromWebContents(web_contents());
+  }
+
  protected:
   std::unique_ptr<data_reduction_proxy::DataReductionProxyTestContext>
       drp_test_context_;
@@ -155,9 +159,7 @@
   SimulateWillProcessResponse();
   CallDidFinishNavigation();
 
-  InfoBarService* infobar_service =
-      InfoBarService::FromWebContents(web_contents());
-  EXPECT_EQ(1U, infobar_service->infobar_count());
+  EXPECT_EQ(1U, infobar_service()->infobar_count());
   EXPECT_TRUE(infobar_tab_helper->displayed_preview_infobar());
 
   // Navigate to reset the displayed state.
@@ -177,9 +179,7 @@
   SimulateWillProcessResponse();
   CallDidFinishNavigation();
 
-  InfoBarService* infobar_service =
-      InfoBarService::FromWebContents(web_contents());
-  EXPECT_EQ(1U, infobar_service->infobar_count());
+  EXPECT_EQ(1U, infobar_service()->infobar_count());
   EXPECT_TRUE(infobar_tab_helper->displayed_preview_infobar());
 
   // Navigate to reset the displayed state.
@@ -199,9 +199,7 @@
   SimulateWillProcessResponse();
   CallDidFinishNavigation();
 
-  InfoBarService* infobar_service =
-      InfoBarService::FromWebContents(web_contents());
-  EXPECT_EQ(0U, infobar_service->infobar_count());
+  EXPECT_EQ(0U, infobar_service()->infobar_count());
   EXPECT_FALSE(infobar_tab_helper->displayed_preview_infobar());
 }
 
@@ -263,9 +261,7 @@
 
   CallDidFinishNavigation();
 
-  InfoBarService* infobar_service =
-      InfoBarService::FromWebContents(web_contents());
-  EXPECT_EQ(1U, infobar_service->infobar_count());
+  EXPECT_EQ(1U, infobar_service()->infobar_count());
   EXPECT_TRUE(infobar_tab_helper->displayed_preview_infobar());
 
   // Navigate to reset the displayed state.
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
index 841e97a..18ea996 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
@@ -200,7 +200,8 @@
   DCHECK(process_control->IsConnected());
   GetCloudPrintProxy().EnableCloudPrintProxyWithRobot(
       robot_auth_code, robot_email, user_email,
-      user_preferences->CreateDeepCopy());
+      std::move(*user_preferences->CreateDeepCopy()));
+
   // Assume the IPC worked.
   profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, user_email);
 }
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc b/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
index 3edbd44c2..48ef108 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
@@ -129,11 +129,10 @@
   void GetPrinters(GetPrintersCallback callback) override { NOTREACHED(); }
   void DisableCloudPrintProxy() override { disabled_ = true; }
 
-  void EnableCloudPrintProxyWithRobot(
-      const std::string& robot_auth_code,
-      const std::string& robot_email,
-      const std::string& user_email,
-      std::unique_ptr<base::DictionaryValue> user_settings) override {
+  void EnableCloudPrintProxyWithRobot(const std::string& robot_auth_code,
+                                      const std::string& robot_email,
+                                      const std::string& user_email,
+                                      base::Value user_settings) override {
     enabled_ = true;
   }
 
diff --git a/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc b/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc
index c050f0ff..e056de3a 100644
--- a/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc
+++ b/chrome/browser/printing/pdf_to_emf_converter_browsertest.cc
@@ -99,6 +99,19 @@
   PdfToEmfConverterBrowserTest() : test_data_dir_(GetTestDataDir()) {}
   ~PdfToEmfConverterBrowserTest() override = default;
 
+  void RunSinglePagePdfToPostScriptConverterTest(
+      const PdfRenderSettings& pdf_settings,
+      base::StringPiece input_filename,
+      base::StringPiece output_filename) {
+    ASSERT_TRUE(GetTestInput(input_filename));
+    ASSERT_TRUE(StartPdfConverter(pdf_settings, 1));
+    ASSERT_TRUE(GetPage(0));
+    // The output is PS encapsulated in EMF.
+    ASSERT_TRUE(GetPageExpectedEmfData(output_filename));
+    ComparePageEmfHeader();
+    ComparePageEmfPayload();
+  }
+
   bool GetTestInput(base::StringPiece filename) {
     base::ScopedAllowBlockingForTesting allow_blocking;
 
@@ -301,15 +314,8 @@
   const PdfRenderSettings pdf_settings(
       kLetter200DpiRect, gfx::Point(0, 0), k200DpiSize,
       /*autorotate=*/false, PdfRenderSettings::Mode::POSTSCRIPT_LEVEL2);
-  constexpr int kNumberOfPages = 1;
-
-  ASSERT_TRUE(GetTestInput("bug_767343.pdf"));
-  ASSERT_TRUE(StartPdfConverter(pdf_settings, kNumberOfPages));
-  ASSERT_TRUE(GetPage(0));
-  // The output is PS encapsulated in EMF.
-  ASSERT_TRUE(GetPageExpectedEmfData("bug_767343.emf"));
-  ComparePageEmfHeader();
-  ComparePageEmfPayload();
+  RunSinglePagePdfToPostScriptConverterTest(pdf_settings, "bug_767343.pdf",
+                                            "bug_767343.emf");
 }
 
 IN_PROC_BROWSER_TEST_F(PdfToEmfConverterBrowserTest,
@@ -317,15 +323,26 @@
   const PdfRenderSettings pdf_settings(
       kLetter200DpiRect, gfx::Point(0, 0), k200DpiSize,
       /*autorotate=*/false, PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3);
-  constexpr int kNumberOfPages = 1;
+  RunSinglePagePdfToPostScriptConverterTest(pdf_settings, "bug_767343.pdf",
+                                            "bug_767343.emf");
+}
 
-  ASSERT_TRUE(GetTestInput("bug_767343.pdf"));
-  ASSERT_TRUE(StartPdfConverter(pdf_settings, kNumberOfPages));
-  ASSERT_TRUE(GetPage(0));
-  // The output is PS encapsulated in EMF.
-  ASSERT_TRUE(GetPageExpectedEmfData("bug_767343.emf"));
-  ComparePageEmfHeader();
-  ComparePageEmfPayload();
+IN_PROC_BROWSER_TEST_F(PdfToEmfConverterBrowserTest,
+                       PostScriptLevel2WithNegativeSizedText) {
+  const PdfRenderSettings pdf_settings(
+      kLetter200DpiRect, gfx::Point(0, 0), k200DpiSize,
+      /*autorotate=*/false, PdfRenderSettings::Mode::POSTSCRIPT_LEVEL2);
+  RunSinglePagePdfToPostScriptConverterTest(pdf_settings, "bug_806746.pdf",
+                                            "bug_806746.emf");
+}
+
+IN_PROC_BROWSER_TEST_F(PdfToEmfConverterBrowserTest,
+                       PostScriptLevel3WithNegativeSizedText) {
+  const PdfRenderSettings pdf_settings(
+      kLetter200DpiRect, gfx::Point(0, 0), k200DpiSize,
+      /*autorotate=*/false, PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3);
+  RunSinglePagePdfToPostScriptConverterTest(pdf_settings, "bug_806746.pdf",
+                                            "bug_806746.emf");
 }
 
 }  // namespace printing
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index c9f770b..1165ba8 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -7,6 +7,15 @@
 
 assert(!is_ios, "Chromium/iOS shouldn't use anything in //chrome")
 
+if (closure_compile) {
+  group("closure_compile") {
+    deps = [
+      "engagement:closure_compile",
+      "md_bookmarks:closure_compile",
+    ]
+  }
+}
+
 grit("invalidations_resources") {
   source = "invalidations_resources.grd"
   defines = chrome_grit_defines
diff --git a/chrome/browser/resources/md_bookmarks/BUILD.gn b/chrome/browser/resources/md_bookmarks/BUILD.gn
index d1d84aa..166396b 100644
--- a/chrome/browser/resources/md_bookmarks/BUILD.gn
+++ b/chrome/browser/resources/md_bookmarks/BUILD.gn
@@ -1,4 +1,9 @@
+# Copyright 2018 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("../optimize_webui.gni")
+import("//third_party/closure_compiler/compile_js.gni")
 
 optimize_webui("build") {
   host = "bookmarks"
@@ -10,3 +15,239 @@
 
   deps = []
 }
+
+js_type_check("closure_compile") {
+  deps = [
+    ":actions",
+    ":api_listener",
+    ":app",
+    ":command_manager",
+    ":constants",
+    ":debouncer",
+    ":dialog_focus_manager",
+    ":dnd_chip",
+    ":dnd_manager",
+    ":edit_dialog",
+    ":folder_node",
+    ":item",
+    ":list",
+    ":mouse_focus_behavior",
+    ":reducers",
+    ":router",
+    ":store",
+    ":store_client",
+    ":toast_manager",
+    ":toolbar",
+    ":types",
+    ":util",
+  ]
+}
+
+js_library("actions") {
+  deps = [
+    ":types",
+    ":util",
+    "//ui/webui/resources/js:cr",
+  ]
+  externs_list = [ "$externs_path/chrome_extensions.js" ]
+}
+
+js_library("api_listener") {
+  deps = [
+    ":actions",
+    ":debouncer",
+    ":store",
+    ":util",
+    "//ui/webui/resources/js:cr",
+  ]
+  externs_list = [ "$externs_path/chrome_extensions.js" ]
+}
+
+js_library("app") {
+  deps = [
+    ":api_listener",
+    ":dnd_manager",
+    ":mouse_focus_behavior",
+    ":router",
+    ":store",
+    ":store_client",
+    "//ui/webui/resources/js:load_time_data",
+    "//ui/webui/resources/js/cr/ui:splitter",
+  ]
+  externs_list = [ "$externs_path/chrome_extensions.js" ]
+}
+
+js_library("command_manager") {
+  deps = [
+    ":api_listener",
+    ":dialog_focus_manager",
+    ":edit_dialog",
+    ":store_client",
+    ":toast_manager",
+    "//third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior:iron-a11y-keys-behavior-extracted",
+    "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
+    "//ui/webui/resources/cr_elements/cr_lazy_render:cr_lazy_render",
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js:load_time_data",
+    "//ui/webui/resources/js/cr/ui:command",
+  ]
+  externs_list = [ "$externs_path/bookmark_manager_private.js" ]
+}
+
+js_library("constants") {
+}
+
+js_library("debouncer") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("dialog_focus_manager") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("dnd_chip") {
+  deps = [
+    ":types",
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js:icon",
+  ]
+}
+
+js_library("dnd_manager") {
+  deps = [
+    ":api_listener",
+    ":debouncer",
+    ":dnd_chip",
+    ":folder_node",
+    ":store",
+    ":types",
+    ":util",
+    "//ui/webui/resources/js:cr",
+  ]
+  externs_list = [
+    "$externs_path/bookmark_manager_private.js",
+    "$externs_path/metrics_private.js",
+  ]
+}
+
+js_library("edit_dialog") {
+  deps = [
+    ":api_listener",
+    ":dialog_focus_manager",
+    ":types",
+    "//third_party/polymer/v1_0/components-chromium/paper-input:paper-input-extracted",
+    "//ui/webui/resources/js:assert",
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js:load_time_data",
+  ]
+  externs_list = [ "$externs_path/chrome_extensions.js" ]
+}
+
+js_library("folder_node") {
+  deps = [
+    ":actions",
+    ":command_manager",
+    ":store_client",
+    "//ui/webui/resources/js:load_time_data",
+  ]
+  externs_list = [ "$externs_path/chrome_extensions.js" ]
+}
+
+js_library("item") {
+  deps = [
+    ":actions",
+    ":command_manager",
+    ":store_client",
+    "//ui/webui/resources/js:icon",
+  ]
+  externs_list = [ "$externs_path/chrome_extensions.js" ]
+}
+
+js_library("list") {
+  deps = [
+    ":actions",
+    ":command_manager",
+    ":item",
+    ":store_client",
+    "//third_party/polymer/v1_0/components-chromium/iron-list:iron-list-extracted",
+    "//ui/webui/resources/js:load_time_data",
+  ]
+}
+
+js_library("mouse_focus_behavior") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("reducers") {
+  deps = [
+    ":actions",
+    ":types",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("router") {
+  deps = [
+    ":actions",
+    ":store_client",
+  ]
+}
+
+js_library("store") {
+  deps = [
+    ":reducers",
+    ":types",
+    "//ui/webui/resources/js:cr",
+  ]
+  externs_list = [ "$externs_path/chrome_extensions.js" ]
+}
+
+js_library("store_client") {
+  deps = [
+    ":store",
+    ":types",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("toast_manager") {
+  deps = [
+    "//third_party/polymer/v1_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer-extracted",
+    "//ui/webui/resources/js:cr",
+  ]
+}
+
+js_library("toolbar") {
+  deps = [
+    ":command_manager",
+    ":edit_dialog",
+    ":store_client",
+    "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
+    "//ui/webui/resources/cr_elements/cr_toolbar:cr_toolbar",
+  ]
+  externs_list = [
+    "$externs_path/bookmark_manager_private.js",
+    "$externs_path/chrome_extensions.js",
+  ]
+}
+
+js_library("types") {
+  deps = [
+    ":constants",
+  ]
+  externs_list = [ "$externs_path/chrome_extensions.js" ]
+}
+
+js_library("util") {
+  deps = [
+    ":types",
+    "//ui/webui/resources/js:cr",
+  ]
+  externs_list = [ "$externs_path/chrome_extensions.js" ]
+}
diff --git a/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp b/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
deleted file mode 100644
index bc67466..0000000
--- a/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
+++ /dev/null
@@ -1,234 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-{
-  'targets': [
-    {
-      'target_name': 'actions',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(EXTERNS_GYP):chrome_extensions',
-        'util',
-        'types',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi']
-    },
-    {
-      'target_name': 'api_listener',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(EXTERNS_GYP):chrome_extensions',
-        'actions',
-        'debouncer',
-        'store',
-        'util',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'app',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
-        '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:splitter',
-        '<(EXTERNS_GYP):chrome_extensions',
-        'api_listener',
-        'dnd_manager',
-        'mouse_focus_behavior',
-        'router',
-        'store',
-        'store_client',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'command_manager',
-      'dependencies': [
-        '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior/compiled_resources2.gyp:iron-a11y-keys-behavior-extracted',
-        '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu',
-        '<(DEPTH)/ui/webui/resources/cr_elements/cr_lazy_render/compiled_resources2.gyp:cr_lazy_render',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
-        '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:command',
-        '<(EXTERNS_GYP):bookmark_manager_private',
-        'api_listener',
-        'dialog_focus_manager',
-        'edit_dialog',
-        'store_client',
-        'toast_manager'
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'constants',
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi']
-    },
-    {
-      'target_name': 'debouncer',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'dialog_focus_manager',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'dnd_chip',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:icon',
-        'types',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'dnd_manager',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(EXTERNS_GYP):bookmark_manager_private',
-        '<(EXTERNS_GYP):metrics_private',
-        'api_listener',
-        'debouncer',
-        'dnd_chip',
-        'folder_node',
-        'store',
-        'types',
-        'util',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi']
-    },
-    {
-      'target_name': 'edit_dialog',
-      'dependencies': [
-        '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-input/compiled_resources2.gyp:paper-input-extracted',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
-        '<(EXTERNS_GYP):chrome_extensions',
-        'api_listener',
-        'dialog_focus_manager',
-        'types',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi']
-    },
-    {
-      'target_name': 'folder_node',
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
-        '<(EXTERNS_GYP):chrome_extensions',
-        'actions',
-        'command_manager',
-        'store_client',
-      ],
-    },
-    {
-      'target_name': 'item',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:icon',
-        '<(EXTERNS_GYP):chrome_extensions',
-        'actions',
-        'command_manager',
-        'store_client',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'list',
-      'dependencies': [
-        '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-list/compiled_resources2.gyp:iron-list-extracted',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
-        'actions',
-        'command_manager',
-        'item',
-        'store_client',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'mouse_focus_behavior',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'reducers',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        'actions',
-        'types',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'router',
-      'dependencies': [
-        'actions',
-        'store_client',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'store',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(EXTERNS_GYP):chrome_extensions',
-        'reducers',
-        'types',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi']
-    },
-    {
-      'target_name': 'store_client',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        'store',
-        'types',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi']
-    },
-    {
-      'target_name': 'toast_manager',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-a11y-announcer/compiled_resources2.gyp:iron-a11y-announcer-extracted',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'toolbar',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu',
-        '<(DEPTH)/ui/webui/resources/cr_elements/cr_toolbar/compiled_resources2.gyp:cr_toolbar',
-        '<(EXTERNS_GYP):bookmark_manager_private',
-        '<(EXTERNS_GYP):chrome_extensions',
-        'command_manager',
-        'edit_dialog',
-        'store_client',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'types',
-      'dependencies': [
-        '<(EXTERNS_GYP):chrome_extensions',
-        'constants',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi']
-    },
-    {
-      'target_name': 'util',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(EXTERNS_GYP):chrome_extensions',
-        'types',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi']
-    }
-  ]
-}
diff --git a/chrome/browser/resources/settings/reset_page/reset_page.html b/chrome/browser/resources/settings/reset_page/reset_page.html
index f86210f..e4ba695 100644
--- a/chrome/browser/resources/settings/reset_page/reset_page.html
+++ b/chrome/browser/resources/settings/reset_page/reset_page.html
@@ -25,17 +25,12 @@
     <style include="settings-shared"></style>
     <settings-animated-pages id="reset-pages" section="reset">
       <neon-animatable route-path="default">
-        <div class="settings-box first two-line" id="resetProfile"
+        <div class="settings-box first" id="resetProfile"
             on-click="onShowResetProfileDialog_" actionable>
-          <div class="start">
-            $i18n{resetTrigger}
-            <div class="secondary" id="resetProfileSecondary">
-              $i18n{resetTriggerDescription}
-            </div>
-          </div>
+          <div id="resetProfileTrigger" class="start">$i18n{resetTrigger}</div>
           <paper-icon-button-light class="subpage-arrow">
             <button id="resetProfileArrow" aria-label="$i18n{resetTrigger}"
-                aria-describedby="resetProfileSecondary"></button>
+                aria-describedby="resetProfileTrigger"></button>
           </paper-icon-button-light>
         </div>
         <!-- Keep a single instance of reset-profile-dialog on purpose, to
diff --git a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
index 30b25d1..d48cb08 100644
--- a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
+++ b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
@@ -41,7 +41,7 @@
         </paper-button>
         <paper-button class="action-button" on-click="onResetTap_"
             id="reset" disabled="[[clearingInProgress_]]">
-          $i18n{resetPageCommit}
+          $i18n{resetDialogCommit}
         </paper-button>
       </div>
       <div slot="footer">
diff --git a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js
index 5017b8257..d4899c2 100644
--- a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js
+++ b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js
@@ -65,7 +65,7 @@
       return loadTimeData.getStringF(
           'triggeredResetPageTitle', this.triggeredResetToolName_);
     }
-    return loadTimeData.getStringF('resetTrigger');
+    return loadTimeData.getStringF('resetDialogCommit');
   },
 
   /** @override */
diff --git a/chrome/browser/resources/settings/site_settings/edit_exception_dialog.html b/chrome/browser/resources/settings/site_settings/edit_exception_dialog.html
index 97de40c..ced08d7 100644
--- a/chrome/browser/resources/settings/site_settings/edit_exception_dialog.html
+++ b/chrome/browser/resources/settings/site_settings/edit_exception_dialog.html
@@ -23,7 +23,7 @@
             id="cancel">$i18n{cancel}</paper-button>
         <paper-button id="actionButton" class="action-button"
             on-click="onActionButtonTap_" disabled="[[invalid_]]">
-          $i18n{edit}
+          $i18n{save}
         </paper-button>
       </div>
     </cr-dialog>
diff --git a/chrome/browser/rlz/chrome_rlz_tracker_delegate.cc b/chrome/browser/rlz/chrome_rlz_tracker_delegate.cc
index c22de9e..fd274a5 100644
--- a/chrome/browser/rlz/chrome_rlz_tracker_delegate.cc
+++ b/chrome/browser/rlz/chrome_rlz_tracker_delegate.cc
@@ -36,6 +36,11 @@
 #include "chrome/installer/util/google_update_settings.h"
 #endif
 
+#if defined(OS_CHROMEOS)
+#include "base/command_line.h"
+#include "chromeos/chromeos_switches.h"
+#endif
+
 ChromeRLZTrackerDelegate::ChromeRLZTrackerDelegate() {}
 
 ChromeRLZTrackerDelegate::~ChromeRLZTrackerDelegate() {}
@@ -44,11 +49,23 @@
 void ChromeRLZTrackerDelegate::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
 #if BUILDFLAG(ENABLE_RLZ)
+  int rlz_ping_delay_seconds = 90;
 #if defined(OS_CHROMEOS)
-  registry->RegisterIntegerPref(prefs::kRlzPingDelaySeconds, 24 * 3600);
-#else
-  registry->RegisterIntegerPref(prefs::kRlzPingDelaySeconds, 90);
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kRlzPingDelay)) {
+    // Use a switch for overwriting the default delay because it doesn't seem
+    // possible to manually override the Preferences file on Chrome OS: the file
+    // is already loaded into memory by the time you modify it and any changes
+    // made get overwritten by Chrome.
+    rlz_ping_delay_seconds =
+        std::stoi(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+            chromeos::switches::kRlzPingDelay));
+  } else {
+    rlz_ping_delay_seconds = 24 * 3600;
+  }
 #endif
+  registry->RegisterIntegerPref(prefs::kRlzPingDelaySeconds,
+                                rlz_ping_delay_seconds);
 #endif
 }
 
diff --git a/chrome/browser/service_process/service_process_control_browsertest.cc b/chrome/browser/service_process/service_process_control_browsertest.cc
index debda7b..8dbb53e 100644
--- a/chrome/browser/service_process/service_process_control_browsertest.cc
+++ b/chrome/browser/service_process/service_process_control_browsertest.cc
@@ -194,7 +194,7 @@
   ServiceProcessControl::GetInstance()->remote_interfaces().GetInterface(
       &cloud_print_proxy);
   cloud_print_proxy->EnableCloudPrintProxyWithRobot(
-      "", "", "", std::make_unique<base::DictionaryValue>());
+      "", "", "", base::Value(base::Value::Type::DICTIONARY));
 
   ServiceProcessControl::GetInstance()->remote_interfaces().GetInterface(
       &cloud_print_proxy);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index e402752..30a3c08 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3474,8 +3474,6 @@
       "app_list/app_list_syncable_service.h",
       "app_list/app_list_syncable_service_factory.cc",
       "app_list/app_list_syncable_service_factory.h",
-      "app_list/app_list_view_delegate.cc",
-      "app_list/app_list_view_delegate.h",
       "app_list/chrome_app_list_item.cc",
       "app_list/chrome_app_list_item.h",
       "app_list/chrome_app_list_model_updater.cc",
diff --git a/chrome/browser/ui/app_list/app_list_client_impl.cc b/chrome/browser/ui/app_list/app_list_client_impl.cc
index a72656ba..608339d 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl.cc
+++ b/chrome/browser/ui/app_list/app_list_client_impl.cc
@@ -4,30 +4,48 @@
 
 #include "chrome/browser/ui/app_list/app_list_client_impl.h"
 
+#include <stddef.h>
+
 #include <utility>
+#include <vector>
 
 #include "ash/public/cpp/menu_utils.h"
 #include "ash/public/interfaces/constants.mojom.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
 #include "chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
 #include "chrome/browser/ui/app_list/app_list_model_updater.h"
 #include "chrome/browser/ui/app_list/app_list_service_impl.h"
-#include "chrome/browser/ui/app_list/app_list_view_delegate.h"
+#include "chrome/browser/ui/app_list/app_list_syncable_service.h"
+#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
+#include "chrome/browser/ui/app_list/app_sync_ui_state_watcher.h"
 #include "chrome/browser/ui/app_list/search/search_controller.h"
+#include "chrome/browser/ui/app_list/search/search_controller_factory.h"
+#include "chrome/browser/ui/app_list/search/search_resource_manager.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "content/public/common/service_manager_connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/base/models/menu_model.h"
+#include "ui/display/types/display_constants.h"
 #include "ui/gfx/geometry/rect.h"
 
-AppListClientImpl::AppListClientImpl() : binding_(this) {
+AppListClientImpl::AppListClientImpl()
+    : template_url_service_observer_(this),
+      binding_(this),
+      weak_ptr_factory_(this) {
+  // Bind this to the AppListController in Ash.
   content::ServiceManagerConnection::GetForProcess()
       ->GetConnector()
       ->BindInterface(ash::mojom::kServiceName, &app_list_controller_);
   ash::mojom::AppListClientPtr client;
   binding_.Bind(mojo::MakeRequest(&client));
   app_list_controller_->SetClient(std::move(client));
+
   AppListServiceImpl::GetInstance()->SetAppListControllerAndClient(
       app_list_controller_.get(), this);
 }
@@ -35,49 +53,65 @@
 AppListClientImpl::~AppListClientImpl() = default;
 
 void AppListClientImpl::StartSearch(const base::string16& raw_query) {
-  if (GetViewDelegate()->search_controller_) {
-    GetViewDelegate()->search_controller_->Start(raw_query);
-    GetViewDelegate()->controller_->OnSearchStarted();
+  if (search_controller_) {
+    search_controller_->Start(raw_query);
+    controller_delegate_->OnSearchStarted();
   }
 }
 
 void AppListClientImpl::OpenSearchResult(const std::string& result_id,
                                          int event_flags) {
-  GetViewDelegate()->OpenSearchResult(result_id, event_flags);
+  if (!model_updater_)
+    return;
+  app_list::SearchResult* result = model_updater_->FindSearchResult(result_id);
+  if (result)
+    search_controller_->OpenResult(result, event_flags);
 }
 
 void AppListClientImpl::InvokeSearchResultAction(const std::string& result_id,
                                                  int action_index,
                                                  int event_flags) {
-  GetViewDelegate()->InvokeSearchResultAction(result_id, action_index,
-                                              event_flags);
+  if (!model_updater_)
+    return;
+  app_list::SearchResult* result = model_updater_->FindSearchResult(result_id);
+  if (result)
+    search_controller_->InvokeResultAction(result, action_index, event_flags);
 }
 
 void AppListClientImpl::ViewClosing() {
-  GetViewDelegate()->ViewClosing();
+  controller_delegate_->SetAppListDisplayId(display::kInvalidDisplayId);
 }
 
 void AppListClientImpl::ViewShown(int64_t display_id) {
-  GetViewDelegate()->ViewShown(display_id);
+  if (model_updater_) {
+    base::RecordAction(base::UserMetricsAction("Launcher_Show"));
+    base::UmaHistogramSparse("Apps.AppListBadgedAppsCount",
+                             model_updater_->BadgedItemCount());
+  }
+  controller_delegate_->SetAppListDisplayId(display_id);
 }
 
 void AppListClientImpl::ActivateItem(const std::string& id, int event_flags) {
-  GetViewDelegate()->model_updater_->ActivateChromeItem(id, event_flags);
+  if (!model_updater_)
+    return;
+  model_updater_->ActivateChromeItem(id, event_flags);
 }
 
 void AppListClientImpl::GetContextMenuModel(
     const std::string& id,
     GetContextMenuModelCallback callback) {
-  ui::MenuModel* menu =
-      GetViewDelegate()->model_updater_->GetContextMenuModel(id);
+  if (!model_updater_)
+    return;
+  ui::MenuModel* menu = model_updater_->GetContextMenuModel(id);
   std::move(callback).Run(ash::menu_utils::GetMojoMenuItemsFromModel(menu));
 }
 
 void AppListClientImpl::ContextMenuItemSelected(const std::string& id,
                                                 int command_id,
                                                 int event_flags) {
-  GetViewDelegate()->model_updater_->ContextMenuItemSelected(id, command_id,
-                                                             event_flags);
+  if (!model_updater_)
+    return;
+  model_updater_->ContextMenuItemSelected(id, command_id, event_flags);
 }
 
 void AppListClientImpl::OnAppListTargetVisibilityChanged(bool visible) {
@@ -106,22 +140,102 @@
 
 void AppListClientImpl::OnFolderCreated(
     ash::mojom::AppListItemMetadataPtr item) {
+  if (!model_updater_)
+    return;
   DCHECK(item->is_folder);
-  GetViewDelegate()->model_updater_->OnFolderCreated(std::move(item));
+  model_updater_->OnFolderCreated(std::move(item));
 }
 
 void AppListClientImpl::OnFolderDeleted(
     ash::mojom::AppListItemMetadataPtr item) {
+  if (!model_updater_)
+    return;
   DCHECK(item->is_folder);
-  GetViewDelegate()->model_updater_->OnFolderDeleted(std::move(item));
+  model_updater_->OnFolderDeleted(std::move(item));
 }
 
 void AppListClientImpl::OnItemUpdated(ash::mojom::AppListItemMetadataPtr item) {
-  GetViewDelegate()->model_updater_->OnItemUpdated(std::move(item));
+  if (!model_updater_)
+    return;
+  model_updater_->OnItemUpdated(std::move(item));
 }
 
-AppListViewDelegate* AppListClientImpl::GetViewDelegate() {
-  return AppListServiceImpl::GetInstance()->GetViewDelegate();
+void AppListClientImpl::UpdateProfile() {
+  Profile* profile = ProfileManager::GetActiveUserProfile();
+  app_list::AppListSyncableService* syncable_service =
+      app_list::AppListSyncableServiceFactory::GetForProfile(profile);
+  DCHECK(syncable_service);
+  SetProfile(profile);
+}
+
+void AppListClientImpl::SetProfile(Profile* new_profile) {
+  if (profile_ == new_profile)
+    return;
+
+  if (profile_) {
+    DCHECK(model_updater_);
+    model_updater_->SetActive(false);
+
+    search_resource_manager_.reset();
+    search_controller_.reset();
+    app_sync_ui_state_watcher_.reset();
+    model_updater_ = nullptr;
+  }
+
+  template_url_service_observer_.RemoveAll();
+
+  profile_ = new_profile;
+  if (!profile_)
+    return;
+
+  // If we are in guest mode, the new profile should be an incognito profile.
+  // Otherwise, this may later hit a check (same condition as this one) in
+  // Browser::Browser when opening links in a browser window (see
+  // http://crbug.com/460437).
+  DCHECK(!profile_->IsGuestSession() || profile_->IsOffTheRecord())
+      << "Guest mode must use incognito profile";
+
+  TemplateURLService* template_url_service =
+      TemplateURLServiceFactory::GetForProfile(profile_);
+  template_url_service_observer_.Add(template_url_service);
+
+  app_list::AppListSyncableService* syncable_service =
+      app_list::AppListSyncableServiceFactory::GetForProfile(profile_);
+  model_updater_ = syncable_service->GetModelUpdater();
+  model_updater_->SetActive(true);
+
+  app_sync_ui_state_watcher_ =
+      std::make_unique<AppSyncUIStateWatcher>(profile_, model_updater_);
+
+  SetUpSearchUI();
+  OnTemplateURLServiceChanged();
+
+  // Clear search query.
+  model_updater_->UpdateSearchBox(base::string16(),
+                                  false /* initiated_by_user */);
+}
+
+void AppListClientImpl::SetUpSearchUI() {
+  search_resource_manager_.reset(
+      new app_list::SearchResourceManager(profile_, model_updater_));
+
+  search_controller_ = app_list::CreateSearchController(
+      profile_, model_updater_, controller_delegate_);
+}
+
+void AppListClientImpl::OnTemplateURLServiceChanged() {
+  DCHECK(model_updater_);
+
+  TemplateURLService* template_url_service =
+      TemplateURLServiceFactory::GetForProfile(profile_);
+  const TemplateURL* default_provider =
+      template_url_service->GetDefaultSearchProvider();
+  const bool is_google =
+      default_provider &&
+      default_provider->GetEngineType(
+          template_url_service->search_terms_data()) == SEARCH_ENGINE_GOOGLE;
+
+  model_updater_->SetSearchEngineIsGoogle(is_google);
 }
 
 void AppListClientImpl::FlushMojoForTesting() {
diff --git a/chrome/browser/ui/app_list/app_list_client_impl.h b/chrome/browser/ui/app_list/app_list_client_impl.h
index fe48eaf3..4d5a8a4 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl.h
+++ b/chrome/browser/ui/app_list/app_list_client_impl.h
@@ -5,16 +5,33 @@
 #ifndef CHROME_BROWSER_UI_APP_LIST_APP_LIST_CLIENT_IMPL_H_
 #define CHROME_BROWSER_UI_APP_LIST_APP_LIST_CLIENT_IMPL_H_
 
+#include <stdint.h>
+
+#include <memory>
 #include <string>
 
 #include "ash/public/interfaces/app_list.mojom.h"
-#include "ash/public/interfaces/shelf.mojom.h"
-#include "chrome/browser/ui/app_list/chrome_app_list_model_updater.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/scoped_observer.h"
+#include "components/search_engines/template_url_service.h"
+#include "components/search_engines/template_url_service_observer.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
-class AppListViewDelegate;
+namespace app_list {
+class SearchController;
+class SearchResourceManager;
+}  // namespace app_list
 
-class AppListClientImpl : public ash::mojom::AppListClient {
+class AppListControllerDelegate;
+class AppListModelUpdater;
+class AppSyncUIStateWatcher;
+class Profile;
+
+class AppListClientImpl : public ash::mojom::AppListClient,
+                          public TemplateURLServiceObserver {
  public:
   AppListClientImpl();
   ~AppListClientImpl() override;
@@ -43,15 +60,48 @@
   void OnFolderDeleted(ash::mojom::AppListItemMetadataPtr item) override;
   void OnItemUpdated(ash::mojom::AppListItemMetadataPtr item) override;
 
+  // Associates this client with the current active user, called when this
+  // client is accessed.
+  void UpdateProfile();
+
+  void set_controller_delegate(AppListControllerDelegate* controller_delegate) {
+    controller_delegate_ = controller_delegate;
+  }
+
   // Flushes all pending mojo call to Ash for testing.
   void FlushMojoForTesting();
 
  private:
-  AppListViewDelegate* GetViewDelegate();
+  // Overridden from TemplateURLServiceObserver:
+  void OnTemplateURLServiceChanged() override;
+
+  // Configures the AppList for the given |profile|.
+  void SetProfile(Profile* profile);
+
+  // Updates the speech webview and start page for the current |profile_|.
+  void SetUpSearchUI();
+
+  // Unowned pointer to the controller delegate.
+  AppListControllerDelegate* controller_delegate_ = nullptr;
+  // Unowned pointer to the associated profile. May change if SetProfile is
+  // called.
+  Profile* profile_ = nullptr;
+  // Unowned pointer to the model updater owned by AppListSyncableService.
+  // Will change if |profile_| changes.
+  AppListModelUpdater* model_updater_ = nullptr;
+
+  std::unique_ptr<app_list::SearchResourceManager> search_resource_manager_;
+  std::unique_ptr<app_list::SearchController> search_controller_;
+  std::unique_ptr<AppSyncUIStateWatcher> app_sync_ui_state_watcher_;
+
+  ScopedObserver<TemplateURLService, AppListClientImpl>
+      template_url_service_observer_;
 
   mojo::Binding<ash::mojom::AppListClient> binding_;
   ash::mojom::AppListControllerPtr app_list_controller_;
 
+  base::WeakPtrFactory<AppListClientImpl> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(AppListClientImpl);
 };
 
diff --git a/chrome/browser/ui/app_list/app_list_controller_browsertest.cc b/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
index 3b59960..0411275e 100644
--- a/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
+++ b/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
 #include "chrome/browser/ui/app_list/app_list_model_updater.h"
-#include "chrome/browser/ui/app_list/app_list_service.h"
+#include "chrome/browser/ui/app_list/app_list_service_impl.h"
 #include "chrome/browser/ui/app_list/test/chrome_app_list_test_support.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -60,10 +60,12 @@
       .AppendASCII("platform_apps")
       .AppendASCII("minimal");
 
-  AppListService* service = AppListService::Get();
+  AppListServiceImpl* service = AppListServiceImpl::GetInstance();
   ASSERT_TRUE(service);
   AppListModelUpdater* model_updater = test::GetModelUpdater(service);
   ASSERT_TRUE(model_updater);
+  // Getting the AppListClient to associate it with the current profile.
+  ASSERT_TRUE(service->GetAppListClient());
 
   // Install the extension.
   const extensions::Extension* extension = InstallExtension(
diff --git a/chrome/browser/ui/app_list/app_list_service_impl.cc b/chrome/browser/ui/app_list/app_list_service_impl.cc
index 4641b05d..21a2098 100644
--- a/chrome/browser/ui/app_list/app_list_service_impl.cc
+++ b/chrome/browser/ui/app_list/app_list_service_impl.cc
@@ -17,8 +17,10 @@
 #include "base/strings/string16.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/app_list/app_list_client_impl.h"
-#include "chrome/browser/ui/app_list/app_list_view_delegate.h"
+#include "chrome/browser/ui/app_list/app_list_syncable_service.h"
+#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/session_util.h"
@@ -40,6 +42,7 @@
   app_list_controller_ = app_list_controller;
   controller_delegate_.SetAppListController(app_list_controller);
   app_list_client_ = app_list_client;
+  app_list_client_->set_controller_delegate(&controller_delegate_);
 }
 
 ash::mojom::AppListController* AppListServiceImpl::GetAppListController() {
@@ -53,12 +56,9 @@
              : nullptr;
 }
 
-AppListViewDelegate* AppListServiceImpl::GetViewDelegate() {
-  if (!view_delegate_)
-    view_delegate_.reset(new AppListViewDelegate(GetControllerDelegate()));
-  Profile* profile = Profile::FromBrowserContext(GetActiveBrowserContext());
-  view_delegate_->SetProfile(profile);
-  return view_delegate_.get();
+AppListClientImpl* AppListServiceImpl::GetAppListClient() {
+  app_list_client_->UpdateProfile();
+  return app_list_client_;
 }
 
 AppListControllerDelegate* AppListServiceImpl::GetControllerDelegate() {
diff --git a/chrome/browser/ui/app_list/app_list_service_impl.h b/chrome/browser/ui/app_list/app_list_service_impl.h
index f93794d..6246f086 100644
--- a/chrome/browser/ui/app_list/app_list_service_impl.h
+++ b/chrome/browser/ui/app_list/app_list_service_impl.h
@@ -17,7 +17,6 @@
 
 class AppListClientImpl;
 class AppListControllerDelegateImpl;
-class AppListViewDelegate;
 
 namespace app_list {
 class SearchModel;
@@ -35,11 +34,6 @@
 
   static AppListServiceImpl* GetInstance();
 
-  AppListViewDelegate* GetViewDelegate();
-
-  void RecordAppListLaunch();
-  static void RecordAppListAppLaunch();
-
   // AppListService overrides:
   Profile* GetCurrentAppListProfile() override;
   void Show() override;
@@ -67,6 +61,7 @@
 
   // Returns a pointer to control the app list views in ash.
   ash::mojom::AppListController* GetAppListController();
+  AppListClientImpl* GetAppListClient();
 
   // TODO(hejq): Search model migration is not done yet. Chrome still accesses
   //             it directly in non-mus+ash mode.
@@ -79,7 +74,6 @@
   std::string GetProfileName();
 
   PrefService* local_state_;
-  std::unique_ptr<AppListViewDelegate> view_delegate_;
 
   AppListControllerDelegateImpl controller_delegate_;
   ash::mojom::AppListController* app_list_controller_ = nullptr;
diff --git a/chrome/browser/ui/app_list/app_list_service_interactive_uitest.cc b/chrome/browser/ui/app_list/app_list_service_interactive_uitest.cc
index 5d8891c..966d716 100644
--- a/chrome/browser/ui/app_list/app_list_service_interactive_uitest.cc
+++ b/chrome/browser/ui/app_list/app_list_service_interactive_uitest.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ui/app_list/app_list_service.h"
 
-#include "chrome/browser/ui/app_list/app_list_client_impl.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
 
@@ -15,13 +14,12 @@
 
 // Show the app list, then dismiss it.
 IN_PROC_BROWSER_TEST_F(AppListServiceInteractiveTest, ShowAndDismiss) {
-  AppListClientImpl app_list_client;
   AppListService* service = AppListService::Get();
   ASSERT_FALSE(service->IsAppListVisible());
   service->Show();
-  app_list_client.FlushMojoForTesting();
+  service->FlushForTesting();
   ASSERT_TRUE(service->IsAppListVisible());
   service->DismissAppList();
-  app_list_client.FlushMojoForTesting();
+  service->FlushForTesting();
   ASSERT_FALSE(service->IsAppListVisible());
 }
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.cc b/chrome/browser/ui/app_list/app_list_syncable_service.cc
index 5321a43..ebd21a1 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.cc
@@ -445,7 +445,6 @@
 }
 
 AppListModelUpdater* AppListSyncableService::GetModelUpdater() {
-  DCHECK(IsInitialized());
   return model_updater_.get();
 }
 
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.cc b/chrome/browser/ui/app_list/app_list_view_delegate.cc
deleted file mode 100644
index 86e032d..0000000
--- a/chrome/browser/ui/app_list/app_list_view_delegate.cc
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright (c) 2012 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/app_list/app_list_view_delegate.h"
-
-#include <stddef.h>
-
-#include <utility>
-#include <vector>
-
-#include "ash/app_list/model/app_list_model.h"
-#include "ash/app_list/model/search/search_model.h"
-#include "ash/public/cpp/menu_utils.h"
-#include "base/command_line.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics.h"
-#include "build/build_config.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
-#include "chrome/browser/ui/app_list/app_list_model_updater.h"
-#include "chrome/browser/ui/app_list/app_list_syncable_service.h"
-#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
-#include "chrome/browser/ui/app_list/app_sync_ui_state_watcher.h"
-#include "chrome/browser/ui/app_list/search/search_controller.h"
-#include "chrome/browser/ui/app_list/search/search_controller_factory.h"
-#include "chrome/browser/ui/app_list/search/search_resource_manager.h"
-#include "chrome/browser/ui/apps/chrome_app_delegate.h"
-#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
-#include "chrome/browser/ui/chrome_pages.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/grit/theme_resources.h"
-#include "components/prefs/pref_service.h"
-#include "components/user_prefs/user_prefs.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/speech_recognition_session_preamble.h"
-#include "content/public/browser/web_contents.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/common/constants.h"
-#include "extensions/common/extension_set.h"
-#include "extensions/common/manifest_constants.h"
-#include "ui/app_list/app_list_switches.h"
-#include "ui/app_list/app_list_view_delegate_observer.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/display/types/display_constants.h"
-#include "ui/keyboard/keyboard_util.h"
-#include "ui/views/controls/webview/webview.h"
-
-AppListViewDelegate::AppListViewDelegate(AppListControllerDelegate* controller)
-    : controller_(controller),
-      profile_(nullptr),
-      model_updater_(nullptr),
-      template_url_service_observer_(this),
-      observer_binding_(this),
-      weak_ptr_factory_(this) {
-  CHECK(controller_);
-
-  registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
-                 content::NotificationService::AllSources());
-
-  ash::mojom::WallpaperObserverAssociatedPtrInfo ptr_info;
-  observer_binding_.Bind(mojo::MakeRequest(&ptr_info));
-  WallpaperControllerClient::Get()->AddObserver(std::move(ptr_info));
-}
-
-AppListViewDelegate::~AppListViewDelegate() {
-  // The destructor might not be called since the delegate is owned by a leaky
-  // singleton. This matches the shutdown work done in Observe() in response to
-  // chrome::NOTIFICATION_APP_TERMINATING, which may happen before this.
-  SetProfile(nullptr);
-}
-
-void AppListViewDelegate::SetProfile(Profile* new_profile) {
-  if (profile_ == new_profile)
-    return;
-
-  if (profile_) {
-    DCHECK(model_updater_);
-    model_updater_->SetActive(false);
-
-    search_resource_manager_.reset();
-    search_controller_.reset();
-    app_sync_ui_state_watcher_.reset();
-    model_updater_ = nullptr;
-  }
-
-  template_url_service_observer_.RemoveAll();
-
-  profile_ = new_profile;
-  if (!profile_)
-    return;
-
-  // If we are in guest mode, the new profile should be an incognito profile.
-  // Otherwise, this may later hit a check (same condition as this one) in
-  // Browser::Browser when opening links in a browser window (see
-  // http://crbug.com/460437).
-  DCHECK(!profile_->IsGuestSession() || profile_->IsOffTheRecord())
-      << "Guest mode must use incognito profile";
-
-  TemplateURLService* template_url_service =
-      TemplateURLServiceFactory::GetForProfile(profile_);
-  template_url_service_observer_.Add(template_url_service);
-
-  app_list::AppListSyncableService* syncable_service =
-      app_list::AppListSyncableServiceFactory::GetForProfile(profile_);
-  model_updater_ = syncable_service->GetModelUpdater();
-  model_updater_->SetActive(true);
-
-  // After |model_updater_| is initialized, make a GetWallpaperColors mojo call
-  // to set wallpaper colors for |model_updater_|.
-  WallpaperControllerClient::Get()->GetWallpaperColors(
-      base::Bind(&AppListViewDelegate::OnGetWallpaperColorsCallback,
-                 weak_ptr_factory_.GetWeakPtr()));
-
-  app_sync_ui_state_watcher_ =
-      std::make_unique<AppSyncUIStateWatcher>(profile_, model_updater_);
-
-  SetUpSearchUI();
-  OnTemplateURLServiceChanged();
-
-  // Clear search query.
-  model_updater_->UpdateSearchBox(base::string16(),
-                                  false /* initiated_by_user */);
-}
-
-void AppListViewDelegate::OnGetWallpaperColorsCallback(
-    const std::vector<SkColor>& colors) {
-  OnWallpaperColorsChanged(colors);
-}
-
-void AppListViewDelegate::SetUpSearchUI() {
-  search_resource_manager_.reset(
-      new app_list::SearchResourceManager(profile_, model_updater_));
-
-  search_controller_ =
-      app_list::CreateSearchController(profile_, model_updater_, controller_);
-}
-
-void AppListViewDelegate::OnWallpaperChanged(uint32_t image_id) {}
-
-void AppListViewDelegate::OnWallpaperColorsChanged(
-    const std::vector<SkColor>& prominent_colors) {
-  if (wallpaper_prominent_colors_ == prominent_colors)
-    return;
-
-  wallpaper_prominent_colors_ = prominent_colors;
-  for (auto& observer : observers_)
-    observer.OnWallpaperColorsChanged();
-}
-
-AppListModelUpdater* AppListViewDelegate::GetModelUpdater() {
-  return model_updater_;
-}
-
-app_list::AppListModel* AppListViewDelegate::GetModel() {
-  NOTREACHED();
-  return nullptr;
-}
-
-app_list::SearchModel* AppListViewDelegate::GetSearchModel() {
-  NOTREACHED();
-  return nullptr;
-}
-
-void AppListViewDelegate::StartSearch(const base::string16& raw_query) {
-  if (search_controller_) {
-    search_controller_->Start(raw_query);
-    controller_->OnSearchStarted();
-  }
-}
-
-void AppListViewDelegate::OpenSearchResult(const std::string& result_id,
-                                           int event_flags) {
-  app_list::SearchResult* result = model_updater_->FindSearchResult(result_id);
-  if (result)
-    search_controller_->OpenResult(result, event_flags);
-}
-
-void AppListViewDelegate::InvokeSearchResultAction(const std::string& result_id,
-                                                   int action_index,
-                                                   int event_flags) {
-  app_list::SearchResult* result = model_updater_->FindSearchResult(result_id);
-  if (result)
-    search_controller_->InvokeResultAction(result, action_index, event_flags);
-}
-
-void AppListViewDelegate::ViewShown(int64_t display_id) {
-  base::RecordAction(base::UserMetricsAction("Launcher_Show"));
-  base::UmaHistogramSparse("Apps.AppListBadgedAppsCount",
-                           model_updater_->BadgedItemCount());
-  controller_->SetAppListDisplayId(display_id);
-}
-
-void AppListViewDelegate::Dismiss() {
-  controller_->DismissView();
-}
-
-void AppListViewDelegate::ViewClosing() {
-  controller_->SetAppListDisplayId(display::kInvalidDisplayId);
-}
-
-void AppListViewDelegate::GetWallpaperProminentColors(
-    GetWallpaperProminentColorsCallback callback) {
-  std::move(callback).Run(wallpaper_prominent_colors_);
-}
-
-void AppListViewDelegate::ActivateItem(const std::string& id, int event_flags) {
-  model_updater_->ActivateChromeItem(id, event_flags);
-}
-
-void AppListViewDelegate::GetContextMenuModel(
-    const std::string& id,
-    GetContextMenuModelCallback callback) {
-  ui::MenuModel* menu = model_updater_->GetContextMenuModel(id);
-  std::move(callback).Run(ash::menu_utils::GetMojoMenuItemsFromModel(menu));
-}
-
-void AppListViewDelegate::ContextMenuItemSelected(const std::string& id,
-                                                  int command_id,
-                                                  int event_flags) {
-  model_updater_->ContextMenuItemSelected(id, command_id, event_flags);
-}
-
-void AppListViewDelegate::AddObserver(
-    app_list::AppListViewDelegateObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void AppListViewDelegate::RemoveObserver(
-    app_list::AppListViewDelegateObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-void AppListViewDelegate::OnTemplateURLServiceChanged() {
-  TemplateURLService* template_url_service =
-      TemplateURLServiceFactory::GetForProfile(profile_);
-  const TemplateURL* default_provider =
-      template_url_service->GetDefaultSearchProvider();
-  const bool is_google =
-      default_provider->GetEngineType(
-          template_url_service->search_terms_data()) == SEARCH_ENGINE_GOOGLE;
-
-  model_updater_->SetSearchEngineIsGoogle(is_google);
-}
-
-void AppListViewDelegate::Observe(int type,
-                                  const content::NotificationSource& source,
-                                  const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
-
-  SetProfile(nullptr);  // Ensures launcher page web contents are torn down.
-}
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.h b/chrome/browser/ui/app_list/app_list_view_delegate.h
deleted file mode 100644
index 0fc40ce..0000000
--- a/chrome/browser/ui/app_list/app_list_view_delegate.h
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (c) 2012 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_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
-#define CHROME_BROWSER_UI_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "ash/public/interfaces/wallpaper.mojom.h"
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/scoped_observer.h"
-#include "chrome/browser/ui/app_list/app_list_model_updater.h"
-#include "components/search_engines/template_url_service.h"
-#include "components/search_engines/template_url_service_observer.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#include "ui/app_list/app_list_view_delegate_observer.h"
-
-class AppListClientImpl;
-
-namespace app_list {
-class SearchController;
-class SearchResourceManager;
-}
-
-namespace content {
-struct SpeechRecognitionSessionPreamble;
-}
-
-class AppListControllerDelegate;
-class AppSyncUIStateWatcher;
-class Profile;
-
-class AppListViewDelegate : public app_list::AppListViewDelegate,
-                            public ash::mojom::WallpaperObserver,
-                            public content::NotificationObserver,
-                            public TemplateURLServiceObserver {
- public:
-  // Constructs Chrome's AppListViewDelegate with a NULL Profile.
-  // Does not take ownership of |controller|. TODO(tapted): It should.
-  explicit AppListViewDelegate(AppListControllerDelegate* controller);
-  ~AppListViewDelegate() override;
-
-  // Configure the AppList for the given |profile|.
-  void SetProfile(Profile* profile);
-  Profile* profile() { return profile_; }
-
-  // Gets the model updater.
-  AppListModelUpdater* GetModelUpdater();
-
-  // Overridden from app_list::AppListViewDelegate:
-  app_list::AppListModel* GetModel() override;
-  app_list::SearchModel* GetSearchModel() override;
-  void StartSearch(const base::string16& raw_query) override;
-  void OpenSearchResult(const std::string& result_id, int event_flags) override;
-  void InvokeSearchResultAction(const std::string& result_id,
-                                int action_index,
-                                int event_flags) override;
-  void ViewShown(int64_t display_id) override;
-  void Dismiss() override;
-  void ViewClosing() override;
-  void GetWallpaperProminentColors(
-      GetWallpaperProminentColorsCallback callback) override;
-  void ActivateItem(const std::string& id, int event_flags) override;
-  void GetContextMenuModel(const std::string& id,
-                           GetContextMenuModelCallback callback) override;
-  void ContextMenuItemSelected(const std::string& id,
-                               int command_id,
-                               int event_flags) override;
-  void AddObserver(app_list::AppListViewDelegateObserver* observer) override;
-  void RemoveObserver(app_list::AppListViewDelegateObserver* observer) override;
-
-  // Overridden from TemplateURLServiceObserver:
-  void OnTemplateURLServiceChanged() override;
-
- private:
-  // TODO(hejq): We'll merge AppListClientImpl and AppListViewDelegate, but not
-  //             now, since that'll change all interface calls.
-  friend AppListClientImpl;
-
-  // Callback for ash::mojom::GetWallpaperColors.
-  void OnGetWallpaperColorsCallback(const std::vector<SkColor>& colors);
-
-  // Updates the speech webview and start page for the current |profile_|.
-  void SetUpSearchUI();
-
-  // Overridden from ash::mojom::WallpaperObserver:
-  void OnWallpaperChanged(uint32_t image_id) override;
-  void OnWallpaperColorsChanged(
-      const std::vector<SkColor>& prominent_colors) override;
-
-  // Overridden from content::NotificationObserver:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
-  // Unowned pointer to the controller.
-  AppListControllerDelegate* controller_;
-  // Unowned pointer to the associated profile. May change if SetProfileByPath
-  // is called.
-  Profile* profile_;
-  // Unowned pointer to the model updater owned by AppListSyncableService.
-  // Will change if |profile_| changes.
-  AppListModelUpdater* model_updater_;
-
-  std::unique_ptr<app_list::SearchResourceManager> search_resource_manager_;
-  std::unique_ptr<app_list::SearchController> search_controller_;
-
-  std::unique_ptr<AppSyncUIStateWatcher> app_sync_ui_state_watcher_;
-
-  ScopedObserver<TemplateURLService, AppListViewDelegate>
-      template_url_service_observer_;
-
-  // Registers for NOTIFICATION_APP_TERMINATING to unload custom launcher pages.
-  content::NotificationRegistrar registrar_;
-
-  // The binding this instance uses to implement mojom::WallpaperObserver.
-  mojo::AssociatedBinding<ash::mojom::WallpaperObserver> observer_binding_;
-
-  std::vector<SkColor> wallpaper_prominent_colors_;
-
-  base::ObserverList<app_list::AppListViewDelegateObserver> observers_;
-
-  base::WeakPtrFactory<AppListViewDelegate> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppListViewDelegate);
-};
-
-#endif  // CHROME_BROWSER_UI_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
diff --git a/chrome/browser/ui/app_list/crostini/crostini_installer_view_browsertest.cc b/chrome/browser/ui/app_list/crostini/crostini_installer_view_browsertest.cc
index 0ea449c..2d06d74 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_installer_view_browsertest.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_installer_view_browsertest.cc
@@ -6,8 +6,8 @@
 
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/ui/app_list/app_list_client_impl.h"
 #include "chrome/browser/ui/app_list/app_list_service_impl.h"
-#include "chrome/browser/ui/app_list/app_list_view_delegate.h"
 #include "chrome/browser/ui/app_list/crostini/crostini_app_model_builder.h"
 #include "chrome/browser/ui/app_list/crostini/crostini_util.h"
 #include "chrome/browser/ui/app_list/test/chrome_app_list_test_support.h"
@@ -29,10 +29,10 @@
   // DialogBrowserTest:
   void ShowUi(const std::string& name) override {
     AppListServiceImpl* service = test::GetAppListServiceImpl();
-    AppListViewDelegate* view_delegate = service->GetViewDelegate();
+    AppListClientImpl* client = service->GetAppListClient();
     const std::string kCrostiniTerminalId =
         crx_file::id_util::GenerateId(kCrostiniTerminalAppName);
-    view_delegate->ActivateItem(kCrostiniTerminalId, 0);
+    client->ActivateItem(kCrostiniTerminalId, 0);
   }
 
   void SetUp() override {
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_web_contents.cc b/chrome/browser/ui/app_list/search/answer_card/answer_card_web_contents.cc
index 46e0d6d..be1c6b4 100644
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_web_contents.cc
+++ b/chrome/browser/ui/app_list/search/answer_card/answer_card_web_contents.cc
@@ -16,6 +16,7 @@
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/renderer_preferences.h"
 #include "net/http/http_response_headers.h"
@@ -181,7 +182,7 @@
   load_params.should_clear_history_list = true;
   web_contents_->GetController().LoadURLWithParams(load_params);
 
-  web_contents_->GetRenderViewHost()->EnableAutoResize(
+  web_contents_->GetRenderWidgetHostView()->EnableAutoResize(
       gfx::Size(1, 1), gfx::Size(INT_MAX, INT_MAX));
 }
 
diff --git a/chrome/browser/ui/cocoa/extensions/extension_view_mac.mm b/chrome/browser/ui/cocoa/extensions/extension_view_mac.mm
index e232ff9..1b80910 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_view_mac.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_view_mac.mm
@@ -63,7 +63,9 @@
                        ExtensionViewMac::kMinHeight);
     gfx::Size max_size(ExtensionViewMac::kMaxWidth,
                        ExtensionViewMac::kMaxHeight);
-    render_view_host()->EnableAutoResize(min_size, max_size);
+    extension_host_->host_contents()
+        ->GetRenderWidgetHostView()
+        ->EnableAutoResize(min_size, max_size);
   }
 }
 
diff --git a/chrome/browser/ui/libgtkui/nav_button_provider_gtk3.cc b/chrome/browser/ui/libgtkui/nav_button_provider_gtk3.cc
index 31a8087..6a09faec 100644
--- a/chrome/browser/ui/libgtkui/nav_button_provider_gtk3.cc
+++ b/chrome/browser/ui/libgtkui/nav_button_provider_gtk3.cc
@@ -213,7 +213,23 @@
     // is not scaled for the (unexpected) smaller button size, and the button's
     // edges appear cut off.  To fix this, manually set the background to scale
     // to the button size when it would have clipped.
-    if (GtkVersionCheck(3, 20)) {
+    //
+    // GTK's "contain" is unlike CSS's "contain".  In CSS, the image would only
+    // be downsized when it would have clipped.  In GTK, the image is always
+    // scaled to fit the drawing region (preserving aspect ratio).  Only add
+    // "contain" if clipping would occur.
+    cairo_pattern_t* cr_pattern = nullptr;
+    cairo_surface_t* cr_surface = nullptr;
+    gtk_style_context_get(button_context, button_state,
+                          GTK_STYLE_PROPERTY_BACKGROUND_IMAGE, &cr_pattern,
+                          nullptr);
+    if (cr_pattern &&
+        cairo_pattern_get_surface(cr_pattern, &cr_surface) ==
+            CAIRO_STATUS_SUCCESS &&
+        cr_surface &&
+        cairo_surface_get_type(cr_surface) == CAIRO_SURFACE_TYPE_IMAGE &&
+        (cairo_image_surface_get_width(cr_surface) > button_size_.width() ||
+         cairo_image_surface_get_height(cr_surface) > button_size_.height())) {
       ApplyCssToContext(button_context,
                         ".titlebutton { background-size: contain; }");
     }
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc b/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc
index e1b66216..8672a077 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc
@@ -39,6 +39,12 @@
   UpdateWithoutTabRestore();
 }
 
+content::WebContents* ChromeOmniboxEditController::GetWebContents() {

+  return nullptr;

+}

+

+void ChromeOmniboxEditController::UpdateWithoutTabRestore() {}
+
 ChromeOmniboxEditController::ChromeOmniboxEditController(
     CommandUpdater* command_updater)
     : command_updater_(command_updater) {}
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h b/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h
index f361392d..049c310 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h
@@ -25,11 +25,11 @@
   void OnInputInProgress(bool in_progress) override;
 
   // Returns the WebContents of the currently active tab.
-  virtual content::WebContents* GetWebContents() = 0;
+  virtual content::WebContents* GetWebContents();
 
   // Called when the the controller should update itself without restoring any
   // tab state.
-  virtual void UpdateWithoutTabRestore() = 0;
+  virtual void UpdateWithoutTabRestore();
 
   CommandUpdater* command_updater() { return command_updater_; }
   const CommandUpdater* command_updater() const { return command_updater_; }
diff --git a/chrome/browser/ui/page_info/page_info_unittest.cc b/chrome/browser/ui/page_info/page_info_unittest.cc
index 0edf29b..626dc1b2 100644
--- a/chrome/browser/ui/page_info/page_info_unittest.cc
+++ b/chrome/browser/ui/page_info/page_info_unittest.cc
@@ -18,7 +18,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
-#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/infobars/mock_infobar_service.h"
 #include "chrome/browser/ui/page_info/page_info_ui.h"
 #include "chrome/browser/usb/usb_chooser_context.h"
 #include "chrome/browser/usb/usb_chooser_context_factory.h"
@@ -117,7 +117,7 @@
     ASSERT_TRUE(cert_);
 
     TabSpecificContentSettings::CreateForWebContents(web_contents());
-    InfoBarService::CreateForWebContents(web_contents());
+    MockInfoBarService::CreateForWebContents(web_contents());
 
     // Setup mock ui.
     ResetMockUI();
diff --git a/chrome/browser/ui/views/chrome_views_delegate_chromeos.cc b/chrome/browser/ui/views/chrome_views_delegate_chromeos.cc
index 3fb7e0d1..1217576e 100644
--- a/chrome/browser/ui/views/chrome_views_delegate_chromeos.cc
+++ b/chrome/browser/ui/views/chrome_views_delegate_chromeos.cc
@@ -75,6 +75,12 @@
 views::NativeWidget* ChromeViewsDelegate::CreateNativeWidget(
     views::Widget::InitParams* params,
     views::internal::NativeWidgetDelegate* delegate) {
+  // The context should be associated with a root window. If the context has a
+  // null root window (e.g. the context window has no parent) it will trigger
+  // the fallback case below. https://crbug.com/828626 https://crrev.com/230793
+  if (params->context)
+    params->context = params->context->GetRootWindow();
+
   // Classic ash requires a parent or a context that it can use to look up a
   // root window to find a WindowParentingClient. Mash handles window parenting
   // inside ash, see ash::CreateAndParentTopLevelWindow().
diff --git a/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc b/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
index dcf1c5a..c3b443cd 100644
--- a/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
+++ b/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
@@ -15,6 +15,7 @@
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
 #include "ui/views/controls/webview/webview.h"
@@ -374,9 +375,9 @@
   }
 
   void ConstrainedDialogWebView::EnableAutoResize() {
-    content::RenderViewHost* render_view_host =
-        GetWebContents()->GetRenderViewHost();
-    render_view_host->EnableAutoResize(min_size_, max_size_);
+    content::RenderWidgetHostView* render_widget_host_view =
+        GetWebContents()->GetRenderWidgetHostView();
+    render_widget_host_view->EnableAutoResize(min_size_, max_size_);
   }
 
 }  // namespace
diff --git a/chrome/browser/ui/views/extensions/extension_view_views.cc b/chrome/browser/ui/views/extensions/extension_view_views.cc
index 9e01306..c78743f 100644
--- a/chrome/browser/ui/views/extensions/extension_view_views.cc
+++ b/chrome/browser/ui/views/extensions/extension_view_views.cc
@@ -88,7 +88,7 @@
     content::RenderViewHost* render_view_host) {
   extensions::ViewType host_type = host_->extension_host_type();
   if (host_type == extensions::VIEW_TYPE_EXTENSION_POPUP) {
-    host_->render_view_host()->EnableAutoResize(
+    host_->host_contents()->GetRenderWidgetHostView()->EnableAutoResize(
         gfx::Size(ExtensionPopup::kMinWidth, ExtensionPopup::kMinHeight),
         gfx::Size(ExtensionPopup::kMaxWidth, ExtensionPopup::kMaxHeight));
   }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index 4290000d..5688b012 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -112,6 +112,12 @@
                                     const gfx::FontList& font_list);
   ~OmniboxSeparatedLineView() override;
 
+  views::ImageView* icon() { return icon_view_; }
+  views::ImageView* image() { return image_view_; }
+  OmniboxTextView* content() { return content_view_; }
+  OmniboxTextView* description() { return description_view_; }
+  OmniboxTextView* separator() { return separator_view_; }
+
   void OnMatchUpdate(const AutocompleteMatch& match);
   void OnHighlightUpdate(const AutocompleteMatch& match);
 
@@ -206,26 +212,17 @@
       font_height_(std::max(
           font_list.GetHeight(),
           font_list.DeriveWithWeight(gfx::Font::Weight::BOLD).GetHeight())),
-      animation_(new gfx::SlideAnimation(this)),
-      suggestion_icon_view_(AddOmniboxImageView()),
-      suggestion_image_view_(AddOmniboxImageView()),
-      suggestion_content_view_(AddOmniboxTextView(font_list)),
-      suggestion_description_view_(AddOmniboxTextView(font_list)),
-      suggestion_separator_view_(AddOmniboxTextView(font_list)),
-      keyword_icon_view_(AddOmniboxImageView()),
-      keyword_content_view_(AddOmniboxTextView(font_list)),
-      keyword_description_view_(AddOmniboxTextView(font_list)),
-      keyword_separator_view_(AddOmniboxTextView(font_list)) {
+      animation_(new gfx::SlideAnimation(this)) {
   CHECK_GE(model_index, 0);
 
   AddChildView(suggestion_view_ = new OmniboxSuggestionView(this, font_list));
   AddChildView(keyword_view_ = new OmniboxSeparatedLineView(this, font_list));
 
-  keyword_icon_view_->EnableCanvasFlippingForRTLUI(true);
-  keyword_icon_view_->SetImage(gfx::CreateVectorIcon(
+  keyword_view_->icon()->EnableCanvasFlippingForRTLUI(true);
+  keyword_view_->icon()->SetImage(gfx::CreateVectorIcon(
       omnibox::kKeywordSearchIcon, GetLayoutConstant(LOCATION_BAR_ICON_SIZE),
       GetColor(OmniboxPart::RESULTS_ICON)));
-  keyword_icon_view_->SizeToPreferredSize();
+  keyword_view_->icon()->SizeToPreferredSize();
 }
 
 OmniboxResultView::~OmniboxResultView() {}
@@ -241,12 +238,13 @@
   suggestion_view_->OnMatchUpdate(match_);
   keyword_view_->OnMatchUpdate(match_);
 
-  suggestion_image_view_->SetVisible(false);  // Until SetAnswerImage is called.
-  keyword_icon_view_->SetVisible(match_.associated_keyword.get());
+  suggestion_view_->image()->SetVisible(
+      false);  // Until SetAnswerImage is called.
+  keyword_view_->icon()->SetVisible(match_.associated_keyword.get());
 
   if (OmniboxFieldTrial::InTabSwitchSuggestionWithButtonTrial() &&
       match.type == AutocompleteMatchType::TAB_SEARCH &&
-      !keyword_icon_view_->visible()) {
+      !keyword_view_->icon()->visible()) {
     suggestion_tab_switch_button_ =
         std::make_unique<OmniboxTabSwitchButton>(this, GetTextHeight());
     suggestion_tab_switch_button_->set_owned_by_client();
@@ -284,36 +282,37 @@
   //       SetMatch() once (rather than repeatedly, as happens here). There may
   //       be an optimization opportunity here.
   // TODO(dschuyler): determine whether to optimize the color changes.
-  suggestion_icon_view_->SetImage(GetIcon().ToImageSkia());
-  keyword_icon_view_->SetImage(gfx::CreateVectorIcon(
+  suggestion_view_->icon()->SetImage(GetIcon().ToImageSkia());
+  keyword_view_->icon()->SetImage(gfx::CreateVectorIcon(
       omnibox::kKeywordSearchIcon, GetLayoutConstant(LOCATION_BAR_ICON_SIZE),
       GetColor(OmniboxPart::RESULTS_ICON)));
 
   if (match_.answer) {
-    suggestion_content_view_->SetText(match_.answer->first_line());
-    suggestion_description_view_->SetText(match_.answer->second_line());
+    suggestion_view_->content()->SetText(match_.answer->first_line());
+    suggestion_view_->description()->SetText(match_.answer->second_line());
   } else {
-    suggestion_content_view_->SetText(match_.contents, match_.contents_class);
-    suggestion_description_view_->SetText(match_.description,
-                                          match_.description_class);
+    suggestion_view_->content()->SetText(match_.contents,
+                                         match_.contents_class);
+    suggestion_view_->description()->SetText(match_.description,
+                                             match_.description_class);
   }
 
   const base::string16& separator =
       l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR);
-  suggestion_separator_view_->SetText(separator);
-  suggestion_separator_view_->Dim();
-  keyword_separator_view_->SetText(separator);
-  keyword_separator_view_->Dim();
+  suggestion_view_->separator()->SetText(separator);
+  suggestion_view_->separator()->Dim();
+  keyword_view_->separator()->SetText(separator);
+  keyword_view_->separator()->Dim();
 
   AutocompleteMatch* keyword_match = match_.associated_keyword.get();
-  keyword_content_view_->SetVisible(keyword_match);
-  keyword_description_view_->SetVisible(keyword_match);
+  keyword_view_->content()->SetVisible(keyword_match);
+  keyword_view_->description()->SetVisible(keyword_match);
   if (keyword_match) {
-    keyword_content_view_->SetText(keyword_match->contents,
-                                   keyword_match->contents_class);
-    keyword_description_view_->SetText(keyword_match->description,
-                                       keyword_match->description_class);
-    keyword_description_view_->Dim();
+    keyword_view_->content()->SetText(keyword_match->contents,
+                                      keyword_match->contents_class);
+    keyword_view_->description()->SetText(keyword_match->description,
+                                          keyword_match->description_class);
+    keyword_view_->description()->Dim();
   }
 
   // TODO(dschuyler): without this Layout call the text will shift slightly when
@@ -348,14 +347,19 @@
 }
 
 void OmniboxResultView::SetAnswerImage(const gfx::ImageSkia& image) {
-  suggestion_image_view_->SetImage(image);
-  suggestion_image_view_->SetVisible(true);
+  suggestion_view_->image()->SetImage(image);
+  suggestion_view_->image()->SetVisible(true);
   Layout();
   SchedulePaint();
 }
 
-void OmniboxResultView::OpenMatch(WindowOpenDisposition disposition) {
-  model_->OpenMatch(model_index_, disposition);
+////////////////////////////////////////////////////////////////////////////////
+// views::ButtonListener overrides:
+
+// |button| is the tab switch button.
+void OmniboxResultView::ButtonPressed(views::Button* button,
+                                      const ui::Event& event) {
+  OpenMatch(WindowOpenDisposition::SWITCH_TO_TAB);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -479,15 +483,15 @@
   const gfx::Image icon = GetIcon();
   int icon_width = icon.Width();
   int answer_icon_size =
-      suggestion_image_view_->visible()
-          ? suggestion_image_view_->height() + kAnswerIconToTextPadding
+      suggestion_view_->image()->visible()
+          ? suggestion_view_->image()->height() + kAnswerIconToTextPadding
           : 0;
   // TODO(dschuyler): The GetIconAlignmentOffset() is applied an extra time to
   // match the math in Layout(). This seems like a (minor) mistake.
   int deduction = (GetIconAlignmentOffset() * 2) + icon_width +
                   (horizontal_padding * 3) + answer_icon_size;
   int description_width = std::max(width() - deduction, 0);
-  return suggestion_description_view_->GetHeightForWidth(description_width) +
+  return suggestion_view_->description()->GetHeightForWidth(description_width) +
          kVerticalPadding;
 }
 
@@ -525,79 +529,94 @@
   return model_->IsSelectedIndex(model_index_);
 }
 
+void OmniboxResultView::OpenMatch(WindowOpenDisposition disposition) {
+  model_->OpenMatch(model_index_, disposition);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // OmniboxResultView, views::View overrides, private:
 
 void OmniboxResultView::Layout() {
   views::View::Layout();
+
   const int horizontal_padding =
       GetLayoutConstant(LOCATION_BAR_ELEMENT_PADDING) +
       GetLayoutConstant(LOCATION_BAR_ICON_INTERIOR_PADDING);
-  const int start_x = GetIconAlignmentOffset() + horizontal_padding;
-  int end_x = width();
-
-  int text_height = GetTextHeight();
-  int row_height = text_height;
-  if (IsTwoLineLayout())
-    row_height += match_.answer ? GetAnswerHeight() : GetTextHeight();
-  suggestion_separator_view_->SetVisible(false);
-  keyword_separator_view_->SetVisible(false);
-
-  // TODO(dschuyler): Refactor these if/else's into separate pieces of code to
-  // improve readability/maintainability.
-
+  // NOTE: While animating the keyword match, both matches may be visible.
+  int suggestion_width = width();
   AutocompleteMatch* keyword_match = match_.associated_keyword.get();
   if (keyword_match) {
-    // NOTE: While animating the keyword match, both matches may be visible.
-    const int icon_width = keyword_icon_view_->width() +
-                           GetIconAlignmentOffset() + horizontal_padding * 2;
+    const int icon_width = keyword_view_->icon()->width() +
+                           GetIconAlignmentOffset() + (horizontal_padding * 2);
     const int max_kw_x = width() - icon_width;
-    int kw_x = animation_->CurrentValueBetween(max_kw_x, 0);
-    end_x = kw_x;
-    kw_x += start_x + BackgroundWith1PxBorder::kLocationBarBorderThicknessDip;
-    keyword_icon_view_->SetPosition(
-        gfx::Point(kw_x, (height() - keyword_icon_view_->height()) / 2));
-    kw_x += keyword_icon_view_->width() + horizontal_padding;
-
-    int content_width = keyword_content_view_->CalculatePreferredSize().width();
-    int description_width =
-        keyword_description_view_->CalculatePreferredSize().width();
-    OmniboxPopupModel::ComputeMatchMaxWidths(
-        content_width, keyword_separator_view_->width(), description_width,
-        width(),
-        /*description_on_separate_line=*/false,
-        !AutocompleteMatch::IsSearchType(match_.type), &content_width,
-        &description_width);
-    int y = GetVerticalMargin();
-    keyword_content_view_->SetBounds(kw_x, y, content_width, text_height);
-    if (description_width != 0) {
-      kw_x += keyword_content_view_->width();
-      keyword_separator_view_->SetVisible(true);
-      keyword_separator_view_->SetBounds(
-          kw_x, y, keyword_separator_view_->width(), text_height);
-      kw_x += keyword_separator_view_->width();
-      keyword_description_view_->SetBounds(kw_x, y, description_width,
-                                           text_height);
-    } else if (IsTwoLineLayout()) {
-      keyword_content_view_->SetSize(gfx::Size(content_width, text_height * 2));
-    }
+    suggestion_width = animation_->CurrentValueBetween(max_kw_x, 0);
   }
-
-  const gfx::Image icon = GetIcon();
-  const int icon_y = GetVerticalMargin() + (row_height - icon.Height()) / 2;
-  suggestion_icon_view_->SetBounds(
-      start_x, icon_y, std::min(end_x, icon.Width()), icon.Height());
-
   if (suggestion_tab_switch_button_) {
     const gfx::Size ts_button_size =
         suggestion_tab_switch_button_->GetPreferredSize();
     suggestion_tab_switch_button_->SetSize(ts_button_size);
 
     // It looks nice to have the same margin on top, bottom and right side.
-    const int margin = (height() - ts_button_size.height()) / 2;
-    end_x -= ts_button_size.width() + margin;
-    suggestion_tab_switch_button_->SetPosition(gfx::Point(end_x, margin));
+    const int margin =
+        (suggestion_view_->height() - ts_button_size.height()) / 2;
+    suggestion_width -= ts_button_size.width() + margin;
+    suggestion_tab_switch_button_->SetPosition(
+        gfx::Point(suggestion_width, margin));
   }
+  keyword_view_->SetBounds(suggestion_width, 0, width() - suggestion_width,
+                           height());
+  suggestion_view_->SetBounds(0, 0, suggestion_width, height());
+
+  const int start_x = GetIconAlignmentOffset() + horizontal_padding;
+  int end_x = suggestion_view_->width();
+
+  int text_height = GetTextHeight();
+  int row_height = text_height;
+  if (IsTwoLineLayout())
+    row_height += match_.answer ? GetAnswerHeight() : GetTextHeight();
+  suggestion_view_->separator()->SetVisible(false);
+  keyword_view_->separator()->SetVisible(false);
+
+  // TODO(dschuyler): Refactor these if/else's into separate pieces of code to
+  // improve readability/maintainability.
+
+  if (keyword_match) {
+    int kw_x =
+        start_x + BackgroundWith1PxBorder::kLocationBarBorderThicknessDip;
+    keyword_view_->icon()->SetPosition(gfx::Point(
+        kw_x, (keyword_view_->height() - keyword_view_->icon()->height()) / 2));
+    kw_x += keyword_view_->icon()->width() + horizontal_padding;
+
+    int content_width =
+        keyword_view_->content()->CalculatePreferredSize().width();
+    int description_width =
+        keyword_view_->description()->CalculatePreferredSize().width();
+    OmniboxPopupModel::ComputeMatchMaxWidths(
+        content_width, keyword_view_->separator()->width(), description_width,
+        width(),
+        /*description_on_separate_line=*/false,
+        !AutocompleteMatch::IsSearchType(match_.type), &content_width,
+        &description_width);
+    int y = GetVerticalMargin();
+    keyword_view_->content()->SetBounds(kw_x, y, content_width, text_height);
+    if (description_width != 0) {
+      kw_x += keyword_view_->content()->width();
+      keyword_view_->separator()->SetVisible(true);
+      keyword_view_->separator()->SetBounds(
+          kw_x, y, keyword_view_->separator()->width(), text_height);
+      kw_x += keyword_view_->separator()->width();
+      keyword_view_->description()->SetBounds(kw_x, y, description_width,
+                                              text_height);
+    } else if (IsTwoLineLayout()) {
+      keyword_view_->content()->SetSize(
+          gfx::Size(content_width, text_height * 2));
+    }
+  }
+
+  const gfx::Image icon = GetIcon();
+  const int icon_y = GetVerticalMargin() + (row_height - icon.Height()) / 2;
+  suggestion_view_->icon()->SetBounds(
+      start_x, icon_y, std::min(end_x, icon.Width()), icon.Height());
 
   // NOTE: While animating the keyword match, both matches may be visible.
   int x = start_x;
@@ -605,77 +624,78 @@
 
   if (base::FeatureList::IsEnabled(omnibox::kOmniboxRichEntitySuggestions) &&
       match_.answer) {
-    suggestion_icon_view_->SetVisible(false);
+    suggestion_view_->icon()->SetVisible(false);
     int image_edge_length =
-        text_height + suggestion_description_view_->GetLineHeight();
-    suggestion_image_view_->SetImageSize(
+        text_height + suggestion_view_->description()->GetLineHeight();
+    suggestion_view_->image()->SetImageSize(
         gfx::Size(image_edge_length, image_edge_length));
-    suggestion_image_view_->SetBounds(x, y, image_edge_length,
-                                      image_edge_length);
+    suggestion_view_->image()->SetBounds(x, y, image_edge_length,
+                                         image_edge_length);
     x += image_edge_length + horizontal_padding;
-    suggestion_content_view_->SetBounds(x, y, end_x - x, text_height);
+    suggestion_view_->content()->SetBounds(x, y, end_x - x, text_height);
     y += text_height;
-    suggestion_description_view_->SetBounds(x, y, end_x - x, text_height);
+    suggestion_view_->description()->SetBounds(x, y, end_x - x, text_height);
     return;
   }
 
-  suggestion_icon_view_->SetVisible(true);
+  suggestion_view_->icon()->SetVisible(true);
   x += icon.Width() + horizontal_padding;
   if (match_.answer) {
-    suggestion_content_view_->SetBounds(x, y, end_x - x, text_height);
+    suggestion_view_->content()->SetBounds(x, y, end_x - x, text_height);
     y += text_height;
-    if (suggestion_image_view_->visible()) {
+    if (suggestion_view_->image()->visible()) {
       // The description may be multi-line. Using the view height results in
       // an image that's too large, so we use the line height here instead.
-      int image_edge_length = suggestion_description_view_->GetLineHeight();
-      suggestion_image_view_->SetBounds(
-          start_x + suggestion_icon_view_->width() + horizontal_padding,
+      int image_edge_length = suggestion_view_->description()->GetLineHeight();
+      suggestion_view_->image()->SetBounds(
+          start_x + suggestion_view_->icon()->width() + horizontal_padding,
           y + (kVerticalPadding / 2), image_edge_length, image_edge_length);
-      suggestion_image_view_->SetImageSize(
+      suggestion_view_->image()->SetImageSize(
           gfx::Size(image_edge_length, image_edge_length));
-      x += suggestion_image_view_->width() + kAnswerIconToTextPadding;
+      x += suggestion_view_->image()->width() + kAnswerIconToTextPadding;
     }
     int description_width = end_x - x;
-    suggestion_description_view_->SetBounds(
+    suggestion_view_->description()->SetBounds(
         x, y, description_width,
-        suggestion_description_view_->GetHeightForWidth(description_width) +
+        suggestion_view_->description()->GetHeightForWidth(description_width) +
             kVerticalPadding);
   } else if (IsTwoLineLayout()) {
-    if (!!suggestion_description_view_->GetContentsBounds().width()) {
+    if (!!suggestion_view_->description()->GetContentsBounds().width()) {
       // A description is present.
-      suggestion_content_view_->SetBounds(x, y, end_x - x, GetTextHeight());
+      suggestion_view_->content()->SetBounds(x, y, end_x - x, GetTextHeight());
       y += GetTextHeight();
       int description_width = end_x - x;
-      suggestion_description_view_->SetBounds(
+      suggestion_view_->description()->SetBounds(
           x, y, description_width,
-          suggestion_description_view_->GetHeightForWidth(description_width) +
+          suggestion_view_->description()->GetHeightForWidth(
+              description_width) +
               kVerticalPadding);
     } else {
       // For no description, shift down halfway to draw contents in middle.
       y += GetTextHeight() / 2;
-      suggestion_content_view_->SetBounds(x, y, end_x - x, GetTextHeight());
+      suggestion_view_->content()->SetBounds(x, y, end_x - x, GetTextHeight());
     }
   } else {
     int content_width =
-        suggestion_content_view_->CalculatePreferredSize().width();
+        suggestion_view_->content()->CalculatePreferredSize().width();
     int description_width =
-        suggestion_description_view_->CalculatePreferredSize().width();
+        suggestion_view_->description()->CalculatePreferredSize().width();
     OmniboxPopupModel::ComputeMatchMaxWidths(
-        content_width, suggestion_separator_view_->width(), description_width,
-        end_x - x,
+        content_width, suggestion_view_->separator()->width(),
+        description_width, end_x - x,
         /*description_on_separate_line=*/false,
         !AutocompleteMatch::IsSearchType(match_.type), &content_width,
         &description_width);
-    suggestion_content_view_->SetBounds(x, y, content_width, text_height);
+    suggestion_view_->content()->SetBounds(x, y, content_width, text_height);
     x += content_width;
     if (description_width) {
-      suggestion_separator_view_->SetVisible(true);
-      suggestion_separator_view_->SetBounds(
-          x, y, suggestion_separator_view_->width(), text_height);
-      x += suggestion_separator_view_->width();
+      suggestion_view_->separator()->SetVisible(true);
+      suggestion_view_->separator()->SetBounds(
+          x, y, suggestion_view_->separator()->width(), text_height);
+      x += suggestion_view_->separator()->width();
     }
-    suggestion_description_view_->SetBounds(x, y, description_width,
-                                            text_height);
+    suggestion_view_->description()->SetBounds(x, y, description_width,
+                                               text_height);
   }
 }
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.h b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
index 5ac721b..213a997 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
@@ -18,6 +18,7 @@
 #include "ui/gfx/animation/slide_animation.h"
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/views/controls/button/button.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/view.h"
 
@@ -37,7 +38,8 @@
 class OmniboxTextView;
 
 class OmniboxResultView : public views::View,
-                          private gfx::AnimationDelegate {
+                          private gfx::AnimationDelegate,
+                          public views::ButtonListener {
  public:
   OmniboxResultView(OmniboxPopupContentsView* model,
                     int model_index,
@@ -68,8 +70,10 @@
   // Stores the image in a local data member and schedules a repaint.
   void SetAnswerImage(const gfx::ImageSkia& image);
 
-  // Allow other classes to trigger navigation.
-  void OpenMatch(WindowOpenDisposition disposition);
+  // views::ButtonListener:
+
+  // Called when tab switch button pressed, due to being a listener.
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
   // views::View:
   bool OnMousePressed(const ui::MouseEvent& event) override;
@@ -103,6 +107,9 @@
   // Whether |this| matches the model's selected index.
   bool IsSelected() const;
 
+  // Call model's OpenMatch() with the selected index and provided disposition.
+  void OpenMatch(WindowOpenDisposition disposition);
+
   // views::View:
   void Layout() override;
   const char* GetClassName() const override;
@@ -130,22 +137,8 @@
   // Weak pointers for easy reference.
   OmniboxSuggestionView* suggestion_view_;  // The leading (or left) view.
   OmniboxSeparatedLineView* keyword_view_;  // The trailing (or right) view.
-
-  // TODO(dschuyler): Move these views into either suggestion_view_ or
-  // keyword_view_. I intend to do so by May, 2018.
-
-  views::ImageView* suggestion_icon_view_;   // Small icon. e.g. favicon.
-  views::ImageView* suggestion_image_view_;  // For rich suggestions.
-  OmniboxTextView* suggestion_content_view_;
-  OmniboxTextView* suggestion_description_view_;
-  OmniboxTextView* suggestion_separator_view_;  // e.g. A hyphen.
   std::unique_ptr<OmniboxTabSwitchButton> suggestion_tab_switch_button_;
 
-  views::ImageView* keyword_icon_view_;  // An icon resembling a '>'.
-  OmniboxTextView* keyword_content_view_;
-  OmniboxTextView* keyword_description_view_;
-  OmniboxTextView* keyword_separator_view_;
-
   DISALLOW_COPY_AND_ASSIGN(OmniboxResultView);
 };
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc b/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc
index 4975847..fef98231 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc
@@ -15,7 +15,7 @@
 
 OmniboxTabSwitchButton::OmniboxTabSwitchButton(OmniboxResultView* result_view,
                                                int text_height)
-    : MdTextButton(this, views::style::CONTEXT_BUTTON_MD),
+    : MdTextButton(result_view, views::style::CONTEXT_BUTTON_MD),
       text_height_(text_height),
       result_view_(result_view) {
   // TODO(krb): SetTooltipText(text);
@@ -44,14 +44,11 @@
     SetBgColorOverride(GetBackgroundColor());
     // If used to be pressed, transer ownership.
     if (old_state == STATE_PRESSED)
-      SetMouseHandler(result_view_);
+      SetMouseHandler(parent());
   }
   if (state() == STATE_HOVERED) {
     if (old_state == STATE_NORMAL) {
       SetBgColorOverride(GetBackgroundColor());
-    } else {
-      // The button was released.
-      result_view_->OpenMatch(WindowOpenDisposition::SWITCH_TO_TAB);
     }
   }
   if (state() == STATE_PRESSED)
diff --git a/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.h b/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.h
index 2116ee0..1caa945 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.h
@@ -9,17 +9,13 @@
 
 class OmniboxResultView;
 
-class OmniboxTabSwitchButton : public views::MdTextButton,
-                               public views::ButtonListener {
+class OmniboxTabSwitchButton : public views::MdTextButton {
  public:
   OmniboxTabSwitchButton(OmniboxResultView* result_view, int text_height);
 
   // views::View
   gfx::Size CalculatePreferredSize() const override;
 
-  // views::ButtonListener
-  void ButtonPressed(Button* sender, const ui::Event& event) override {}
-
   // views::Button
   void StateChanged(ButtonState old_state) override;
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 077232b..5594d7f 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -922,6 +922,13 @@
   // Save the user's existing selection to restore it later.
   saved_selection_for_focus_change_ = GetSelectedRange();
 
+  // Revert the URL if the user has not made any changes. If steady-state
+  // elisions is on, this will also re-elide the URL.
+  if (model()->user_input_in_progress() &&
+      text() == model()->GetCurrentPermanentUrlText()) {
+    RevertAll();
+  }
+
   views::Textfield::OnBlur();
   model()->OnWillKillFocus();
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
index 935b17e..ca5771d 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -163,13 +163,10 @@
 
  private:
   // ChromeOmniboxEditController:
-  void UpdateWithoutTabRestore() override {}
-  void OnChanged() override {}
   ToolbarModel* GetToolbarModel() override { return toolbar_model_; }
   const ToolbarModel* GetToolbarModel() const override {
     return toolbar_model_;
   }
-  content::WebContents* GetWebContents() override { return nullptr; }
 
   ToolbarModel* toolbar_model_;
 
@@ -184,6 +181,7 @@
  public:
   OmniboxViewViewsTest();
 
+  TestToolbarModel* toolbar_model() { return &toolbar_model_; }
   TestingOmniboxView* omnibox_view() { return omnibox_view_.get(); }
   views::Textfield* omnibox_textfield() { return omnibox_view(); }
   ui::TextEditCommand scheduled_text_edit_command() const {
@@ -390,3 +388,30 @@
     }
   }
 }
+
+TEST_F(OmniboxViewViewsTest, RevertOnBlur) {
+  toolbar_model()->set_text(base::ASCIIToUTF16("permanent text"));
+  omnibox_view()->model()->ResetDisplayUrls();
+  omnibox_view()->RevertAll();
+
+  EXPECT_EQ(base::ASCIIToUTF16("permanent text"), omnibox_view()->text());
+  EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
+
+  omnibox_view()->SetUserText(base::ASCIIToUTF16("user text"));
+
+  EXPECT_EQ(base::ASCIIToUTF16("user text"), omnibox_view()->text());
+  EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
+
+  // Expect that on blur, if the text has been edited, stay in user input mode.
+  omnibox_textfield()->OnBlur();
+  EXPECT_EQ(base::ASCIIToUTF16("user text"), omnibox_view()->text());
+  EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
+
+  // Expect that on blur, if the text is the same as the permanent text, exit
+  // user input mode.
+  omnibox_view()->SetUserText(base::ASCIIToUTF16("permanent text"));
+  EXPECT_TRUE(omnibox_view()->model()->user_input_in_progress());
+  omnibox_textfield()->OnBlur();
+  EXPECT_EQ(base::ASCIIToUTF16("permanent text"), omnibox_view()->text());
+  EXPECT_FALSE(omnibox_view()->model()->user_input_in_progress());
+}
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 8d8516c..ab3315c 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -924,14 +924,12 @@
 #else
     {"resetPageTitle", IDS_SETTINGS_RESET},
 #endif
-    {"resetTrigger", IDS_SETTINGS_RESET},
-    {"resetTriggerDescription",
-     IDS_SETTINGS_RESET_PROFILE_SETTINGS_DESCRIPTION},
+    {"resetTrigger", IDS_SETTINGS_RESET_SETTINGS_TRIGGER},
     {"resetPageExplanation", IDS_RESET_PROFILE_SETTINGS_EXPLANATION},
     {"triggeredResetPageExplanation",
      IDS_TRIGGERED_RESET_PROFILE_SETTINGS_EXPLANATION},
     {"triggeredResetPageTitle", IDS_TRIGGERED_RESET_PROFILE_SETTINGS_TITLE},
-    {"resetPageCommit", IDS_RESET_PROFILE_SETTINGS_COMMIT_BUTTON},
+    {"resetDialogCommit", IDS_SETTINGS_RESET},
     {"resetPageFeedback", IDS_SETTINGS_RESET_PROFILE_FEEDBACK},
 #if defined(OS_CHROMEOS)
     {"powerwashTitle", IDS_SETTINGS_FACTORY_RESET},
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 5b88838d..51e79efd 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -755,7 +755,7 @@
       "service_process.mojom",
     ]
     public_deps = [
-      "//mojo/common:common_custom_types",
+      "//mojo/public/mojom/base",
     ]
   }
 }
diff --git a/chrome/common/cloud_print.mojom b/chrome/common/cloud_print.mojom
index 5bbbae85..6e64341 100644
--- a/chrome/common/cloud_print.mojom
+++ b/chrome/common/cloud_print.mojom
@@ -4,7 +4,7 @@
 
 module cloud_print.mojom;
 
-import "mojo/common/values.mojom";
+import "mojo/public/mojom/base/values.mojom";
 
 // An interface for controlling cloud print running in a service process.
 interface CloudPrint {
@@ -14,7 +14,7 @@
       string robot_auth_code,
       string robot_email,
       string user_email,
-      mojo.common.mojom.DictionaryValue user_settings);
+      mojo_base.mojom.DictionaryValue user_settings);
 
   // Tell the service process to disable the cloud proxy.
   DisableCloudPrintProxy();
diff --git a/chrome/common/profiling/memlog_allocator_shim.cc b/chrome/common/profiling/memlog_allocator_shim.cc
index 885385d..9586f35e 100644
--- a/chrome/common/profiling/memlog_allocator_shim.cc
+++ b/chrome/common/profiling/memlog_allocator_shim.cc
@@ -18,6 +18,7 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_id_name_manager.h"
 #include "base/threading/thread_local.h"
+#include "base/threading/thread_local_storage.h"
 #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
 #include "base/trace_event/heap_profiler_allocation_register.h"
 #include "base/trace_event/heap_profiler_event_filter.h"
@@ -41,6 +42,35 @@
 
 namespace {
 
+// In the very unlikely scenario where a thread has grabbed the SendBuffer lock,
+// and then performs a heap allocation/free, ignore the allocation. Failing to
+// do so will cause non-deterministic deadlock, depending on whether the
+// allocation is dispatched to the same SendBuffer.
+//
+// On macOS, this flag is also used to prevent double-counting during sampling.
+// The implementation of libmalloc will sometimes call malloc [from
+// one zone to another] - without this flag, the allocation would get two
+// chances of being sampled.
+base::LazyInstance<base::ThreadLocalBoolean>::Leaky g_prevent_reentrancy =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// This class is friended by ThreadLocalStorage.
+class MemlogAllocatorShimInternal {
+ public:
+  static bool ShouldLogAllocationOnCurrentThread() {
+    // Thread is being destroyed and TLS is no longer available.
+    if (UNLIKELY(base::ThreadLocalStorage::HasBeenDestroyed()))
+      return false;
+
+    // Prevent re-entrancy.
+    return !g_prevent_reentrancy.Pointer()->Get();
+  }
+};
+
+namespace {
+
 using base::allocator::AllocatorDispatch;
 
 base::LazyInstance<base::OnceClosure>::Leaky g_on_init_allocator_shim_callback_;
@@ -72,18 +102,6 @@
 SetGCAllocHookFunction g_hook_gc_alloc = nullptr;
 SetGCFreeHookFunction g_hook_gc_free = nullptr;
 
-// In the very unlikely scenario where a thread has grabbed the SendBuffer lock,
-// and then performs a heap allocation/free, ignore the allocation. Failing to
-// do so will cause non-deterministic deadlock, depending on whether the
-// allocation is dispatched to the same SendBuffer.
-//
-// On macOS, this flag is also used to prevent double-counting during sampling.
-// The implementation of libmalloc will sometimes call malloc [from
-// one zone to another] - without this flag, the allocation would get two
-// chances of being sampled.
-base::LazyInstance<base::ThreadLocalBoolean>::Leaky g_prevent_reentrancy =
-    LAZY_INSTANCE_INITIALIZER;
-
 // The allocator shim needs to retain some additional state for each thread.
 struct ShimState {
   // The pointer must be valid for the lifetime of the process.
@@ -124,6 +142,10 @@
   delete static_cast<ShimState*>(shim_state);
 }
 
+// Technically, this code could be called after Thread destruction and we would
+// need to guard this with ThreadLocalStorage::HasBeenDestroyed(), but all calls
+// to this are guarded behind ShouldLogAllocationOnCurrentThread, which already
+// makes the check.
 base::ThreadLocalStorage::Slot& ShimStateTLS() {
   static base::NoDestructor<base::ThreadLocalStorage::Slot> shim_state_tls(
       &DestructShimState);
@@ -276,13 +298,14 @@
   const AllocatorDispatch* const next = self->next;
 
   // If this is our first time passing through, set the reentrancy bit.
-  bool reentering = g_prevent_reentrancy.Pointer()->Get();
-  if (LIKELY(!reentering))
+  bool should_log =
+      MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
+  if (LIKELY(should_log))
     g_prevent_reentrancy.Pointer()->Set(true);
 
   void* ptr = next->alloc_function(next, size, context);
 
-  if (LIKELY(!reentering)) {
+  if (LIKELY(should_log)) {
     AllocatorShimLogAlloc(AllocatorType::kMalloc, ptr, size, nullptr);
     g_prevent_reentrancy.Pointer()->Set(false);
   }
@@ -297,13 +320,14 @@
   const AllocatorDispatch* const next = self->next;
 
   // If this is our first time passing through, set the reentrancy bit.
-  bool reentering = g_prevent_reentrancy.Pointer()->Get();
-  if (LIKELY(!reentering))
+  bool should_log =
+      MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
+  if (LIKELY(should_log))
     g_prevent_reentrancy.Pointer()->Set(true);
 
   void* ptr = next->alloc_zero_initialized_function(next, n, size, context);
 
-  if (LIKELY(!reentering)) {
+  if (LIKELY(should_log)) {
     AllocatorShimLogAlloc(AllocatorType::kMalloc, ptr, n * size, nullptr);
     g_prevent_reentrancy.Pointer()->Set(false);
   }
@@ -317,13 +341,14 @@
   const AllocatorDispatch* const next = self->next;
 
   // If this is our first time passing through, set the reentrancy bit.
-  bool reentering = g_prevent_reentrancy.Pointer()->Get();
-  if (LIKELY(!reentering))
+  bool should_log =
+      MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
+  if (LIKELY(should_log))
     g_prevent_reentrancy.Pointer()->Set(true);
 
   void* ptr = next->alloc_aligned_function(next, alignment, size, context);
 
-  if (LIKELY(!reentering)) {
+  if (LIKELY(should_log)) {
     AllocatorShimLogAlloc(AllocatorType::kMalloc, ptr, size, nullptr);
     g_prevent_reentrancy.Pointer()->Set(false);
   }
@@ -337,13 +362,14 @@
   const AllocatorDispatch* const next = self->next;
 
   // If this is our first time passing through, set the reentrancy bit.
-  bool reentering = g_prevent_reentrancy.Pointer()->Get();
-  if (LIKELY(!reentering))
+  bool should_log =
+      MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
+  if (LIKELY(should_log))
     g_prevent_reentrancy.Pointer()->Set(true);
 
   void* ptr = next->realloc_function(next, address, size, context);
 
-  if (LIKELY(!reentering)) {
+  if (LIKELY(should_log)) {
     AllocatorShimLogFree(address);
     if (size > 0)  // realloc(size == 0) means free()
       AllocatorShimLogAlloc(AllocatorType::kMalloc, ptr, size, nullptr);
@@ -355,14 +381,15 @@
 
 void HookFree(const AllocatorDispatch* self, void* address, void* context) {
   // If this is our first time passing through, set the reentrancy bit.
-  bool reentering = g_prevent_reentrancy.Pointer()->Get();
-  if (LIKELY(!reentering))
+  bool should_log =
+      MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
+  if (LIKELY(should_log))
     g_prevent_reentrancy.Pointer()->Set(true);
 
   const AllocatorDispatch* const next = self->next;
   next->free_function(next, address, context);
 
-  if (LIKELY(!reentering)) {
+  if (LIKELY(should_log)) {
     AllocatorShimLogFree(address);
     g_prevent_reentrancy.Pointer()->Set(false);
   }
@@ -381,15 +408,16 @@
                          unsigned num_requested,
                          void* context) {
   // If this is our first time passing through, set the reentrancy bit.
-  bool reentering = g_prevent_reentrancy.Pointer()->Get();
-  if (LIKELY(!reentering))
+  bool should_log =
+      MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
+  if (LIKELY(should_log))
     g_prevent_reentrancy.Pointer()->Set(true);
 
   const AllocatorDispatch* const next = self->next;
   unsigned count =
       next->batch_malloc_function(next, size, results, num_requested, context);
 
-  if (LIKELY(!reentering)) {
+  if (LIKELY(should_log)) {
     for (unsigned i = 0; i < count; ++i)
       AllocatorShimLogAlloc(AllocatorType::kMalloc, results[i], size, nullptr);
     g_prevent_reentrancy.Pointer()->Set(false);
@@ -402,14 +430,15 @@
                    unsigned num_to_be_freed,
                    void* context) {
   // If this is our first time passing through, set the reentrancy bit.
-  bool reentering = g_prevent_reentrancy.Pointer()->Get();
-  if (LIKELY(!reentering))
+  bool should_log =
+      MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
+  if (LIKELY(should_log))
     g_prevent_reentrancy.Pointer()->Set(true);
 
   const AllocatorDispatch* const next = self->next;
   next->batch_free_function(next, to_be_freed, num_to_be_freed, context);
 
-  if (LIKELY(!reentering)) {
+  if (LIKELY(should_log)) {
     for (unsigned i = 0; i < num_to_be_freed; ++i)
       AllocatorShimLogFree(to_be_freed[i]);
     g_prevent_reentrancy.Pointer()->Set(false);
@@ -421,14 +450,15 @@
                           size_t size,
                           void* context) {
   // If this is our first time passing through, set the reentrancy bit.
-  bool reentering = g_prevent_reentrancy.Pointer()->Get();
-  if (LIKELY(!reentering))
+  bool should_log =
+      MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
+  if (LIKELY(should_log))
     g_prevent_reentrancy.Pointer()->Set(true);
 
   const AllocatorDispatch* const next = self->next;
   next->free_definite_size_function(next, ptr, size, context);
 
-  if (LIKELY(!reentering)) {
+  if (LIKELY(should_log)) {
     AllocatorShimLogFree(ptr);
     g_prevent_reentrancy.Pointer()->Set(false);
   }
@@ -450,7 +480,8 @@
 
 void HookPartitionAlloc(void* address, size_t size, const char* type) {
   // If this is our first time passing through, set the reentrancy bit.
-  if (LIKELY(!g_prevent_reentrancy.Pointer()->Get())) {
+  if (LIKELY(
+          MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread())) {
     g_prevent_reentrancy.Pointer()->Set(true);
     AllocatorShimLogAlloc(AllocatorType::kPartitionAlloc, address, size, type);
     g_prevent_reentrancy.Pointer()->Set(false);
@@ -459,7 +490,8 @@
 
 void HookPartitionFree(void* address) {
   // If this is our first time passing through, set the reentrancy bit.
-  if (LIKELY(!g_prevent_reentrancy.Pointer()->Get())) {
+  if (LIKELY(
+          MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread())) {
     g_prevent_reentrancy.Pointer()->Set(true);
     AllocatorShimLogFree(address);
     g_prevent_reentrancy.Pointer()->Set(false);
@@ -467,7 +499,8 @@
 }
 
 void HookGCAlloc(uint8_t* address, size_t size, const char* type) {
-  if (LIKELY(!g_prevent_reentrancy.Pointer()->Get())) {
+  if (LIKELY(
+          MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread())) {
     g_prevent_reentrancy.Pointer()->Set(true);
     AllocatorShimLogAlloc(AllocatorType::kOilpan, address, size, type);
     g_prevent_reentrancy.Pointer()->Set(false);
@@ -475,7 +508,8 @@
 }
 
 void HookGCFree(uint8_t* address) {
-  if (LIKELY(!g_prevent_reentrancy.Pointer()->Get())) {
+  if (LIKELY(
+          MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread())) {
     g_prevent_reentrancy.Pointer()->Set(true);
     AllocatorShimLogFree(address);
     g_prevent_reentrancy.Pointer()->Set(false);
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index 32b8c44..91c93f7 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -1306,6 +1306,7 @@
           switches::kProcessType);
 
   if (process_type == crash_reporter::switches::kCrashpadHandler) {
+    persistent_histogram_storage.Disable();
     return crash_reporter::RunAsCrashpadHandler(
         *base::CommandLine::ForCurrentProcess(), base::FilePath(),
         switches::kProcessType, switches::kUserDataDir);
@@ -1350,6 +1351,11 @@
 
   const bool is_uninstall = cmd_line.HasSwitch(installer::switches::kUninstall);
 
+  // Disable histogram storage during uninstall since there's neither a
+  // directory in which to write them nor a browser to subsequently upload them.
+  if (is_uninstall)
+    persistent_histogram_storage.Disable();
+
   // Check to make sure current system is Win7 or later. If not, log
   // error message and get out.
   if (!InstallUtil::IsOSSupported()) {
diff --git a/chrome/service/cloud_print/cloud_print_message_handler.cc b/chrome/service/cloud_print/cloud_print_message_handler.cc
index a0baca1b..25d402e 100644
--- a/chrome/service/cloud_print/cloud_print_message_handler.cc
+++ b/chrome/service/cloud_print/cloud_print_message_handler.cc
@@ -32,9 +32,12 @@
     const std::string& robot_auth_code,
     const std::string& robot_email,
     const std::string& user_email,
-    std::unique_ptr<base::DictionaryValue> user_settings) {
+    base::Value user_settings) {
+  std::unique_ptr<base::DictionaryValue> user_settings_dict =
+      base::DictionaryValue::From(
+          base::Value::ToUniquePtrValue(std::move(user_settings)));
   proxy_provider_->GetCloudPrintProxy()->EnableForUserWithRobot(
-      robot_auth_code, robot_email, user_email, *user_settings);
+      robot_auth_code, robot_email, user_email, *user_settings_dict);
 }
 
 void CloudPrintMessageHandler::GetCloudPrintProxyInfo(
diff --git a/chrome/service/cloud_print/cloud_print_message_handler.h b/chrome/service/cloud_print/cloud_print_message_handler.h
index 81e209ef..6a46675c 100644
--- a/chrome/service/cloud_print/cloud_print_message_handler.h
+++ b/chrome/service/cloud_print/cloud_print_message_handler.h
@@ -11,10 +11,6 @@
 #include "chrome/common/cloud_print.mojom.h"
 #include "chrome/service/cloud_print/cloud_print_proxy.h"
 
-namespace base {
-class DictionaryValue;
-}
-
 namespace cloud_print {
 
 // Handles IPC messages for Cloud Print. Lives on the main thread.
@@ -28,11 +24,10 @@
 
  private:
   // cloud_print::mojom::CloudPrintProxy.
-  void EnableCloudPrintProxyWithRobot(
-      const std::string& robot_auth_code,
-      const std::string& robot_email,
-      const std::string& user_email,
-      std::unique_ptr<base::DictionaryValue> user_settings) override;
+  void EnableCloudPrintProxyWithRobot(const std::string& robot_auth_code,
+                                      const std::string& robot_email,
+                                      const std::string& user_email,
+                                      base::Value user_settings) override;
   void GetCloudPrintProxyInfo(GetCloudPrintProxyInfoCallback callback) override;
   void GetPrinters(GetPrintersCallback callback) override;
   void DisableCloudPrintProxy() override;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 0ed02c5..739c629 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2815,6 +2815,7 @@
       "../browser/offline_pages/prefetch/prefetch_background_task_handler_impl_unittest.cc",
       "../browser/offline_pages/prefetch/prefetch_instance_id_proxy_unittest.cc",
       "../browser/offline_pages/prefetch/prefetched_pages_notifier_unittest.cc",
+      "../browser/offline_pages/prefetch/thumbnail_fetcher_impl_unittest.cc",
       "../browser/offline_pages/recent_tab_helper_unittest.cc",
       "../browser/offline_pages/test_offline_page_model_builder.cc",
       "../browser/offline_pages/test_offline_page_model_builder.h",
diff --git a/chrome/test/data/extensions/api_test/declarative_net_request/page_whitelisting_api/background.js b/chrome/test/data/extensions/api_test/declarative_net_request/page_whitelisting_api/background.js
index 4e549da..6d5ba51 100644
--- a/chrome/test/data/extensions/api_test/declarative_net_request/page_whitelisting_api/background.js
+++ b/chrome/test/data/extensions/api_test/declarative_net_request/page_whitelisting_api/background.js
@@ -17,7 +17,11 @@
 
 chrome.test.runTests([
   function addWhitelistedPages() {
-    var toAdd = ['https://www.google.com/', 'https://www.yahoo.com/'];
+    // Any duplicates in arguments will be filtered out.
+    var toAdd = [
+      'https://www.google.com/', 'https://www.google.com/',
+      'https://www.yahoo.com/'
+    ];
     chrome.declarativeNetRequest.addWhitelistedPages(
         toAdd, callbackPass(function() {}));
   },
@@ -70,5 +74,65 @@
         callbackPass(function(patterns) {
           checkUnordererArrayEquality(['https://www.yahoo.com/'], patterns);
         }));
+  },
+
+  function reachMaximumPatternLimit() {
+    var toAdd = [];
+    var numPatterns = 1;  // The extension already has one whitelisted pattern.
+    while (numPatterns <
+           chrome.declarativeNetRequest.MAX_NUMBER_OF_WHITELISTED_PAGES) {
+      toAdd.push('https://' + numPatterns + '.com/');
+      numPatterns++;
+    }
+
+    chrome.declarativeNetRequest.addWhitelistedPages(
+        toAdd, callbackPass(function() {}));
+  },
+
+  function errorOnExceedingMaximumPatternLimit() {
+    chrome.declarativeNetRequest.addWhitelistedPages(
+        ['https://example.com/'],
+        callbackFail(
+            'The number of whitelisted page patterns can\'t exceed ' +
+            chrome.declarativeNetRequest.MAX_NUMBER_OF_WHITELISTED_PAGES));
+  },
+
+  function addingDuplicatePatternSucceeds() {
+    // Adding a duplicate pattern should still succeed since the final set of
+    // whitelisted patterns is still at the limit.
+    chrome.declarativeNetRequest.addWhitelistedPages(
+        ['https://www.yahoo.com/'], callbackPass(function() {}));
+  },
+
+  function verifyPatterns() {
+    chrome.declarativeNetRequest.getWhitelistedPages(
+        callbackPass(function(patterns) {
+          chrome.test.assertTrue(patterns.includes('https://www.yahoo.com/'));
+          chrome.test.assertEq(
+              chrome.declarativeNetRequest.MAX_NUMBER_OF_WHITELISTED_PAGES,
+              patterns.length, 'Incorrect number of patterns observed.');
+        }));
+  },
+
+  function removePattern() {
+    chrome.declarativeNetRequest.removeWhitelistedPages(
+        ['https://www.yahoo.com/'], callbackPass(function() {}));
+  },
+
+  function addPattern() {
+    // Adding a pattern should now succeed since removing the pattern caused us
+    // to go under the limit.
+    chrome.declarativeNetRequest.addWhitelistedPages(
+        ['https://www.example.com/'], callbackPass(function() {}));
+  },
+
+  function verifyPatterns() {
+    chrome.declarativeNetRequest.getWhitelistedPages(
+        callbackPass(function(patterns) {
+          chrome.test.assertTrue(patterns.includes('https://www.example.com/'));
+          chrome.test.assertEq(
+              chrome.declarativeNetRequest.MAX_NUMBER_OF_WHITELISTED_PAGES,
+              patterns.length, 'Incorrect number of patterns observed.');
+        }));
   }
 ]);
diff --git a/chrome/test/data/printing/bug_806746.emf b/chrome/test/data/printing/bug_806746.emf
new file mode 100644
index 0000000..50d8f9d2
--- /dev/null
+++ b/chrome/test/data/printing/bug_806746.emf
Binary files differ
diff --git a/chrome/test/data/printing/bug_806746.pdf b/chrome/test/data/printing/bug_806746.pdf
new file mode 100644
index 0000000..203caf8
--- /dev/null
+++ b/chrome/test/data/printing/bug_806746.pdf
Binary files differ
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn
index 8e74729..92a2fb17 100644
--- a/chromecast/browser/BUILD.gn
+++ b/chromecast/browser/BUILD.gn
@@ -127,6 +127,7 @@
     "//content/public/common",
     "//content/public/common:service_names",
     "//content/public/utility",
+    "//device/bluetooth",
     "//device/geolocation",
     "//gpu",
     "//ipc",
diff --git a/chromecast/browser/DEPS b/chromecast/browser/DEPS
index eaf3d03..216a7b1 100644
--- a/chromecast/browser/DEPS
+++ b/chromecast/browser/DEPS
@@ -23,6 +23,7 @@
   "+content/public/browser",
   "+content/public/common",
   "+content/public/test",
+  "+device/bluetooth",
   "+device/geolocation",
   "+extensions/browser",
   "+extensions/common",
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc
index f571f85..03a3095 100644
--- a/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -104,6 +104,10 @@
 #include "extensions/browser/extension_prefs.h"  // nogncheck
 #endif
 
+#if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
+#include "device/bluetooth/cast/bluetooth_adapter_cast.h"
+#endif  // !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
+
 namespace {
 
 #if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
@@ -469,6 +473,13 @@
 void CastBrowserMainParts::PreMainMessageLoopRun() {
 #if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
   memory_pressure_monitor_.reset(new CastMemoryPressureMonitor());
+
+  // base::Unretained() is safe because the browser client will outlive any
+  // component in the browser; this factory method will not be called after
+  // the browser starts to tear down.
+  device::BluetoothAdapterCast::SetFactory(base::BindRepeating(
+      &CastContentBrowserClient::CreateBluetoothAdapter,
+      base::Unretained(cast_browser_process_->browser_client())));
 #endif  // !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
 
   cast_browser_process_->SetNetLog(net_log_.get());
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index cb55a80..f169d3a 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -249,6 +249,14 @@
   return cast_browser_main_parts_->media_caps();
 }
 
+#if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
+base::WeakPtr<device::BluetoothAdapterCast>
+CastContentBrowserClient::CreateBluetoothAdapter() {
+  NOTREACHED() << "Bluetooth Adapter is not supported!";
+  return nullptr;
+}
+#endif  // !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
+
 void CastContentBrowserClient::SetMetricsClientId(
     const std::string& client_id) {}
 
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h
index 390d4a75..2c186bb 100644
--- a/chromecast/browser/cast_content_browser_client.h
+++ b/chromecast/browser/cast_content_browser_client.h
@@ -25,6 +25,10 @@
 class CrashHandlerHostLinux;
 }
 
+namespace device {
+class BluetoothAdapterCast;
+}
+
 namespace metrics {
 class MetricsService;
 }
@@ -96,6 +100,14 @@
 #endif  // BUILDFLAG(IS_CAST_USING_CMA_BACKEND)
   media::MediaCapsImpl* media_caps();
 
+#if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
+  // Create a BluetoothAdapter for WebBluetooth support.
+  // TODO(slan): This further couples the browser to the Cast service. Remove
+  // this once the dedicated Bluetooth service has been implemented.
+  // (b/76155468)
+  virtual base::WeakPtr<device::BluetoothAdapterCast> CreateBluetoothAdapter();
+#endif  // !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
+
   // Invoked when the metrics client ID changes.
   virtual void SetMetricsClientId(const std::string& client_id);
 
diff --git a/chromecast/device/bluetooth/le/remote_characteristic_impl.cc b/chromecast/device/bluetooth/le/remote_characteristic_impl.cc
index c534c84..a9e16a4 100644
--- a/chromecast/device/bluetooth/le/remote_characteristic_impl.cc
+++ b/chromecast/device/bluetooth/le/remote_characteristic_impl.cc
@@ -119,8 +119,11 @@
 
   auto it = uuid_to_descriptor_.find(RemoteDescriptor::kCccdUuid);
   if (it == uuid_to_descriptor_.end()) {
-    LOG(ERROR) << "No CCCD found";
-    EXEC_CB_AND_RET(cb, false);
+    // If there is no CCCD on the remote characteristic, this is unusual, but
+    // not something that we can necessarily help. Log a warning and return
+    // success.
+    LOG(WARNING) << "No CCCD found on the remote characteristic.";
+    EXEC_CB_AND_RET(cb, true);
   }
 
   it->second->WriteAuth(bluetooth_v2_shlib::Gatt::Client::AUTH_REQ_NONE,
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index 3f9dc69..6c886c4 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -29,6 +29,7 @@
     ":media_perception_proto",
     ":power_manager_proto",
     ":smbprovider_proto",
+    ":vm_applications_apps_proto",
     "//base",
     "//base:i18n",
     "//base/third_party/dynamic_annotations",
@@ -270,6 +271,8 @@
     "dbus/services/proxy_resolution_service_provider.h",
     "dbus/services/virtual_file_request_service_provider.cc",
     "dbus/services/virtual_file_request_service_provider.h",
+    "dbus/services/vm_applications_service_provider.cc",
+    "dbus/services/vm_applications_service_provider.h",
     "dbus/session_manager_client.cc",
     "dbus/session_manager_client.h",
     "dbus/shill_client_helper.cc",
@@ -542,6 +545,7 @@
     "dbus/services/org.chromium.LivenessService.conf",
     "dbus/services/org.chromium.NetworkProxyService.conf",
     "dbus/services/org.chromium.VirtualFileRequestService.conf",
+    "dbus/services/org.chromium.VmApplicationsService.conf",
   ]
   outputs = [
     "$root_out_dir/dbus/{{source_file_part}}",
@@ -873,3 +877,11 @@
 
   proto_out_dir = "chromeos/dbus/concierge"
 }
+
+proto_library("vm_applications_apps_proto") {
+  sources = [
+    "//third_party/cros_system_api/dbus/vm_applications/apps.proto",
+  ]
+
+  proto_out_dir = "chromeos/dbus/vm_applications"
+}
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index 7a181d9..3934ec0 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -512,6 +512,9 @@
 // must succeed, otherwise session restart should fail).
 const char kProfileRequiresPolicy[] = "profile-requires-policy";
 
+// The rlz ping delay (in seconds) that overwrites the default value.
+const char kRlzPingDelay[] = "rlz-ping-delay";
+
 // Overrides network stub behavior. By default, ethernet, wifi and vpn are
 // enabled, and transitions occur instantaneously. Multiple options can be
 // comma separated (no spaces). Note: all options are in the format 'foo=x'.
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 1a29e36c..90b715d4d 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -145,6 +145,7 @@
 CHROMEOS_EXPORT extern const char kOobeSkipToLogin[];
 CHROMEOS_EXPORT extern const char kOobeTimerInterval[];
 CHROMEOS_EXPORT extern const char kProfileRequiresPolicy[];
+CHROMEOS_EXPORT extern const char kRlzPingDelay[];
 CHROMEOS_EXPORT extern const char kShillStub[];
 CHROMEOS_EXPORT extern const char kShowLoginDevOverlay[];
 CHROMEOS_EXPORT extern const char kSmsTestMessages[];
diff --git a/chromeos/components/proximity_auth/mock_proximity_auth_client.cc b/chromeos/components/proximity_auth/mock_proximity_auth_client.cc
index 694e6da..063bb3a2 100644
--- a/chromeos/components/proximity_auth/mock_proximity_auth_client.cc
+++ b/chromeos/components/proximity_auth/mock_proximity_auth_client.cc
@@ -12,11 +12,6 @@
 
 MockProximityAuthClient::~MockProximityAuthClient() {}
 
-std::unique_ptr<cryptauth::SecureMessageDelegate>
-MockProximityAuthClient::CreateSecureMessageDelegate() {
-  return base::WrapUnique(CreateSecureMessageDelegatePtr());
-}
-
 std::unique_ptr<cryptauth::CryptAuthClientFactory>
 MockProximityAuthClient::CreateCryptAuthClientFactory() {
   return base::WrapUnique(CreateCryptAuthClientFactoryPtr());
diff --git a/chromeos/components/proximity_auth/mock_proximity_auth_client.h b/chromeos/components/proximity_auth/mock_proximity_auth_client.h
index 69b8020..61f94be 100644
--- a/chromeos/components/proximity_auth/mock_proximity_auth_client.h
+++ b/chromeos/components/proximity_auth/mock_proximity_auth_client.h
@@ -13,7 +13,6 @@
 #include "components/cryptauth/cryptauth_client.h"
 #include "components/cryptauth/cryptauth_device_manager.h"
 #include "components/cryptauth/cryptauth_enrollment_manager.h"
-#include "components/cryptauth/secure_message_delegate.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace proximity_auth {
@@ -43,15 +42,11 @@
                cryptauth::CryptAuthEnrollmentManager*(void));
   MOCK_METHOD0(GetCryptAuthDeviceManager,
                cryptauth::CryptAuthDeviceManager*(void));
-  std::unique_ptr<cryptauth::SecureMessageDelegate>
-  CreateSecureMessageDelegate() override;
   std::unique_ptr<cryptauth::CryptAuthClientFactory>
   CreateCryptAuthClientFactory() override;
   MOCK_METHOD0(GetLocalDevicePublicKey, std::string(void));
 
   // Proxy mock methods because implementation requires returning scoped_ptr.
-  MOCK_METHOD0(CreateSecureMessageDelegatePtr,
-               cryptauth::SecureMessageDelegate*(void));
   MOCK_METHOD0(CreateCryptAuthClientFactoryPtr,
                cryptauth::CryptAuthClientFactory*(void));
 
diff --git a/chromeos/components/proximity_auth/proximity_auth_client.h b/chromeos/components/proximity_auth/proximity_auth_client.h
index cace724..c0fde56 100644
--- a/chromeos/components/proximity_auth/proximity_auth_client.h
+++ b/chromeos/components/proximity_auth/proximity_auth_client.h
@@ -17,7 +17,6 @@
 class CryptAuthClientFactory;
 class CryptAuthDeviceManager;
 class CryptAuthEnrollmentManager;
-class SecureMessageDelegate;
 }  // namespace cryptauth
 
 namespace proximity_auth {
@@ -59,10 +58,6 @@
   // Returns the manager responsible for EasyUnlock preferences.
   virtual ProximityAuthPrefManager* GetPrefManager() = 0;
 
-  // Returns the SecureMessageDelegate used by the system.
-  virtual std::unique_ptr<cryptauth::SecureMessageDelegate>
-  CreateSecureMessageDelegate() = 0;
-
   // Constructs the CryptAuthClientFactory that can be used for API requests.
   virtual std::unique_ptr<cryptauth::CryptAuthClientFactory>
   CreateCryptAuthClientFactory() = 0;
diff --git a/chromeos/components/proximity_auth/proximity_auth_system.cc b/chromeos/components/proximity_auth/proximity_auth_system.cc
index 31c65b20..108057f 100644
--- a/chromeos/components/proximity_auth/proximity_auth_system.cc
+++ b/chromeos/components/proximity_auth/proximity_auth_system.cc
@@ -127,7 +127,7 @@
 ProximityAuthSystem::CreateRemoteDeviceLifeCycle(
     const cryptauth::RemoteDevice& remote_device) {
   return std::unique_ptr<RemoteDeviceLifeCycle>(
-      new RemoteDeviceLifeCycleImpl(remote_device, proximity_auth_client_));
+      new RemoteDeviceLifeCycleImpl(remote_device));
 }
 
 void ProximityAuthSystem::OnLifeCycleStateChanged(
diff --git a/chromeos/components/proximity_auth/remote_device_life_cycle_impl.cc b/chromeos/components/proximity_auth/remote_device_life_cycle_impl.cc
index cc74e0b..ec32df0 100644
--- a/chromeos/components/proximity_auth/remote_device_life_cycle_impl.cc
+++ b/chromeos/components/proximity_auth/remote_device_life_cycle_impl.cc
@@ -15,12 +15,11 @@
 #include "chromeos/components/proximity_auth/bluetooth_low_energy_connection_finder.h"
 #include "chromeos/components/proximity_auth/logging/logging.h"
 #include "chromeos/components/proximity_auth/messenger_impl.h"
-#include "chromeos/components/proximity_auth/proximity_auth_client.h"
 #include "chromeos/components/proximity_auth/switches.h"
 #include "components/cryptauth/connection_finder.h"
 #include "components/cryptauth/device_to_device_authenticator.h"
 #include "components/cryptauth/secure_context.h"
-#include "components/cryptauth/secure_message_delegate.h"
+#include "components/cryptauth/secure_message_delegate_impl.h"
 
 namespace proximity_auth {
 
@@ -33,10 +32,8 @@
 }  // namespace
 
 RemoteDeviceLifeCycleImpl::RemoteDeviceLifeCycleImpl(
-    const cryptauth::RemoteDevice& remote_device,
-    ProximityAuthClient* proximity_auth_client)
+    const cryptauth::RemoteDevice& remote_device)
     : remote_device_(remote_device),
-      proximity_auth_client_(proximity_auth_client),
       state_(RemoteDeviceLifeCycle::State::STOPPED),
       weak_ptr_factory_(this) {}
 
@@ -86,7 +83,7 @@
 RemoteDeviceLifeCycleImpl::CreateAuthenticator() {
   return std::make_unique<cryptauth::DeviceToDeviceAuthenticator>(
       connection_.get(), remote_device_.user_id,
-      proximity_auth_client_->CreateSecureMessageDelegate());
+      cryptauth::SecureMessageDelegateImpl::Factory::NewInstance());
 }
 
 void RemoteDeviceLifeCycleImpl::TransitionToState(
diff --git a/chromeos/components/proximity_auth/remote_device_life_cycle_impl.h b/chromeos/components/proximity_auth/remote_device_life_cycle_impl.h
index db948b7..5278ccb 100644
--- a/chromeos/components/proximity_auth/remote_device_life_cycle_impl.h
+++ b/chromeos/components/proximity_auth/remote_device_life_cycle_impl.h
@@ -25,7 +25,6 @@
 namespace proximity_auth {
 
 class Messenger;
-class ProximityAuthClient;
 
 // Implementation of RemoteDeviceLifeCycle.
 class RemoteDeviceLifeCycleImpl : public RemoteDeviceLifeCycle,
@@ -33,8 +32,8 @@
  public:
   // Creates the life cycle for controlling the given |remote_device|.
   // |proximity_auth_client| is not owned.
-  RemoteDeviceLifeCycleImpl(const cryptauth::RemoteDevice& remote_device,
-                            ProximityAuthClient* proximity_auth_client);
+  explicit RemoteDeviceLifeCycleImpl(
+      const cryptauth::RemoteDevice& remote_device);
   ~RemoteDeviceLifeCycleImpl() override;
 
   // RemoteDeviceLifeCycle:
@@ -81,9 +80,6 @@
   // The remote device being controlled.
   const cryptauth::RemoteDevice remote_device_;
 
-  // Used to grab dependencies in chrome. Not owned.
-  ProximityAuthClient* proximity_auth_client_;
-
   // The current state in the life cycle.
   RemoteDeviceLifeCycle::State state_;
 
diff --git a/chromeos/components/proximity_auth/remote_device_life_cycle_impl_unittest.cc b/chromeos/components/proximity_auth/remote_device_life_cycle_impl_unittest.cc
index d9149e3..8291821 100644
--- a/chromeos/components/proximity_auth/remote_device_life_cycle_impl_unittest.cc
+++ b/chromeos/components/proximity_auth/remote_device_life_cycle_impl_unittest.cc
@@ -131,7 +131,7 @@
  public:
   TestableRemoteDeviceLifeCycleImpl(
       const cryptauth::RemoteDevice& remote_device)
-      : RemoteDeviceLifeCycleImpl(remote_device, nullptr),
+      : RemoteDeviceLifeCycleImpl(remote_device),
         remote_device_(remote_device) {}
 
   ~TestableRemoteDeviceLifeCycleImpl() override {}
diff --git a/chromeos/components/proximity_auth/webui/proximity_auth_webui_handler.cc b/chromeos/components/proximity_auth/webui/proximity_auth_webui_handler.cc
index bb89b97..f50ac53c 100644
--- a/chromeos/components/proximity_auth/webui/proximity_auth_webui_handler.cc
+++ b/chromeos/components/proximity_auth/webui/proximity_auth_webui_handler.cc
@@ -25,7 +25,7 @@
 #include "components/cryptauth/remote_device.h"
 #include "components/cryptauth/remote_device_loader.h"
 #include "components/cryptauth/secure_context.h"
-#include "components/cryptauth/secure_message_delegate.h"
+#include "components/cryptauth/secure_message_delegate_impl.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_ui.h"
@@ -370,7 +370,7 @@
           std::vector<cryptauth::ExternalDeviceInfo>(1, unlock_key),
           proximity_auth_client_->GetAccountId(),
           enrollment_manager->GetUserPrivateKey(),
-          proximity_auth_client_->CreateSecureMessageDelegate()));
+          cryptauth::SecureMessageDelegateImpl::Factory::NewInstance()));
       remote_device_loader_->Load(
           true /* should_load_beacon_seeds */,
           base::Bind(&ProximityAuthWebUIHandler::OnRemoteDevicesLoaded,
@@ -513,8 +513,7 @@
   }
 
   selected_remote_device_ = remote_devices[0];
-  life_cycle_.reset(new RemoteDeviceLifeCycleImpl(selected_remote_device_,
-                                                  proximity_auth_client_));
+  life_cycle_.reset(new RemoteDeviceLifeCycleImpl(selected_remote_device_));
   life_cycle_->AddObserver(this);
   life_cycle_->Start();
 }
diff --git a/chromeos/components/tether/asynchronous_shutdown_object_container_impl_unittest.cc b/chromeos/components/tether/asynchronous_shutdown_object_container_impl_unittest.cc
index 5147be7..0c03cc1 100644
--- a/chromeos/components/tether/asynchronous_shutdown_object_container_impl_unittest.cc
+++ b/chromeos/components/tether/asynchronous_shutdown_object_container_impl_unittest.cc
@@ -42,9 +42,7 @@
   std::unique_ptr<cryptauth::RemoteDeviceProvider> BuildInstance(
       cryptauth::CryptAuthDeviceManager* device_manager,
       const std::string& user_id,
-      const std::string& user_private_key,
-      cryptauth::SecureMessageDelegate::Factory*
-          secure_message_delegate_factory) override {
+      const std::string& user_private_key) override {
     return std::make_unique<cryptauth::FakeRemoteDeviceProvider>();
   }
 };
diff --git a/chromeos/dbus/services/org.chromium.VmApplicationsService.conf b/chromeos/dbus/services/org.chromium.VmApplicationsService.conf
new file mode 100644
index 0000000..98f6022
--- /dev/null
+++ b/chromeos/dbus/services/org.chromium.VmApplicationsService.conf
@@ -0,0 +1,19 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<!--
+  Copyright 2018 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.
+-->
+
+<busconfig>
+  <policy user="chronos">
+    <allow own="org.chromium.VmApplicationsService"/>
+  </policy>
+
+  <!-- The concierge service runs as crosvm -->
+  <policy user="crosvm">
+    <allow send_destination="org.chromium.VmApplicationsService"
+           send_interface="org.chromium.VmApplicationsService"/>
+  </policy>
+</busconfig>
diff --git a/chromeos/dbus/services/vm_applications_service_provider.cc b/chromeos/dbus/services/vm_applications_service_provider.cc
new file mode 100644
index 0000000..de391173
--- /dev/null
+++ b/chromeos/dbus/services/vm_applications_service_provider.cc
@@ -0,0 +1,60 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/dbus/services/vm_applications_service_provider.h"
+
+#include "base/bind.h"
+#include "chromeos/dbus/vm_applications/apps.pb.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+VmApplicationsServiceProvider::VmApplicationsServiceProvider(
+    std::unique_ptr<Delegate> delegate)
+    : delegate_(std::move(delegate)), weak_ptr_factory_(this) {}
+
+VmApplicationsServiceProvider::~VmApplicationsServiceProvider() = default;
+
+void VmApplicationsServiceProvider::Start(
+    scoped_refptr<dbus::ExportedObject> exported_object) {
+  exported_object->ExportMethod(
+      vm_tools::apps::kVmApplicationsServiceInterface,
+      vm_tools::apps::kVmApplicationsServiceUpdateApplicationListMethod,
+      base::BindRepeating(&VmApplicationsServiceProvider::UpdateApplicationList,
+                          weak_ptr_factory_.GetWeakPtr()),
+      base::BindRepeating(&VmApplicationsServiceProvider::OnExported,
+                          weak_ptr_factory_.GetWeakPtr()));
+}
+
+void VmApplicationsServiceProvider::OnExported(
+    const std::string& interface_name,
+    const std::string& method_name,
+    bool success) {
+  LOG_IF(ERROR, !success) << "Failed to export " << interface_name << "."
+                          << method_name;
+}
+
+void VmApplicationsServiceProvider::UpdateApplicationList(
+    dbus::MethodCall* method_call,
+    dbus::ExportedObject::ResponseSender response_sender) {
+  dbus::MessageReader reader(method_call);
+
+  vm_tools::apps::ApplicationList request;
+
+  if (!reader.PopArrayOfBytesAsProto(&request)) {
+    constexpr char error_message[] =
+        "Unable to parse ApplicationList from message";
+    LOG(ERROR) << error_message;
+    response_sender.Run(dbus::ErrorResponse::FromMethodCall(
+        method_call, DBUS_ERROR_INVALID_ARGS, error_message));
+    return;
+  }
+
+  delegate_->UpdateApplicationList(request);
+  response_sender.Run(dbus::Response::FromMethodCall(method_call));
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/services/vm_applications_service_provider.h b/chromeos/dbus/services/vm_applications_service_provider.h
new file mode 100644
index 0000000..04e65981
--- /dev/null
+++ b/chromeos/dbus/services/vm_applications_service_provider.h
@@ -0,0 +1,75 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_SERVICES_VM_APPLICATIONS_SERVICE_PROVIDER_H_
+#define CHROMEOS_DBUS_SERVICES_VM_APPLICATIONS_SERVICE_PROVIDER_H_
+
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/services/cros_dbus_service.h"
+#include "dbus/exported_object.h"
+
+namespace dbus {
+class MethodCall;
+}  // namespace dbus
+
+namespace vm_tools {
+namespace apps {
+class ApplicationList;
+}  // namespace apps
+}  // namespace vm_tools
+
+namespace chromeos {
+
+// This class exports D-Bus methods for functions that we want to be available
+// to the Crostini container.
+class CHROMEOS_EXPORT VmApplicationsServiceProvider
+    : public CrosDBusService::ServiceProviderInterface {
+ public:
+  // Delegate interface providing additional resources to
+  // VmApplicationsServiceProvider.
+  class Delegate {
+   public:
+    Delegate() = default;
+    virtual ~Delegate() = default;
+
+    virtual void UpdateApplicationList(
+        const vm_tools::apps::ApplicationList& app_list) = 0;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Delegate);
+  };
+
+  explicit VmApplicationsServiceProvider(std::unique_ptr<Delegate> delegate);
+  ~VmApplicationsServiceProvider() override;
+
+  // CrosDBusService::ServiceProviderInterface overrides:
+  void Start(scoped_refptr<dbus::ExportedObject> exported_object) override;
+
+ private:
+  // Called from ExportedObject when UpdateApplicationList() is exported as a
+  // D-Bus method or failed to be exported.
+  void OnExported(const std::string& interface_name,
+                  const std::string& method_name,
+                  bool success);
+
+  // Called on UI thread in response to a D-Bus request.
+  void UpdateApplicationList(
+      dbus::MethodCall* method_call,
+      dbus::ExportedObject::ResponseSender response_sender);
+
+  std::unique_ptr<Delegate> delegate_;
+
+  base::WeakPtrFactory<VmApplicationsServiceProvider> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(VmApplicationsServiceProvider);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_SERVICES_VM_APPLICATIONS_SERVICE_PROVIDER_H_
diff --git a/chromeos/services/device_sync/cryptauth_enroller_factory_impl.cc b/chromeos/services/device_sync/cryptauth_enroller_factory_impl.cc
index 0dc14538..77a9ac6 100644
--- a/chromeos/services/device_sync/cryptauth_enroller_factory_impl.cc
+++ b/chromeos/services/device_sync/cryptauth_enroller_factory_impl.cc
@@ -8,6 +8,7 @@
 
 #include "chromeos/services/device_sync/cryptauth_client_factory_impl.h"
 #include "components/cryptauth/cryptauth_enroller_impl.h"
+#include "components/cryptauth/secure_message_delegate_impl.h"
 
 namespace chromeos {
 
@@ -15,11 +16,9 @@
 
 CryptAuthEnrollerFactoryImpl::CryptAuthEnrollerFactoryImpl(
     identity::IdentityManager* identity_manager,
-    cryptauth::SecureMessageDelegate::Factory* secure_message_delegate_factory,
     scoped_refptr<net::URLRequestContextGetter> url_request_context,
     const cryptauth::DeviceClassifier& device_classifier)
     : identity_manager_(identity_manager),
-      secure_message_delegate_factory_(secure_message_delegate_factory),
       url_request_context_(url_request_context),
       device_classifier_(device_classifier) {}
 
@@ -30,7 +29,7 @@
   return std::make_unique<cryptauth::CryptAuthEnrollerImpl>(
       std::make_unique<CryptAuthClientFactoryImpl>(
           identity_manager_, url_request_context_, device_classifier_),
-      secure_message_delegate_factory_->CreateSecureMessageDelegate());
+      cryptauth::SecureMessageDelegateImpl::Factory::NewInstance());
 }
 
 }  // namespace device_sync
diff --git a/chromeos/services/device_sync/cryptauth_enroller_factory_impl.h b/chromeos/services/device_sync/cryptauth_enroller_factory_impl.h
index 2003e40..d0e9028 100644
--- a/chromeos/services/device_sync/cryptauth_enroller_factory_impl.h
+++ b/chromeos/services/device_sync/cryptauth_enroller_factory_impl.h
@@ -8,7 +8,6 @@
 #include "base/memory/ref_counted.h"
 #include "components/cryptauth/cryptauth_enroller.h"
 #include "components/cryptauth/proto/cryptauth_api.pb.h"
-#include "components/cryptauth/secure_message_delegate.h"
 #include "net/url_request/url_request_context_getter.h"
 
 namespace identity {
@@ -29,8 +28,6 @@
  public:
   CryptAuthEnrollerFactoryImpl(
       identity::IdentityManager* identity_manager,
-      cryptauth::SecureMessageDelegate::Factory*
-          secure_message_delegate_factory,
       scoped_refptr<net::URLRequestContextGetter> url_request_context,
       const cryptauth::DeviceClassifier& device_classifier);
   ~CryptAuthEnrollerFactoryImpl() override;
@@ -40,7 +37,6 @@
 
  private:
   identity::IdentityManager* identity_manager_;
-  cryptauth::SecureMessageDelegate::Factory* secure_message_delegate_factory_;
   const scoped_refptr<net::URLRequestContextGetter> url_request_context_;
   const cryptauth::DeviceClassifier device_classifier_;
 };
diff --git a/components/cryptauth/BUILD.gn b/components/cryptauth/BUILD.gn
index 3dbc56b..6151b25 100644
--- a/components/cryptauth/BUILD.gn
+++ b/components/cryptauth/BUILD.gn
@@ -81,6 +81,8 @@
     "secure_context.h",
     "secure_message_delegate.cc",
     "secure_message_delegate.h",
+    "secure_message_delegate_impl.cc",
+    "secure_message_delegate_impl.h",
     "session_keys.cc",
     "session_keys.h",
     "switches.cc",
@@ -95,6 +97,7 @@
 
   deps = [
     "//base",
+    "//chromeos",
     "//chromeos/components/proximity_auth/logging",
     "//components/cryptauth/ble",
     "//components/gcm_driver",
diff --git a/components/cryptauth/DEPS b/components/cryptauth/DEPS
index 2b6584ce..0779a592f 100644
--- a/components/cryptauth/DEPS
+++ b/components/cryptauth/DEPS
@@ -2,10 +2,15 @@
   "+components/gcm_driver",
   "+components/prefs",
   "+components/version_info/version_info.h",
-  # TODO(khorimoto): Remove this once CryptAuth is refactored into chromeos/.
+  # Note: //components/cryptauth will eventually migrate to //chromeos. As of
+  #       https://chromium-review.googlesource.com/c/chromium/src/+/984441,
+  #       //components/cryptauth is CrOS-only.
+  # TODO(khorimoto): Remove this once CryptAuth is refactored into //chromeos.
+  "+chromeos",
   "+chromeos/components/proximity_auth/logging",
   "+crypto",
   "+device/bluetooth",
   "+google_apis",
   "+net",
+  "+third_party/cros_system_api/dbus/service_constants.h",
 ]
diff --git a/components/cryptauth/cryptauth_enrollment_manager.h b/components/cryptauth/cryptauth_enrollment_manager.h
index 5b0bb5b..6efafb37 100644
--- a/components/cryptauth/cryptauth_enrollment_manager.h
+++ b/components/cryptauth/cryptauth_enrollment_manager.h
@@ -25,11 +25,11 @@
   class Observer {
    public:
     // Called when an enrollment attempt is started.
-    virtual void OnEnrollmentStarted() = 0;
+    virtual void OnEnrollmentStarted() {}
 
     // Called when an enrollment attempt finishes with the |success| of the
     // attempt.
-    virtual void OnEnrollmentFinished(bool success) = 0;
+    virtual void OnEnrollmentFinished(bool success) {}
 
     virtual ~Observer() = default;
   };
diff --git a/components/cryptauth/cryptauth_service.h b/components/cryptauth/cryptauth_service.h
index e774a6cc..f63a184c 100644
--- a/components/cryptauth/cryptauth_service.h
+++ b/components/cryptauth/cryptauth_service.h
@@ -9,7 +9,6 @@
 
 #include "base/macros.h"
 #include "components/cryptauth/proto/cryptauth_api.pb.h"
-#include "components/cryptauth/secure_message_delegate.h"
 #include "components/prefs/pref_registry_simple.h"
 
 namespace cryptauth {
@@ -19,7 +18,7 @@
 class CryptAuthEnrollmentManager;
 
 // Service which provides access to various CryptAuth singletons.
-class CryptAuthService : public SecureMessageDelegate::Factory {
+class CryptAuthService {
  public:
   static void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
@@ -32,7 +31,7 @@
 
  protected:
   CryptAuthService() = default;
-  ~CryptAuthService() override = default;
+  virtual ~CryptAuthService() = default;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(CryptAuthService);
diff --git a/components/cryptauth/fake_cryptauth_service.cc b/components/cryptauth/fake_cryptauth_service.cc
index 4fa3e34..38a5c76 100644
--- a/components/cryptauth/fake_cryptauth_service.cc
+++ b/components/cryptauth/fake_cryptauth_service.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "base/callback.h"
-#include "components/cryptauth/fake_secure_message_delegate.h"
 #include "components/cryptauth/mock_cryptauth_client.h"
 
 namespace cryptauth {
@@ -33,11 +32,6 @@
   return account_id_;
 }
 
-std::unique_ptr<SecureMessageDelegate>
-FakeCryptAuthService::CreateSecureMessageDelegate() {
-  return std::make_unique<FakeSecureMessageDelegate>();
-}
-
 std::unique_ptr<CryptAuthClientFactory>
 FakeCryptAuthService::CreateCryptAuthClientFactory() {
   return std::make_unique<MockCryptAuthClientFactory>(
diff --git a/components/cryptauth/fake_cryptauth_service.h b/components/cryptauth/fake_cryptauth_service.h
index ba5ac17..c19a8173 100644
--- a/components/cryptauth/fake_cryptauth_service.h
+++ b/components/cryptauth/fake_cryptauth_service.h
@@ -16,7 +16,6 @@
 class CryptAuthClientFactory;
 class CryptAuthDeviceManager;
 class CryptAuthEnrollmentManager;
-class SecureMessageDelegate;
 
 // Service which provides access to various CryptAuth singletons.
 class FakeCryptAuthService : public CryptAuthService {
@@ -47,7 +46,6 @@
   CryptAuthEnrollmentManager* GetCryptAuthEnrollmentManager() override;
   DeviceClassifier GetDeviceClassifier() override;
   std::string GetAccountId() override;
-  std::unique_ptr<SecureMessageDelegate> CreateSecureMessageDelegate() override;
   std::unique_ptr<CryptAuthClientFactory> CreateCryptAuthClientFactory()
       override;
 
diff --git a/components/cryptauth/remote_device_provider_impl.cc b/components/cryptauth/remote_device_provider_impl.cc
index a2a707ea..6e1d805 100644
--- a/components/cryptauth/remote_device_provider_impl.cc
+++ b/components/cryptauth/remote_device_provider_impl.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "components/cryptauth/remote_device_loader.h"
-#include "components/cryptauth/secure_message_delegate.h"
+#include "components/cryptauth/secure_message_delegate_impl.h"
 
 namespace cryptauth {
 
@@ -20,14 +20,12 @@
 RemoteDeviceProviderImpl::Factory::NewInstance(
     CryptAuthDeviceManager* device_manager,
     const std::string& user_id,
-    const std::string& user_private_key,
-    SecureMessageDelegate::Factory* secure_message_delegate_factory) {
+    const std::string& user_private_key) {
   if (!factory_instance_) {
     factory_instance_ = new Factory();
   }
   return factory_instance_->BuildInstance(device_manager, user_id,
-                                          user_private_key,
-                                          secure_message_delegate_factory);
+                                          user_private_key);
 }
 
 // static
@@ -40,27 +38,23 @@
 RemoteDeviceProviderImpl::Factory::BuildInstance(
     CryptAuthDeviceManager* device_manager,
     const std::string& user_id,
-    const std::string& user_private_key,
-    SecureMessageDelegate::Factory* secure_message_delegate_factory) {
+    const std::string& user_private_key) {
   return base::WrapUnique(
-      new RemoteDeviceProviderImpl(device_manager, user_id, user_private_key,
-                                   secure_message_delegate_factory));
+      new RemoteDeviceProviderImpl(device_manager, user_id, user_private_key));
 }
 
 RemoteDeviceProviderImpl::RemoteDeviceProviderImpl(
     CryptAuthDeviceManager* device_manager,
     const std::string& user_id,
-    const std::string& user_private_key,
-    SecureMessageDelegate::Factory* secure_message_delegate_factory)
+    const std::string& user_private_key)
     : device_manager_(device_manager),
       user_id_(user_id),
       user_private_key_(user_private_key),
-      secure_message_delegate_factory_(secure_message_delegate_factory),
       weak_ptr_factory_(this) {
   device_manager_->AddObserver(this);
   remote_device_loader_ = cryptauth::RemoteDeviceLoader::Factory::NewInstance(
       device_manager->GetSyncedDevices(), user_id, user_private_key,
-      secure_message_delegate_factory->CreateSecureMessageDelegate());
+      cryptauth::SecureMessageDelegateImpl::Factory::NewInstance());
   remote_device_loader_->Load(
       false /* should_load_beacon_seeds */,
       base::Bind(&RemoteDeviceProviderImpl::OnRemoteDevicesLoaded,
@@ -79,7 +73,7 @@
           CryptAuthDeviceManager::DeviceChangeResult::CHANGED) {
     remote_device_loader_ = cryptauth::RemoteDeviceLoader::Factory::NewInstance(
         device_manager_->GetSyncedDevices(), user_id_, user_private_key_,
-        secure_message_delegate_factory_->CreateSecureMessageDelegate());
+        cryptauth::SecureMessageDelegateImpl::Factory::NewInstance());
 
     remote_device_loader_->Load(
         false /* should_load_beacon_seeds */,
diff --git a/components/cryptauth/remote_device_provider_impl.h b/components/cryptauth/remote_device_provider_impl.h
index e1db57c..8a8a59d 100644
--- a/components/cryptauth/remote_device_provider_impl.h
+++ b/components/cryptauth/remote_device_provider_impl.h
@@ -7,7 +7,6 @@
 
 #include "components/cryptauth/cryptauth_device_manager.h"
 #include "components/cryptauth/remote_device_provider.h"
-#include "components/cryptauth/secure_message_delegate.h"
 
 namespace cryptauth {
 
@@ -22,8 +21,7 @@
     static std::unique_ptr<RemoteDeviceProvider> NewInstance(
         CryptAuthDeviceManager* device_manager,
         const std::string& user_id,
-        const std::string& user_private_key,
-        SecureMessageDelegate::Factory* secure_message_delegate_factory);
+        const std::string& user_private_key);
 
     static void SetInstanceForTesting(Factory* factory);
 
@@ -31,18 +29,15 @@
     virtual std::unique_ptr<RemoteDeviceProvider> BuildInstance(
         CryptAuthDeviceManager* device_manager,
         const std::string& user_id,
-        const std::string& user_private_key,
-        SecureMessageDelegate::Factory* secure_message_delegate_factory);
+        const std::string& user_private_key);
 
    private:
     static Factory* factory_instance_;
   };
 
-  RemoteDeviceProviderImpl(
-      CryptAuthDeviceManager* device_manager,
-      const std::string& user_id,
-      const std::string& user_private_key,
-      SecureMessageDelegate::Factory* secure_message_delegate_factory);
+  RemoteDeviceProviderImpl(CryptAuthDeviceManager* device_manager,
+                           const std::string& user_id,
+                           const std::string& user_private_key);
 
   ~RemoteDeviceProviderImpl() override;
 
@@ -66,7 +61,6 @@
   // The private key used to generate RemoteDevices.
   const std::string user_private_key_;
 
-  SecureMessageDelegate::Factory* secure_message_delegate_factory_;
   std::unique_ptr<RemoteDeviceLoader> remote_device_loader_;
   RemoteDeviceList synced_remote_devices_;
   base::WeakPtrFactory<RemoteDeviceProviderImpl> weak_ptr_factory_;
diff --git a/components/cryptauth/remote_device_provider_impl_unittest.cc b/components/cryptauth/remote_device_provider_impl_unittest.cc
index 588b9b8..a3bbf97 100644
--- a/components/cryptauth/remote_device_provider_impl_unittest.cc
+++ b/components/cryptauth/remote_device_provider_impl_unittest.cc
@@ -16,6 +16,7 @@
 #include "components/cryptauth/proto/cryptauth_api.pb.h"
 #include "components/cryptauth/remote_device_loader.h"
 #include "components/cryptauth/remote_device_test_util.h"
+#include "components/cryptauth/secure_message_delegate_impl.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -32,11 +33,10 @@
 const char kTestUserPrivateKey[] = "kTestUserPrivateKey";
 
 class FakeSecureMessageDelegateFactory
-    : public cryptauth::SecureMessageDelegate::Factory {
+    : public cryptauth::SecureMessageDelegateImpl::Factory {
  public:
-  // cryptauth::SecureMessageDelegate::Factory:
-  std::unique_ptr<cryptauth::SecureMessageDelegate>
-  CreateSecureMessageDelegate() override {
+  // cryptauth::SecureMessageDelegateImpl::Factory:
+  std::unique_ptr<cryptauth::SecureMessageDelegate> BuildInstance() override {
     cryptauth::FakeSecureMessageDelegate* delegate =
         new cryptauth::FakeSecureMessageDelegate();
     created_delegates_.push_back(delegate);
@@ -157,6 +157,8 @@
     fake_device_manager_ = std::make_unique<FakeCryptAuthDeviceManager>();
     fake_secure_message_delegate_factory_ =
         std::make_unique<FakeSecureMessageDelegateFactory>();
+    cryptauth::SecureMessageDelegateImpl::Factory::SetInstanceForTesting(
+        fake_secure_message_delegate_factory_.get());
     test_device_loader_factory_ =
         std::make_unique<FakeDeviceLoader::TestRemoteDeviceLoaderFactory>();
     cryptauth::RemoteDeviceLoader::Factory::SetInstanceForTesting(
@@ -164,10 +166,14 @@
     test_observer_ = std::make_unique<TestObserver>();
   }
 
+  void TearDown() override {
+    cryptauth::SecureMessageDelegateImpl::Factory::SetInstanceForTesting(
+        nullptr);
+  }
+
   void CreateRemoteDeviceProvider() {
     remote_device_provider_ = std::make_unique<RemoteDeviceProviderImpl>(
-        fake_device_manager_.get(), kTestUserId, kTestUserPrivateKey,
-        fake_secure_message_delegate_factory_.get());
+        fake_device_manager_.get(), kTestUserId, kTestUserPrivateKey);
     remote_device_provider_->AddObserver(test_observer_.get());
     EXPECT_EQ(0u, remote_device_provider_->GetSyncedDevices().size());
     test_device_loader_factory_->InvokeLastCallback(
diff --git a/components/cryptauth/secure_channel.cc b/components/cryptauth/secure_channel.cc
index a7e8c59..aac65ad 100644
--- a/components/cryptauth/secure_channel.cc
+++ b/components/cryptauth/secure_channel.cc
@@ -10,6 +10,7 @@
 #include "base/memory/ptr_util.h"
 #include "chromeos/components/proximity_auth/logging/logging.h"
 #include "components/cryptauth/cryptauth_service.h"
+#include "components/cryptauth/secure_message_delegate_impl.h"
 #include "components/cryptauth/wire_message.h"
 
 namespace cryptauth {
@@ -246,7 +247,7 @@
 
   authenticator_ = DeviceToDeviceAuthenticator::Factory::NewInstance(
       connection_.get(), connection_->remote_device().user_id,
-      cryptauth_service_->CreateSecureMessageDelegate());
+      cryptauth::SecureMessageDelegateImpl::Factory::NewInstance());
   authenticator_->Authenticate(
       base::Bind(&SecureChannel::OnAuthenticationResult,
                  weak_ptr_factory_.GetWeakPtr()));
diff --git a/components/cryptauth/secure_channel.h b/components/cryptauth/secure_channel.h
index a9b941af..82e0409 100644
--- a/components/cryptauth/secure_channel.h
+++ b/components/cryptauth/secure_channel.h
@@ -14,7 +14,6 @@
 #include "components/cryptauth/device_to_device_authenticator.h"
 #include "components/cryptauth/remote_device.h"
 #include "components/cryptauth/secure_context.h"
-#include "components/cryptauth/secure_message_delegate.h"
 
 namespace cryptauth {
 
diff --git a/components/cryptauth/secure_channel_unittest.cc b/components/cryptauth/secure_channel_unittest.cc
index bfcdbcc..6961a42 100644
--- a/components/cryptauth/secure_channel_unittest.cc
+++ b/components/cryptauth/secure_channel_unittest.cc
@@ -16,6 +16,7 @@
 #include "components/cryptauth/fake_secure_context.h"
 #include "components/cryptauth/fake_secure_message_delegate.h"
 #include "components/cryptauth/remote_device_test_util.h"
+#include "components/cryptauth/secure_message_delegate_impl.h"
 #include "components/cryptauth/wire_message.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -43,6 +44,15 @@
   std::string payload;
 };
 
+class FakeSecureMessageDelegateFactory
+    : public cryptauth::SecureMessageDelegateImpl::Factory {
+ public:
+  // cryptauth::SecureMessageDelegateImpl::Factory:
+  std::unique_ptr<cryptauth::SecureMessageDelegate> BuildInstance() override {
+    return std::make_unique<FakeSecureMessageDelegate>();
+  }
+};
+
 class TestObserver final : public SecureChannel::Observer {
  public:
   TestObserver(SecureChannel* secure_channel)
@@ -170,6 +180,11 @@
     DeviceToDeviceAuthenticator::Factory::SetInstanceForTesting(
         test_authenticator_factory_.get());
 
+    fake_secure_message_delegate_factory_ =
+        std::make_unique<FakeSecureMessageDelegateFactory>();
+    cryptauth::SecureMessageDelegateImpl::Factory::SetInstanceForTesting(
+        fake_secure_message_delegate_factory_.get());
+
     fake_secure_context_ = nullptr;
 
     fake_cryptauth_service_ = std::make_unique<FakeCryptAuthService>();
@@ -201,6 +216,9 @@
 
     if (!has_verified_gatt_services_event_)
       EXPECT_EQ(0, test_observer_->num_gatt_services_unavailable_events());
+
+    cryptauth::SecureMessageDelegateImpl::Factory::SetInstanceForTesting(
+        nullptr);
   }
 
   void VerifyConnectionStateChanges(
@@ -356,6 +374,9 @@
   // Owned by secure_channel_.
   FakeConnection* fake_connection_;
 
+  std::unique_ptr<FakeSecureMessageDelegateFactory>
+      fake_secure_message_delegate_factory_;
+
   std::unique_ptr<FakeCryptAuthService> fake_cryptauth_service_;
 
   // Owned by secure_channel_ once authentication has completed successfully.
diff --git a/components/cryptauth/secure_message_delegate.h b/components/cryptauth/secure_message_delegate.h
index e4cfd48..2f02f58d 100644
--- a/components/cryptauth/secure_message_delegate.h
+++ b/components/cryptauth/secure_message_delegate.h
@@ -18,14 +18,6 @@
 // implementation on ChromeOS communicates with a daemon process over IPC.
 class SecureMessageDelegate {
  public:
-  class Factory {
-   public:
-    virtual std::unique_ptr<SecureMessageDelegate>
-    CreateSecureMessageDelegate() = 0;
-
-    virtual ~Factory() = default;
-  };
-
   // Fields specifying how to create a SecureMessage.
   struct CreateOptions {
     CreateOptions();
diff --git a/chrome/browser/chromeos/login/easy_unlock/secure_message_delegate_chromeos.cc b/components/cryptauth/secure_message_delegate_impl.cc
similarity index 72%
rename from chrome/browser/chromeos/login/easy_unlock/secure_message_delegate_chromeos.cc
rename to components/cryptauth/secure_message_delegate_impl.cc
index 9807947db..83a7447 100644
--- a/chrome/browser/chromeos/login/easy_unlock/secure_message_delegate_chromeos.cc
+++ b/components/cryptauth/secure_message_delegate_impl.cc
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/login/easy_unlock/secure_message_delegate_chromeos.h"
+#include "components/cryptauth/secure_message_delegate_impl.h"
 
 #include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/no_destructor.h"
 #include "chromeos/components/proximity_auth/logging/logging.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/easy_unlock_client.h"
@@ -12,7 +14,7 @@
 
 using cryptauth::SecureMessageDelegate;
 
-namespace chromeos {
+namespace cryptauth {
 namespace {
 
 // Converts encryption type to a string representation used by EasyUnlock dbus
@@ -71,25 +73,51 @@
 
 }  // namespace
 
-SecureMessageDelegateChromeOS::SecureMessageDelegateChromeOS()
-    : dbus_client_(DBusThreadManager::Get()->GetEasyUnlockClient()) {}
+// static
+SecureMessageDelegateImpl::Factory*
+    SecureMessageDelegateImpl::Factory::test_factory_instance_ = nullptr;
 
-SecureMessageDelegateChromeOS::~SecureMessageDelegateChromeOS() {}
+// static
+std::unique_ptr<SecureMessageDelegate>
+SecureMessageDelegateImpl::Factory::NewInstance() {
+  if (test_factory_instance_)
+    return test_factory_instance_->BuildInstance();
 
-void SecureMessageDelegateChromeOS::GenerateKeyPair(
+  static base::NoDestructor<SecureMessageDelegateImpl::Factory> factory;
+  return factory->BuildInstance();
+}
+
+// static
+void SecureMessageDelegateImpl::Factory::SetInstanceForTesting(
+    Factory* test_factory) {
+  test_factory_instance_ = test_factory;
+}
+
+SecureMessageDelegateImpl::Factory::~Factory() = default;
+
+std::unique_ptr<SecureMessageDelegate>
+SecureMessageDelegateImpl::Factory::BuildInstance() {
+  return base::WrapUnique(new SecureMessageDelegateImpl());
+}
+
+SecureMessageDelegateImpl::SecureMessageDelegateImpl()
+    : dbus_client_(chromeos::DBusThreadManager::Get()->GetEasyUnlockClient()) {}
+
+SecureMessageDelegateImpl::~SecureMessageDelegateImpl() {}
+
+void SecureMessageDelegateImpl::GenerateKeyPair(
     const GenerateKeyPairCallback& callback) {
   dbus_client_->GenerateEcP256KeyPair(
       base::Bind(HandleKeyPairResult, callback));
 }
 
-void SecureMessageDelegateChromeOS::DeriveKey(
-    const std::string& private_key,
-    const std::string& public_key,
-    const DeriveKeyCallback& callback) {
+void SecureMessageDelegateImpl::DeriveKey(const std::string& private_key,
+                                          const std::string& public_key,
+                                          const DeriveKeyCallback& callback) {
   dbus_client_->PerformECDHKeyAgreement(private_key, public_key, callback);
 }
 
-void SecureMessageDelegateChromeOS::CreateSecureMessage(
+void SecureMessageDelegateImpl::CreateSecureMessage(
     const std::string& payload,
     const std::string& key,
     const CreateOptions& create_options,
@@ -101,7 +129,7 @@
     return;
   }
 
-  EasyUnlockClient::CreateSecureMessageOptions options;
+  chromeos::EasyUnlockClient::CreateSecureMessageOptions options;
   options.key.assign(key);
 
   if (!create_options.associated_data.empty())
@@ -122,7 +150,7 @@
   dbus_client_->CreateSecureMessage(payload, options, callback);
 }
 
-void SecureMessageDelegateChromeOS::UnwrapSecureMessage(
+void SecureMessageDelegateImpl::UnwrapSecureMessage(
     const std::string& serialized_message,
     const std::string& key,
     const UnwrapOptions& unwrap_options,
@@ -134,7 +162,7 @@
     return;
   }
 
-  EasyUnlockClient::UnwrapSecureMessageOptions options;
+  chromeos::EasyUnlockClient::UnwrapSecureMessageOptions options;
   options.key.assign(key);
 
   if (!unwrap_options.associated_data.empty())
@@ -147,4 +175,4 @@
                                     base::Bind(&HandleUnwrapResult, callback));
 }
 
-}  // namespace chromeos
+}  // namespace cryptauth
diff --git a/components/cryptauth/secure_message_delegate_impl.h b/components/cryptauth/secure_message_delegate_impl.h
new file mode 100644
index 0000000..3232831
--- /dev/null
+++ b/components/cryptauth/secure_message_delegate_impl.h
@@ -0,0 +1,61 @@
+// 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.
+
+#ifndef COMPONENTS_CRYPTAUTH_SECURE_MESSAGE_DELEGATE_IMPL_H_
+#define COMPONENTS_CRYPTAUTH_SECURE_MESSAGE_DELEGATE_IMPL_H_
+
+#include "base/macros.h"
+#include "components/cryptauth/secure_message_delegate.h"
+
+namespace chromeos {
+class EasyUnlockClient;
+}  // namespace chromeos
+
+namespace cryptauth {
+
+// Concrete SecureMessageDelegate implementation.
+class SecureMessageDelegateImpl : public SecureMessageDelegate {
+ public:
+  class Factory {
+   public:
+    static std::unique_ptr<SecureMessageDelegate> NewInstance();
+    static void SetInstanceForTesting(Factory* test_factory);
+
+    virtual ~Factory();
+    virtual std::unique_ptr<SecureMessageDelegate> BuildInstance();
+
+   private:
+    static Factory* test_factory_instance_;
+  };
+
+  ~SecureMessageDelegateImpl() override;
+
+  // SecureMessageDelegate:
+  void GenerateKeyPair(const GenerateKeyPairCallback& callback) override;
+  void DeriveKey(const std::string& private_key,
+                 const std::string& public_key,
+                 const DeriveKeyCallback& callback) override;
+  void CreateSecureMessage(
+      const std::string& payload,
+      const std::string& key,
+      const CreateOptions& create_options,
+      const CreateSecureMessageCallback& callback) override;
+  void UnwrapSecureMessage(
+      const std::string& serialized_message,
+      const std::string& key,
+      const UnwrapOptions& unwrap_options,
+      const UnwrapSecureMessageCallback& callback) override;
+
+ private:
+  SecureMessageDelegateImpl();
+
+  // Not owned by this instance.
+  chromeos::EasyUnlockClient* dbus_client_;
+
+  DISALLOW_COPY_AND_ASSIGN(SecureMessageDelegateImpl);
+};
+
+}  // namespace cryptauth
+
+#endif  // COMPONENTS_CRYPTAUTH_SECURE_MESSAGE_DELEGATE_IMPL_H_
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc
index 36e470d..8b694811 100644
--- a/components/exo/shell_surface_base.cc
+++ b/components/exo/shell_surface_base.cc
@@ -56,6 +56,9 @@
 // Application Id set by the client.
 DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kApplicationIdKey, nullptr);
 
+// Application Id set by the client.
+DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kStartupIdKey, nullptr);
+
 // The accelerator keys used to close ShellSurfaces.
 const struct {
   ui::KeyboardCode keycode;
@@ -524,6 +527,25 @@
     SetApplicationId(widget_->GetNativeWindow(), application_id);
 }
 
+// static
+void ShellSurfaceBase::SetStartupId(aura::Window* window,
+                                    const std::string& id) {
+  TRACE_EVENT1("exo", "ShellSurfaceBase::SetStartupId", "startup_id", id);
+  window->SetProperty(kStartupIdKey, new std::string(id));
+}
+
+// static
+const std::string* ShellSurfaceBase::GetStartupId(aura::Window* window) {
+  return window->GetProperty(kStartupIdKey);
+}
+
+void ShellSurfaceBase::SetStartupId(const char* startup_id) {
+  // Store the value in |startup_id_| in case the window does not exist yet.
+  startup_id_ = std::string(startup_id);
+  if (widget_ && widget_->GetNativeWindow())
+    SetStartupId(widget_->GetNativeWindow(), startup_id);
+}
+
 void ShellSurfaceBase::Close() {
   if (!close_callback_.is_null())
     close_callback_.Run();
@@ -610,6 +632,12 @@
 
     if (application_id)
       value->SetString("application_id", *application_id);
+
+    const std::string* startup_id =
+        GetStartupId(GetWidget()->GetNativeWindow());
+
+    if (startup_id)
+      value->SetString("startup_id", *startup_id);
   }
   return value;
 }
@@ -766,6 +794,10 @@
   }
 }
 
+void ShellSurfaceBase::OnSetStartupId(const char* startup_id) {
+  SetStartupId(startup_id);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // SurfaceObserver overrides:
 
@@ -1120,6 +1152,7 @@
   window->SetEventTargeter(base::WrapUnique(
       new CustomWindowTargeter(widget_, client_controlled_move_resize_)));
   SetApplicationId(window, application_id_);
+  SetStartupId(window, startup_id_);
   SetMainSurface(window, root_surface());
 
   // Start tracking changes to window bounds and window state.
diff --git a/components/exo/shell_surface_base.h b/components/exo/shell_surface_base.h
index 266d6f6..64c6ed8 100644
--- a/components/exo/shell_surface_base.h
+++ b/components/exo/shell_surface_base.h
@@ -121,6 +121,14 @@
   // Set the application ID for the surface.
   void SetApplicationId(const std::string& application_id);
 
+  // Sets the startup ID for the window. The startup ID identifies the
+  // application using startup notification protocol.
+  static void SetStartupId(aura::Window* window, const std::string& id);
+  static const std::string* GetStartupId(aura::Window* window);
+
+  // Set the startup ID for the surface.
+  void SetStartupId(const char* startup_id);
+
   // Signal a request to close the window. It is up to the implementation to
   // actually decide to do so though.
   void Close();
@@ -165,6 +173,7 @@
   void OnSetFrame(SurfaceFrameType type) override;
   void OnSetFrameColors(SkColor active_color, SkColor inactive_color) override;
   void OnSetParent(Surface* parent, const gfx::Point& position) override;
+  void OnSetStartupId(const char* startup_id) override;
 
   // Overridden from SurfaceObserver:
   void OnSurfaceDestroying(Surface* surface) override;
@@ -338,6 +347,7 @@
   SkColor inactive_frame_color_ = SK_ColorBLACK;
   bool pending_show_widget_ = false;
   std::string application_id_;
+  std::string startup_id_;
   gfx::Rect geometry_;
   gfx::Rect pending_geometry_;
   base::RepeatingClosure close_callback_;
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc
index 3ec59b94..845a990c 100644
--- a/components/exo/shell_surface_unittest.cc
+++ b/components/exo/shell_surface_unittest.cc
@@ -252,6 +252,24 @@
   EXPECT_EQ("test", *ShellSurface::GetApplicationId(window));
 }
 
+TEST_F(ShellSurfaceTest, SetStartupId) {
+  gfx::Size buffer_size(64, 64);
+  std::unique_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+  std::unique_ptr<Surface> surface(new Surface);
+  std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+
+  EXPECT_FALSE(shell_surface->GetWidget());
+  shell_surface->SetStartupId("pre-widget-id");
+
+  surface->Attach(buffer.get());
+  surface->Commit();
+  aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
+  EXPECT_EQ("pre-widget-id", *ShellSurface::GetStartupId(window));
+  shell_surface->SetStartupId("test");
+  EXPECT_EQ("test", *ShellSurface::GetStartupId(window));
+}
+
 TEST_F(ShellSurfaceTest, Move) {
   std::unique_ptr<Surface> surface(new Surface);
   std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
diff --git a/components/exo/sub_surface.h b/components/exo/sub_surface.h
index acd775e..cb55462 100644
--- a/components/exo/sub_surface.h
+++ b/components/exo/sub_surface.h
@@ -56,6 +56,7 @@
   void OnSetFrameColors(SkColor active_color, SkColor inactive_color) override {
   }
   void OnSetParent(Surface* parent, const gfx::Point& position) override {}
+  void OnSetStartupId(const char* startup_id) override {}
 
   // Overridden from SurfaceObserver:
   void OnSurfaceDestroying(Surface* surface) override;
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index cb4793db..5b197534 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -447,6 +447,13 @@
     delegate_->OnSetFrameColors(active_color, inactive_color);
 }
 
+void Surface::SetStartupId(const char* startup_id) {
+  TRACE_EVENT1("exo", "Surface::SetStartupId", "startup_id", startup_id);
+
+  if (delegate_)
+    delegate_->OnSetStartupId(startup_id);
+}
+
 void Surface::SetParent(Surface* parent, const gfx::Point& position) {
   TRACE_EVENT2("exo", "Surface::SetParent", "parent", !!parent, "position",
                position.ToString());
diff --git a/components/exo/surface.h b/components/exo/surface.h
index 54215f6..a3610ac 100644
--- a/components/exo/surface.h
+++ b/components/exo/surface.h
@@ -145,6 +145,9 @@
   // Request that surface should use a specific set of frame colors.
   void SetFrameColors(SkColor active_color, SkColor inactive_color);
 
+  // Request that surface should have a specific startup_id string.
+  void SetStartupId(const char* startup_id);
+
   // Request "parent" for surface.
   void SetParent(Surface* parent, const gfx::Point& position);
 
diff --git a/components/exo/surface_delegate.h b/components/exo/surface_delegate.h
index 4b5ed49..b9cbb527 100644
--- a/components/exo/surface_delegate.h
+++ b/components/exo/surface_delegate.h
@@ -38,6 +38,9 @@
   // is the initial position of surface relative to origin of parent.
   virtual void OnSetParent(Surface* parent, const gfx::Point& position) = 0;
 
+  // Called when surface was requested to set a specific startup ID label.
+  virtual void OnSetStartupId(const char* startup_id) = 0;
+
  protected:
   virtual ~SurfaceDelegate() {}
 };
diff --git a/components/exo/surface_tree_host.h b/components/exo/surface_tree_host.h
index 51c0dad3..65fe76d 100644
--- a/components/exo/surface_tree_host.h
+++ b/components/exo/surface_tree_host.h
@@ -91,6 +91,7 @@
   void OnSetFrameColors(SkColor active_color, SkColor inactive_color) override {
   }
   void OnSetParent(Surface* parent, const gfx::Point& position) override {}
+  void OnSetStartupId(const char* startup_id) override {}
 
   // Overridden from cc::BeginFrameObserverBase:
   bool OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) override;
diff --git a/components/exo/wayland/aura-shell-client-protocol.h b/components/exo/wayland/aura-shell-client-protocol.h
index bdee99af..cd8dbf4 100644
--- a/components/exo/wayland/aura-shell-client-protocol.h
+++ b/components/exo/wayland/aura-shell-client-protocol.h
@@ -218,7 +218,7 @@
 #define ZAURA_SURFACE_SET_FRAME 0
 #define ZAURA_SURFACE_SET_PARENT 1
 #define ZAURA_SURFACE_SET_FRAME_COLORS 2
-
+#define ZAURA_SURFACE_SET_STARTUP_ID 3
 
 /**
  * @ingroup iface_zaura_surface
@@ -232,6 +232,10 @@
  * @ingroup iface_zaura_surface
  */
 #define ZAURA_SURFACE_SET_FRAME_COLORS_SINCE_VERSION 3
+/**
+ * @ingroup iface_zaura_surface
+ */
+#define ZAURA_SURFACE_SET_STARTUP_ID_SINCE_VERSION 4
 
 /** @ingroup iface_zaura_surface */
 static inline void
@@ -297,6 +301,18 @@
 			 ZAURA_SURFACE_SET_FRAME_COLORS, active_color, inactive_color);
 }
 
+/**
+ * @ingroup iface_zaura_surface
+ *
+ * Set the startup ID.
+ */
+static inline void zaura_surface_set_startup_id(
+    struct zaura_surface* zaura_surface,
+    const char* startup_id) {
+  wl_proxy_marshal((struct wl_proxy*)zaura_surface,
+                   ZAURA_SURFACE_SET_STARTUP_ID, startup_id);
+}
+
 #ifndef ZAURA_OUTPUT_SCALE_PROPERTY_ENUM
 #define ZAURA_OUTPUT_SCALE_PROPERTY_ENUM
 /**
diff --git a/components/exo/wayland/aura-shell-protocol.c b/components/exo/wayland/aura-shell-protocol.c
index 1e6d424..894f282 100644
--- a/components/exo/wayland/aura-shell-protocol.c
+++ b/components/exo/wayland/aura-shell-protocol.c
@@ -50,7 +50,7 @@
 };
 
 WL_EXPORT const struct wl_interface zaura_shell_interface = {
-	"zaura_shell", 3,
+	"zaura_shell", 4,
 	2, zaura_shell_requests,
 	0, NULL,
 };
@@ -59,11 +59,12 @@
 	{ "set_frame", "u", types + 0 },
 	{ "set_parent", "2?oii", types + 6 },
 	{ "set_frame_colors", "3uu", types + 0 },
+	{ "set_startup_id", "4?s", types + 0 },
 };
 
 WL_EXPORT const struct wl_interface zaura_surface_interface = {
-	"zaura_surface", 3,
-	3, zaura_surface_requests,
+	"zaura_surface", 4,
+	4, zaura_surface_requests,
 	0, NULL,
 };
 
diff --git a/components/exo/wayland/aura-shell-server-protocol.h b/components/exo/wayland/aura-shell-server-protocol.h
index e306f8d9..1a128634 100644
--- a/components/exo/wayland/aura-shell-server-protocol.h
+++ b/components/exo/wayland/aura-shell-server-protocol.h
@@ -224,6 +224,15 @@
 				 struct wl_resource *resource,
 				 uint32_t active_color,
 				 uint32_t inactive_color);
+        /**
+         * set the startup ID of this surface
+         *
+         * Set the startup ID.
+         * @since 4
+         */
+        void (*set_startup_id)(struct wl_client* client,
+                               struct wl_resource* resource,
+                               const char* startup_id);
 };
 
 
@@ -239,6 +248,10 @@
  * @ingroup iface_zaura_surface
  */
 #define ZAURA_SURFACE_SET_FRAME_COLORS_SINCE_VERSION 3
+/**
+ * @ingroup iface_zaura_surface
+ */
+#define ZAURA_SURFACE_SET_STARTUP_ID_SINCE_VERSION 4
 
 #ifndef ZAURA_OUTPUT_SCALE_PROPERTY_ENUM
 #define ZAURA_OUTPUT_SCALE_PROPERTY_ENUM
diff --git a/components/exo/wayland/protocol/aura-shell.xml b/components/exo/wayland/protocol/aura-shell.xml
index 549b288..f947fff 100644
--- a/components/exo/wayland/protocol/aura-shell.xml
+++ b/components/exo/wayland/protocol/aura-shell.xml
@@ -24,7 +24,7 @@
     DEALINGS IN THE SOFTWARE.
   </copyright>
 
-  <interface name="zaura_shell" version="3">
+  <interface name="zaura_shell" version="4">
     <description summary="aura_shell">
       The global interface exposing aura shell capabilities is used to
       instantiate an interface extension for a wl_surface object.
@@ -68,7 +68,7 @@
     </request>
   </interface>
 
-  <interface name="zaura_surface" version="3">
+  <interface name="zaura_surface" version="4">
     <description summary="aura shell interface to a wl_surface">
       An additional interface to a wl_surface object, which allows the
       client to access aura shell specific functionality for surface.
@@ -111,6 +111,15 @@
       <arg name="active_color" type="uint" summary="32 bit ARGB color value, not premultiplied"/>
       <arg name="inactive_color" type="uint" summary="32 bit ARGB color value, not premultiplied"/>
     </request>
+
+    <!-- Version 4 additions -->
+
+    <request name="set_startup_id" since="4">
+      <description summary="set the startup ID of this surface">
+	Set the startup ID.
+      </description>
+      <arg name="startup_id" type="string" allow-null="true"/>
+    </request>
   </interface>
 
   <interface name="zaura_output" version="2">
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index 3e3295f6..c8f3424 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -2708,6 +2708,11 @@
       surface_->SetParent(parent ? parent->surface_ : nullptr, position);
   }
 
+  void SetStartupId(const char* startup_id) {
+    if (surface_)
+      surface_->SetStartupId(startup_id);
+  }
+
   // Overridden from SurfaceObserver:
   void OnSurfaceDestroying(Surface* surface) override {
     surface->RemoveSurfaceObserver(this);
@@ -2757,9 +2762,15 @@
                                                        inactive_color);
 }
 
+void aura_surface_set_startup_id(wl_client* client,
+                                 wl_resource* resource,
+                                 const char* startup_id) {
+  GetUserDataAs<AuraSurface>(resource)->SetStartupId(startup_id);
+}
+
 const struct zaura_surface_interface aura_surface_implementation = {
     aura_surface_set_frame, aura_surface_set_parent,
-    aura_surface_set_frame_colors};
+    aura_surface_set_frame_colors, aura_surface_set_startup_id};
 
 ////////////////////////////////////////////////////////////////////////////////
 // aura_output_interface:
@@ -2850,7 +2861,7 @@
 const struct zaura_shell_interface aura_shell_implementation = {
     aura_shell_get_aura_surface, aura_shell_get_aura_output};
 
-const uint32_t aura_shell_version = 3;
+const uint32_t aura_shell_version = 4;
 
 void bind_aura_shell(wl_client* client,
                      void* data,
diff --git a/components/guest_view/browser/guest_view_base.cc b/components/guest_view/browser/guest_view_base.cc
index 865dec7..d291c77 100644
--- a/components/guest_view/browser/guest_view_base.cc
+++ b/components/guest_view/browser/guest_view_base.cc
@@ -299,10 +299,12 @@
   enable_auto_size &= !min_auto_size_.IsEmpty() && !max_auto_size_.IsEmpty() &&
                       IsAutoSizeSupported();
 
-  content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
+  content::RenderWidgetHostView* rwhv =
+      web_contents()->GetRenderWidgetHostView();
   if (enable_auto_size) {
     // Autosize is being enabled.
-    rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
+    if (rwhv)
+      rwhv->EnableAutoResize(min_auto_size_, max_auto_size_);
     normal_size_.SetSize(0, 0);
   } else {
     // Autosize is being disabled.
@@ -324,7 +326,8 @@
     bool changed_due_to_auto_resize = false;
     if (auto_size_enabled_) {
       // Autosize was previously enabled.
-      rvh->DisableAutoResize(new_size);
+      if (rwhv)
+        rwhv->DisableAutoResize(new_size);
       changed_due_to_auto_resize = true;
     } else {
       // Autosize was already disabled.
diff --git a/components/ntp_snippets/mock_content_suggestions_provider.cc b/components/ntp_snippets/mock_content_suggestions_provider.cc
index f7e9adc..46dc34f 100644
--- a/components/ntp_snippets/mock_content_suggestions_provider.cc
+++ b/components/ntp_snippets/mock_content_suggestions_provider.cc
@@ -67,7 +67,7 @@
 void MockContentSuggestionsProvider::FetchSuggestionImageData(
     const ContentSuggestion::ID& id,
     ImageDataFetchedCallback callback) {
-  FetchSuggestionImageDataMock(id, callback);
+  FetchSuggestionImageDataMock(id, &callback);
 }
 
 void MockContentSuggestionsProvider::FireSuggestionsChanged(
diff --git a/components/ntp_snippets/mock_content_suggestions_provider.h b/components/ntp_snippets/mock_content_suggestions_provider.h
index 9c9dfc4..7cabecf 100644
--- a/components/ntp_snippets/mock_content_suggestions_provider.h
+++ b/components/ntp_snippets/mock_content_suggestions_provider.h
@@ -81,8 +81,7 @@
   MOCK_METHOD2(FetchSuggestionImageMock,
                void(const ContentSuggestion::ID&, const ImageFetchedCallback&));
   MOCK_METHOD2(FetchSuggestionImageDataMock,
-               void(const ContentSuggestion::ID&,
-                    const ImageDataFetchedCallback&));
+               void(const ContentSuggestion::ID&, ImageDataFetchedCallback*));
 
  private:
   std::vector<Category> provided_categories_;
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.cc b/components/offline_pages/core/model/offline_page_model_taskified.cc
index 6627e0c..6e83c768 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.cc
+++ b/components/offline_pages/core/model/offline_page_model_taskified.cc
@@ -22,11 +22,14 @@
 #include "components/offline_pages/core/archive_manager.h"
 #include "components/offline_pages/core/client_namespace_constants.h"
 #include "components/offline_pages/core/model/add_page_task.h"
+#include "components/offline_pages/core/model/cleanup_thumbnails_task.h"
 #include "components/offline_pages/core/model/delete_page_task.h"
 #include "components/offline_pages/core/model/get_pages_task.h"
+#include "components/offline_pages/core/model/get_thumbnail_task.h"
 #include "components/offline_pages/core/model/mark_page_accessed_task.h"
 #include "components/offline_pages/core/model/offline_page_model_utils.h"
 #include "components/offline_pages/core/model/startup_maintenance_task.h"
+#include "components/offline_pages/core/model/store_thumbnail_task.h"
 #include "components/offline_pages/core/model/update_file_path_task.h"
 #include "components/offline_pages/core/offline_page_feature.h"
 #include "components/offline_pages/core/offline_page_metadata_store_sql.h"
@@ -385,6 +388,21 @@
   task_queue_.AddTask(std::move(task));
 }
 
+void OfflinePageModelTaskified::StoreThumbnail(
+    const OfflinePageThumbnail& thumb) {
+  task_queue_.AddTask(std::make_unique<StoreThumbnailTask>(
+      store_.get(), thumb,
+      base::BindOnce(&OfflinePageModelTaskified::OnStoreThumbnailDone,
+                     weak_ptr_factory_.GetWeakPtr(), thumb)));
+}
+
+void OfflinePageModelTaskified::GetThumbnailByOfflineId(
+    int64_t offline_id,
+    base::OnceCallback<void(std::unique_ptr<OfflinePageThumbnail>)> callback) {
+  task_queue_.AddTask(std::make_unique<GetThumbnailTask>(
+      store_.get(), offline_id, std::move(callback)));
+}
+
 const base::FilePath& OfflinePageModelTaskified::GetInternalArchiveDirectory(
     const std::string& name_space) const {
   if (policy_controller_->IsRemovedOnCacheReset(name_space))
@@ -622,6 +640,15 @@
     callback.Run(result);
 }
 
+void OfflinePageModelTaskified::OnStoreThumbnailDone(
+    const OfflinePageThumbnail& thumbnail,
+    bool success) {
+  if (success) {
+    for (Observer& observer : observers_)
+      observer.ThumbnailAdded(this, thumbnail);
+  }
+}
+
 void OfflinePageModelTaskified::RemoveFromDownloadManager(
     SystemDownloadManager* download_manager,
     const std::vector<int64_t>& system_download_ids) {
@@ -656,6 +683,9 @@
   if (first_run) {
     task_queue_.AddTask(std::make_unique<StartupMaintenanceTask>(
         store_.get(), archive_manager_.get(), policy_controller_.get()));
+
+    task_queue_.AddTask(std::make_unique<CleanupThumbnailsTask>(
+        store_.get(), GetCurrentTime(), base::DoNothing()));
   }
 
   task_queue_.AddTask(std::make_unique<ClearStorageTask>(
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.h b/components/offline_pages/core/model/offline_page_model_taskified.h
index 489d5af..867bf9a 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.h
+++ b/components/offline_pages/core/model/offline_page_model_taskified.h
@@ -125,10 +125,14 @@
       int64_t file_size,
       const std::string& digest,
       const SingleOfflinePageItemCallback& callback) override;
-
   void GetOfflineIdsForClientId(
       const ClientId& client_id,
       const MultipleOfflineIdCallback& callback) override;
+  void StoreThumbnail(const OfflinePageThumbnail& thumb) override;
+  void GetThumbnailByOfflineId(
+      int64_t offline_id,
+      base::OnceCallback<void(std::unique_ptr<OfflinePageThumbnail>)> callback)
+      override;
 
   const base::FilePath& GetInternalArchiveDirectory(
       const std::string& name_space) const override;
@@ -190,6 +194,9 @@
       DeletePageResult result,
       const std::vector<OfflinePageModel::DeletedPageInfo>& infos);
 
+  void OnStoreThumbnailDone(const OfflinePageThumbnail& thumbnail,
+                            bool success);
+
   // Methods for clearing temporary pages and performing consistency checks. The
   // latter are executed only once per Chrome session.
   void ScheduleMaintenanceTasks();
diff --git a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
index 71ce6da..ac5e0b7 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
+++ b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/histogram_tester.h"
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_feature_list.h"
@@ -122,6 +123,9 @@
                         const OfflinePageItem& added_page) override;
   void OfflinePageDeleted(
       const OfflinePageModel::DeletedPageInfo& page_info) override;
+  MOCK_METHOD2(ThumbnailAdded,
+               void(OfflinePageModel* model,
+                    const OfflinePageThumbnail& added_thumbnail));
 
   // OfflinePageTestArchiver::Observer implementation.
   void SetLastPathCreatedByArchiver(const base::FilePath& file_path) override;
@@ -185,6 +189,20 @@
     return model_->last_maintenance_tasks_schedule_time_;
   }
 
+  std::unique_ptr<OfflinePageThumbnail> GetThumbnailSync(int64_t offline_id) {
+    bool called = false;
+    std::unique_ptr<OfflinePageThumbnail> result;
+    auto callback = base::BindLambdaForTesting(
+        [&](std::unique_ptr<OfflinePageThumbnail> thumbnail) {
+          called = true;
+          result = std::move(thumbnail);
+        });
+    model_->GetThumbnailByOfflineId(offline_id, callback);
+    PumpLoop();
+    EXPECT_TRUE(called);
+    return result;
+  }
+
  private:
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
   base::ThreadTaskRunnerHandle task_runner_handle_;
@@ -224,6 +242,7 @@
 }
 
 void OfflinePageModelTaskifiedTest::TearDown() {
+  SCOPED_TRACE("in TearDown");
   CheckTaskQueueIdle();
   store_test_util_.DeleteStore();
   if (temporary_dir_.IsValid()) {
@@ -1466,6 +1485,16 @@
 }
 
 TEST_F(OfflinePageModelTaskifiedTest, ClearStorage) {
+  // Add a thumbnail that will be cleaned up by RunMaintenanceTasks.
+  // TODO(harringtond): Replace thumbnail checks with UMA after UMA is added.
+  const int64_t kThumbnailOfflineID = 95912912;  // Does not match any items.
+  OfflinePageThumbnail thumbnail;
+  thumbnail.offline_id = kThumbnailOfflineID;
+  thumbnail.expiration = task_runner()->Now() - base::TimeDelta::FromDays(1);
+  thumbnail.thumbnail = "page1";
+  model()->StoreThumbnail(thumbnail);
+  EXPECT_CALL(*this, ThumbnailAdded(_, thumbnail));
+
   // The ClearStorage task should not be executed based on time delays after
   // launch (aka the model being built).
   task_runner()->FastForwardBy(base::TimeDelta::FromDays(1));
@@ -1491,6 +1520,22 @@
   task_runner()->FastForwardBy(run_delay);
   PumpLoop();
   EXPECT_EQ(last_scheduling_time, last_maintenance_tasks_schedule_time());
+  // Check that CleanupThumbnailsTask ran.
+  bool called = false;
+  model()->GetThumbnailByOfflineId(
+      kThumbnailOfflineID,
+      base::BindLambdaForTesting(
+          [&](std::unique_ptr<OfflinePageThumbnail> thumbnail) {
+            EXPECT_FALSE(thumbnail);
+            called = true;
+          }));
+  PumpLoop();
+  EXPECT_TRUE(called);
+
+  // Add thumbnail again, it should not be deleted because CleanupThumbnailsTask
+  // is only called on first run.
+  model()->StoreThumbnail(thumbnail);
+  EXPECT_CALL(*this, ThumbnailAdded(_, thumbnail));
 
   // Calling GetAllPages after only half of the enforced interval between
   // ClearStorage runs should not schedule ClearStorage.
@@ -1523,6 +1568,19 @@
   task_runner()->FastForwardBy(run_delay);
   PumpLoop();
   EXPECT_EQ(last_scheduling_time, last_maintenance_tasks_schedule_time());
+
+  // Check that CleanupThumbnailsTask did not run again.
+  called = false;
+  model()->GetThumbnailByOfflineId(
+      kThumbnailOfflineID,
+      base::BindLambdaForTesting(
+          [&](std::unique_ptr<OfflinePageThumbnail> thumbnail) {
+            EXPECT_TRUE(thumbnail);
+            called = true;
+          }));
+  PumpLoop();
+  EXPECT_TRUE(called);
+
   // Confirm that two runs happened.
   histogram_tester()->ExpectUniqueSample(
       "OfflinePages.ClearTemporaryPages.Result",
@@ -1560,4 +1618,23 @@
       "OfflinePages.ConsistencyCheck.Persistent.Result", 0);
 }
 
+TEST_F(OfflinePageModelTaskifiedTest, StoreAndGetThumbnail) {
+  OfflinePageThumbnail thumb;
+  thumb.offline_id = 1;
+  thumb.expiration = base::Time::Now();
+  thumb.thumbnail = "abc123";
+  model()->StoreThumbnail(thumb);
+  EXPECT_CALL(*this, ThumbnailAdded(_, thumb));
+  PumpLoop();
+
+  std::unique_ptr<OfflinePageThumbnail> result_thumbnail;
+  auto callback = base::BindLambdaForTesting(
+      [&](std::unique_ptr<OfflinePageThumbnail> result) {
+        result_thumbnail = std::move(result);
+      });
+  model()->GetThumbnailByOfflineId(thumb.offline_id, callback);
+  PumpLoop();
+  EXPECT_EQ(thumb, *result_thumbnail);
+}
+
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/offline_page_model.h b/components/offline_pages/core/offline_page_model.h
index 5d1ca0e..63b5b16 100644
--- a/components/offline_pages/core/offline_page_model.h
+++ b/components/offline_pages/core/offline_page_model.h
@@ -17,6 +17,7 @@
 #include "components/offline_pages/core/client_policy_controller.h"
 #include "components/offline_pages/core/offline_event_logger.h"
 #include "components/offline_pages/core/offline_page_archiver.h"
+#include "components/offline_pages/core/offline_page_thumbnail.h"
 #include "components/offline_pages/core/offline_page_types.h"
 
 class GURL;
@@ -106,6 +107,10 @@
     // Invoked when an offline copy related to |offline_id| was deleted.
     virtual void OfflinePageDeleted(const DeletedPageInfo& page_info) = 0;
 
+    // Invoked when a thumbnail for an offline page is added.
+    virtual void ThumbnailAdded(OfflinePageModel* model,
+                                const OfflinePageThumbnail& added_thumbnail) {}
+
    protected:
     virtual ~Observer() = default;
   };
@@ -212,6 +217,14 @@
       const ClientId& client_id,
       const MultipleOfflineIdCallback& callback) = 0;
 
+  // Stores a new page thumbnail in the page_thumbnails table.
+  virtual void StoreThumbnail(const OfflinePageThumbnail& thumb) = 0;
+
+  // Reads a thumbnail from the page_thumbnails table. Calls callback
+  // with nullptr if the thumbnail was not found.
+  virtual void GetThumbnailByOfflineId(int64_t offline_id,
+                                       GetThumbnailCallback callback) = 0;
+
   // Publishes an offline page from the internal offline page directory.  This
   // includes putting it in a public directory, updating the system download
   // manager, if any, and updating the offline page model database.
diff --git a/components/offline_pages/core/prefetch/BUILD.gn b/components/offline_pages/core/prefetch/BUILD.gn
index 528c29a4..bfaedd4 100644
--- a/components/offline_pages/core/prefetch/BUILD.gn
+++ b/components/offline_pages/core/prefetch/BUILD.gn
@@ -88,6 +88,7 @@
     "store/prefetch_store_utils.h",
     "suggested_articles_observer.cc",
     "suggested_articles_observer.h",
+    "thumbnail_fetcher.h",
   ]
 
   public_deps = [
@@ -117,6 +118,8 @@
   sources = [
     "mock_prefetch_item_generator.cc",
     "mock_prefetch_item_generator.h",
+    "mock_thumbnail_fetcher.cc",
+    "mock_thumbnail_fetcher.h",
     "prefetch_item.cc",
     "prefetch_item.h",
     "prefetch_request_test_base.cc",
@@ -153,6 +156,7 @@
     "//components/version_info:channel",
     "//net:test_support",
     "//sql:sql",
+    "//testing/gmock",
     "//url",
   ]
 }
diff --git a/components/offline_pages/core/prefetch/download_completed_task.cc b/components/offline_pages/core/prefetch/download_completed_task.cc
index 4c25f93..147cd15d 100644
--- a/components/offline_pages/core/prefetch/download_completed_task.cc
+++ b/components/offline_pages/core/prefetch/download_completed_task.cc
@@ -15,7 +15,7 @@
 #include "components/offline_pages/core/prefetch/store/prefetch_store.h"
 #include "sql/connection.h"
 #include "sql/statement.h"
-#include "url/gurl.h"
+#include "sql/transaction.h"
 
 namespace offline_pages {
 namespace {
@@ -41,37 +41,61 @@
                          : DownloadOutcome::DOWNLOAD_FAILED_ITEM_NOT_FOUND;
 }
 
-// Updates a prefetch item after its archive was successfully downloaded.
-// Returns true if the respective row was successfully updated (as normally
-// expected).
-bool UpdatePrefetchItemOnDownloadSuccessSync(const std::string& guid,
-                                             const base::FilePath& file_path,
-                                             int64_t file_size,
-                                             sql::Connection* db) {
-  if (!db)
-    return false;
+using UpdateInfo = DownloadCompletedTask::UpdateInfo;
 
+// Updates a prefetch item after its archive was successfully downloaded.
+// Returns an UpdateInfo describing the result.
+UpdateInfo UpdatePrefetchItemOnDownloadSuccessSync(
+    const std::string& guid,
+    const base::FilePath& file_path,
+    int64_t file_size,
+    sql::Connection* db) {
+  if (!db)
+    return UpdateInfo();
+  sql::Transaction transaction(db);
+  if (!transaction.Begin())
+    return UpdateInfo();
+  // First, grab some data about the page.
+  int64_t offline_id;
+  ClientId client_id;
+  {
+    static const char kSql[] =
+        "SELECT offline_id, client_namespace, client_id"
+        " FROM prefetch_items"
+        " WHERE guid = ? AND state = ?";
+    sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+    statement.BindString(0, guid);
+    statement.BindInt(1, static_cast<int>(PrefetchItemState::DOWNLOADING));
+    if (!statement.Step())
+      return UpdateInfo();
+    offline_id = statement.ColumnInt64(0);
+    client_id = ClientId(statement.ColumnString(1), statement.ColumnString(2));
+  }
+
+  // Now update the item and return the offline item information.
   static const char kSql[] =
       "UPDATE prefetch_items"
       " SET state = ?, file_path = ?, file_size = ?"
-      " WHERE guid = ? AND state = ?";
+      " WHERE offline_id = ?";
 
   sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
   statement.BindInt(0, static_cast<int>(PrefetchItemState::DOWNLOADED));
   statement.BindString(1, store_utils::ToDatabaseFilePath(file_path));
   statement.BindInt64(2, file_size);
-  statement.BindString(3, guid);
-  statement.BindInt(4, static_cast<int>(PrefetchItemState::DOWNLOADING));
-
-  return statement.Run() && db->GetLastChangeCount() > 0;
+  statement.BindInt64(3, offline_id);
+  if (!statement.Run() || db->GetLastChangeCount() != 1 ||
+      !transaction.Commit()) {
+    return UpdateInfo();
+  }
+  return UpdateInfo{true, offline_id, client_id};
 }
 
 // Updates a prefetch item after its archive failed being downloaded. Returns
 // true if the respective row was successfully updated (as normally expected).
-bool UpdatePrefetchItemOnDownloadErrorSync(const std::string& guid,
-                                           sql::Connection* db) {
+UpdateInfo UpdatePrefetchItemOnDownloadErrorSync(const std::string& guid,
+                                                 sql::Connection* db) {
   if (!db)
-    return false;
+    return UpdateInfo();
 
   static const char kSql[] =
       "UPDATE prefetch_items"
@@ -84,7 +108,9 @@
   statement.BindString(2, guid);
   statement.BindInt(3, static_cast<int>(PrefetchItemState::DOWNLOADING));
 
-  return statement.Run() && db->GetLastChangeCount() > 0;
+  UpdateInfo info;
+  info.success = statement.Run() && db->GetLastChangeCount() > 0;
+  return info;
 }
 
 }  // namespace
@@ -123,14 +149,20 @@
 }
 
 void DownloadCompletedTask::OnPrefetchItemUpdated(bool successful_download,
-                                                  bool row_was_updated) {
+                                                  UpdateInfo update_info) {
   // No further action can be done if the database fails to be updated. The
   // cleanup task should eventually kick in to clean this up.
-  if (row_was_updated)
+  if (update_info.success) {
     prefetch_dispatcher_->SchedulePipelineProcessing();
+  }
+  // Kick off thumbnail download if the page was downloaded successfully.
+  if (update_info.success && successful_download) {
+    prefetch_dispatcher_->ItemDownloaded(update_info.offline_id,
+                                         update_info.client_id);
+  }
 
   DownloadOutcome status =
-      GetDownloadOutcome(successful_download, row_was_updated);
+      GetDownloadOutcome(successful_download, update_info.success);
   UMA_HISTOGRAM_ENUMERATION("OfflinePages.Prefetching.DownloadFinishedUpdate",
                             status, DownloadOutcome::COUNT);
 
diff --git a/components/offline_pages/core/prefetch/download_completed_task.h b/components/offline_pages/core/prefetch/download_completed_task.h
index 43e8c2f9..4651e299 100644
--- a/components/offline_pages/core/prefetch/download_completed_task.h
+++ b/components/offline_pages/core/prefetch/download_completed_task.h
@@ -24,11 +24,18 @@
 
   void Run() override;
 
+  struct UpdateInfo {
+    // True if the row was updated.
+    bool success = false;
+    int64_t offline_id = 0;
+    ClientId client_id;
+  };
+
  private:
-  void OnPrefetchItemUpdated(bool successful_download, bool row_was_updated);
+  void OnPrefetchItemUpdated(bool successful_download, UpdateInfo update_info);
 
   PrefetchDispatcher* prefetch_dispatcher_;  // Outlives this class.
-  PrefetchStore* prefetch_store_;  // Outlives this class.
+  PrefetchStore* prefetch_store_;            // Outlives this class.
   PrefetchDownloadResult download_result_;
 
   base::WeakPtrFactory<DownloadCompletedTask> weak_ptr_factory_;
diff --git a/components/offline_pages/core/prefetch/download_completed_task_unittest.cc b/components/offline_pages/core/prefetch/download_completed_task_unittest.cc
index d7e3931..772c300 100644
--- a/components/offline_pages/core/prefetch/download_completed_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/download_completed_task_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/test/test_mock_time_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "components/offline_pages/core/client_namespace_constants.h"
 #include "components/offline_pages/core/prefetch/prefetch_item.h"
 #include "components/offline_pages/core/prefetch/prefetch_task_test_base.h"
 #include "components/offline_pages/core/prefetch/prefetch_types.h"
@@ -18,20 +19,21 @@
 #include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
 #include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
 #include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
-#include "sql/connection.h"
-#include "sql/statement.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace offline_pages {
-
 namespace {
 const int64_t kTestOfflineID = 1111;
 const int64_t kTestOfflineID2 = 223344;
 const char kTestGUID[] = "1a150628-1b56-44da-a85a-c575120af180";
 const char kTestGUID2[] = "736edb12-98f6-41c2-8e50-a667694511a5";
-const base::FilePath kTestFilePath(FILE_PATH_LITERAL("foo"));
 const int64_t kTestFileSize = 88888;
-}  // namespace
+const char kClientID1[] = "client-id-1";
+const char kClientID2[] = "client-id-2";
+
+base::FilePath TestFilePath() {
+  return base::FilePath(FILE_PATH_LITERAL("foo"));
+}
 
 class DownloadCompletedTaskTest : public PrefetchTaskTestBase {
  public:
@@ -39,9 +41,22 @@
 
   void SetUp() override;
 
+ protected:
   TestPrefetchDispatcher* dispatcher() { return &dispatcher_; }
   base::HistogramTester* histogram_tester() { return histogram_tester_.get(); }
 
+  std::unique_ptr<DownloadCompletedTask> CreateTask(
+      PrefetchDownloadResult download_result) {
+    return std::make_unique<DownloadCompletedTask>(dispatcher(), store(),
+                                                   download_result);
+  }
+  // Expect that dispatcher()->ItemDownloaded was called for each entry in
+  // item_downloaded_results.
+  void ExpectItemDownloaded(
+      std::vector<std::pair<int64_t, ClientId>> item_downloaded_results) {
+    EXPECT_EQ(item_downloaded_results, dispatcher_.item_downloaded_results);
+  }
+
  private:
   TestPrefetchDispatcher dispatcher_;
   std::unique_ptr<base::HistogramTester> histogram_tester_;
@@ -55,6 +70,8 @@
   item.state = PrefetchItemState::DOWNLOADING;
   item.creation_time = base::Time::Now();
   item.freshness_time = item.creation_time;
+  item.client_id.name_space = kSuggestedArticlesNamespace;
+  item.client_id.id = kClientID1;
   EXPECT_TRUE(store_util()->InsertPrefetchItem(item));
 
   PrefetchItem item2;
@@ -63,6 +80,8 @@
   item2.state = PrefetchItemState::NEW_REQUEST;
   item2.creation_time = base::Time::Now();
   item2.freshness_time = item.creation_time;
+  item.client_id.name_space = kSuggestedArticlesNamespace;
+  item.client_id.id = kClientID2;
   EXPECT_TRUE(store_util()->InsertPrefetchItem(item2));
 
   histogram_tester_.reset(new base::HistogramTester());
@@ -71,25 +90,27 @@
 TEST_F(DownloadCompletedTaskTest, StoreFailure) {
   store_util()->SimulateInitializationError();
 
-  PrefetchDownloadResult download_result(kTestGUID, kTestFilePath,
+  PrefetchDownloadResult download_result(kTestGUID, TestFilePath(),
                                          kTestFileSize);
-  RunTask(std::make_unique<DownloadCompletedTask>(dispatcher(), store(),
-                                                  download_result));
+  RunTask(CreateTask(download_result));
+  std::vector<std::pair<int64_t, ClientId>> want;
+  ExpectItemDownloaded({});
 }
 
 TEST_F(DownloadCompletedTaskTest, UpdateItemOnDownloadSuccess) {
-  PrefetchDownloadResult download_result(kTestGUID, kTestFilePath,
+  PrefetchDownloadResult download_result(kTestGUID, TestFilePath(),
                                          kTestFileSize);
-  RunTask(std::make_unique<DownloadCompletedTask>(dispatcher(), store(),
-                                                  download_result));
+  RunTask(CreateTask(download_result));
 
   std::unique_ptr<PrefetchItem> item =
       store_util()->GetPrefetchItem(kTestOfflineID);
   EXPECT_EQ(PrefetchItemState::DOWNLOADED, item->state);
   EXPECT_EQ(kTestGUID, item->guid);
-  EXPECT_EQ(kTestFilePath, item->file_path);
+  EXPECT_EQ(TestFilePath(), item->file_path);
   EXPECT_EQ(kTestFileSize, item->file_size);
   EXPECT_EQ(1, dispatcher()->processing_schedule_count);
+  ExpectItemDownloaded(
+      {{kTestOfflineID, ClientId(kSuggestedArticlesNamespace, kClientID1)}});
 
   histogram_tester()->ExpectUniqueSample(
       "OfflinePages.Prefetching.DownloadedFileSize", kTestFileSize / 1024, 1);
@@ -102,8 +123,7 @@
   PrefetchDownloadResult download_result;
   download_result.download_id = kTestGUID;
   download_result.success = false;
-  RunTask(std::make_unique<DownloadCompletedTask>(dispatcher(), store(),
-                                                  download_result));
+  RunTask(CreateTask(download_result));
 
   std::unique_ptr<PrefetchItem> item =
       store_util()->GetPrefetchItem(kTestOfflineID);
@@ -113,6 +133,7 @@
   EXPECT_TRUE(item->file_path.empty());
   EXPECT_EQ(-1, item->file_size);
   EXPECT_EQ(1, dispatcher()->processing_schedule_count);
+  ExpectItemDownloaded({});
 
   histogram_tester()->ExpectTotalCount(
       "OfflinePages.Prefetching.DownloadedFileSize", 0);
@@ -122,10 +143,9 @@
 }
 
 TEST_F(DownloadCompletedTaskTest, NoUpdateOnMismatchedDownloadSuccess) {
-  PrefetchDownloadResult download_result(kTestGUID2, kTestFilePath,
+  PrefetchDownloadResult download_result(kTestGUID2, TestFilePath(),
                                          kTestFileSize);
-  RunTask(std::make_unique<DownloadCompletedTask>(dispatcher(), store(),
-                                                  download_result));
+  RunTask(CreateTask(download_result));
 
   // Item will only be updated when both offline_id and state match.
   std::unique_ptr<PrefetchItem> item =
@@ -137,6 +157,7 @@
   EXPECT_EQ(PrefetchItemState::NEW_REQUEST, item2->state);
 
   EXPECT_EQ(0, dispatcher()->processing_schedule_count);
+  ExpectItemDownloaded({});
 
   histogram_tester()->ExpectUniqueSample(
       "OfflinePages.Prefetching.DownloadedFileSize", kTestFileSize / 1024, 1);
@@ -149,8 +170,7 @@
   PrefetchDownloadResult download_result;
   download_result.download_id = kTestGUID2;
   download_result.success = false;
-  RunTask(std::make_unique<DownloadCompletedTask>(dispatcher(), store(),
-                                                  download_result));
+  RunTask(CreateTask(download_result));
 
   // Item will only be updated when both offline_id and state match.
   std::unique_ptr<PrefetchItem> item =
@@ -162,6 +182,7 @@
   EXPECT_EQ(PrefetchItemState::NEW_REQUEST, item2->state);
 
   EXPECT_EQ(0, dispatcher()->processing_schedule_count);
+  ExpectItemDownloaded({});
 
   histogram_tester()->ExpectTotalCount(
       "OfflinePages.Prefetching.DownloadedFileSize", 0);
@@ -170,4 +191,5 @@
       "OfflinePages.Prefetching.DownloadFinishedUpdate", 3, 1);
 }
 
+}  // namespace
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/mock_thumbnail_fetcher.cc b/components/offline_pages/core/prefetch/mock_thumbnail_fetcher.cc
new file mode 100644
index 0000000..bbebb042
--- /dev/null
+++ b/components/offline_pages/core/prefetch/mock_thumbnail_fetcher.cc
@@ -0,0 +1,14 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/core/prefetch/mock_thumbnail_fetcher.h"
+
+#include "components/offline_pages/core/client_id.h"
+
+namespace offline_pages {
+
+MockThumbnailFetcher::MockThumbnailFetcher() = default;
+MockThumbnailFetcher::~MockThumbnailFetcher() = default;
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/mock_thumbnail_fetcher.h b/components/offline_pages/core/prefetch/mock_thumbnail_fetcher.h
new file mode 100644
index 0000000..91ee36e
--- /dev/null
+++ b/components/offline_pages/core/prefetch/mock_thumbnail_fetcher.h
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_MOCK_THUMBNAIL_FETCHER_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_MOCK_THUMBNAIL_FETCHER_H_
+
+#include "components/offline_pages/core/prefetch/thumbnail_fetcher.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace offline_pages {
+
+class MockThumbnailFetcher : public ThumbnailFetcher {
+ public:
+  MockThumbnailFetcher();
+  ~MockThumbnailFetcher() override;
+  MOCK_METHOD2(FetchSuggestionImageData_,
+               void(const ClientId& client_id,
+                    ImageDataFetchedCallback* callback));
+  void FetchSuggestionImageData(const ClientId& client_id,
+                                ImageDataFetchedCallback callback) {
+    FetchSuggestionImageData_(client_id, &callback);
+  }
+};
+
+}  // namespace offline_pages
+
+#endif  // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_MOCK_THUMBNAIL_FETCHER_H_
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher.h b/components/offline_pages/core/prefetch/prefetch_dispatcher.h
index 533e438..0cfc6cf 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher.h
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher.h
@@ -108,6 +108,11 @@
   virtual void DownloadCompleted(
       const PrefetchDownloadResult& download_result) = 0;
 
+  // Called when an item's state has been set to
+  // |PrefetchItemState::DOWNLOADED|, just after a download is completed.
+  virtual void ItemDownloaded(int64_t offline_id,
+                              const ClientId& client_id) = 0;
+
   // Called when an archive is imported successfully or fails.
   virtual void ArchiveImported(int64_t offline_id, bool success) = 0;
 };
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
index e97a36b..479cd5c 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
@@ -11,6 +11,7 @@
 #include "base/task_runner.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/core/client_namespace_constants.h"
 #include "components/offline_pages/core/offline_event_logger.h"
 #include "components/offline_pages/core/offline_page_feature.h"
 #include "components/offline_pages/core/offline_page_model.h"
@@ -41,6 +42,7 @@
 #include "components/offline_pages/core/prefetch/sent_get_operation_cleanup_task.h"
 #include "components/offline_pages/core/prefetch/stale_entry_finalizer_task.h"
 #include "components/offline_pages/core/prefetch/suggested_articles_observer.h"
+#include "components/offline_pages/core/prefetch/thumbnail_fetcher.h"
 #include "components/offline_pages/core/task.h"
 #include "url/gurl.h"
 
@@ -50,6 +52,26 @@
 void DeleteBackgroundTaskHelper(std::unique_ptr<PrefetchBackgroundTask> task) {
   task.reset();
 }
+
+void FetchComplete(OfflinePageModel* offline_model,
+                   int64_t offline_id,
+                   const std::string& image_data) {
+  if (image_data.empty())
+    return;
+  if (image_data.size() > PrefetchDispatcherImpl::kMaxThumbnailSize)
+    return;
+
+  // Thumbnails are marked to expire after this delta. Expired thumbnails are
+  // eventually deleted if their offline_id does not correspond to an offline
+  // item. Two days gives us plenty of time so that the prefetched item can be
+  // imported into the offline item database.
+  const base::TimeDelta kThumbnailExpirationDelta =
+      base::TimeDelta::FromDays(2);
+
+  offline_model->StoreThumbnail(OfflinePageThumbnail(
+      offline_id, base::Time::Now() + kThumbnailExpirationDelta, image_data));
+}
+
 }  // namespace
 
 PrefetchDispatcherImpl::PrefetchDispatcherImpl()
@@ -332,6 +354,16 @@
       service_->GetPrefetchStore(), service_->GetPrefetchImporter()));
 }
 
+void PrefetchDispatcherImpl::ItemDownloaded(int64_t offline_id,
+                                            const ClientId& client_id) {
+  DCHECK(client_id.name_space == kSuggestedArticlesNamespace);
+  auto complete_callback = base::BindOnce(
+      &FetchComplete, base::Unretained(service_->GetOfflinePageModel()),
+      offline_id);
+  service_->GetThumbnailFetcher()->FetchSuggestionImageData(
+      client_id, std::move(complete_callback));
+}
+
 void PrefetchDispatcherImpl::ArchiveImported(int64_t offline_id, bool success) {
   DCHECK_NE(OfflinePageModel::kInvalidOfflineId, offline_id);
 
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
index 5f95ec17..1161aa53 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
@@ -24,6 +24,10 @@
 class PrefetchDispatcherImpl : public PrefetchDispatcher,
                                public TaskQueue::Delegate {
  public:
+  // Thumbnails larger than 200KB are not retained. Thumbnails are typically
+  // around 10KB.
+  static constexpr int64_t kMaxThumbnailSize = 200000;
+
   PrefetchDispatcherImpl();
   ~PrefetchDispatcherImpl() override;
 
@@ -47,6 +51,7 @@
           success_downloads) override;
   void DownloadCompleted(
       const PrefetchDownloadResult& download_result) override;
+  void ItemDownloaded(int64_t offline_id, const ClientId& client_id) override;
   void ArchiveImported(int64_t offline_id, bool success) override;
 
   // TaskQueue::Delegate implementation:
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
index 83edcb1..30f4b7abb 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
@@ -12,6 +12,7 @@
 #include "components/offline_pages/core/offline_page_feature.h"
 #include "components/offline_pages/core/prefetch/generate_page_bundle_request.h"
 #include "components/offline_pages/core/prefetch/get_operation_request.h"
+#include "components/offline_pages/core/prefetch/mock_thumbnail_fetcher.h"
 #include "components/offline_pages/core/prefetch/prefetch_background_task.h"
 #include "components/offline_pages/core/prefetch/prefetch_configuration.h"
 #include "components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h"
@@ -23,10 +24,13 @@
 #include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
 #include "components/offline_pages/core/prefetch/suggested_articles_observer.h"
 #include "components/offline_pages/core/prefetch/test_prefetch_network_request_factory.h"
+#include "components/offline_pages/core/stub_offline_page_model.h"
 #include "components/version_info/channel.h"
 #include "net/http/http_status_code.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gmock_mutant.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -35,11 +39,19 @@
 namespace offline_pages {
 
 namespace {
+using testing::_;
 
-const std::string kTestNamespace = "TestPrefetchClientNamespace";
-const std::string kTestID = "id";
+const char kTestNamespace[] = "TestPrefetchClientNamespace";
+const char kTestID[] = "id";
 const GURL kTestURL("https://www.chromium.org");
 const GURL kTestURL2("https://www.chromium.org/2");
+const int64_t kTestOfflineID = 1111;
+const char kClientID1[] = "client-id-1";
+
+class MockOfflinePageModel : public StubOfflinePageModel {
+ public:
+  MOCK_METHOD1(StoreThumbnail, void(const OfflinePageThumbnail& thumb));
+};
 
 class TestPrefetchBackgroundTask : public PrefetchBackgroundTask {
  public:
@@ -113,7 +125,27 @@
     return reschedule_type_;
   }
 
+  void ExpectFetchThumbnail(const std::string& thumbnail_data) {
+    EXPECT_CALL(*thumbnail_fetcher_,
+                FetchSuggestionImageData_(
+                    ClientId(kSuggestedArticlesNamespace, kClientID1), _))
+        .WillOnce(
+            testing::Invoke(testing::CallbackToFunctor(base::BindRepeating(
+                [](const std::string& thumbnail_data,
+                   scoped_refptr<base::TestMockTimeTaskRunner> task_runner,
+                   const ClientId& id,
+                   ThumbnailFetcher::ImageDataFetchedCallback* callback) {
+                  task_runner->PostTask(
+                      FROM_HERE,
+                      base::BindOnce(std::move(*callback), thumbnail_data));
+                },
+                thumbnail_data, task_runner()))));
+  }
+
  protected:
+  // Owned by |taco_|.
+  MockOfflinePageModel* offline_model_;
+
   std::vector<PrefetchURL> test_urls_;
 
  private:
@@ -125,6 +157,8 @@
   PrefetchDispatcherImpl* dispatcher_;
   // Owned by |taco_|.
   TestPrefetchNetworkRequestFactory* network_request_factory_;
+  // Owned by |taco_|.
+  MockThumbnailFetcher* thumbnail_fetcher_;
 
   bool reschedule_called_ = false;
   PrefetchBackgroundTaskRescheduleType reschedule_type_ =
@@ -144,6 +178,12 @@
       base::WrapUnique(network_request_factory_));
   taco_->SetPrefetchConfiguration(
       std::make_unique<TestPrefetchConfiguration>());
+  auto thumbnail_fetcher = std::make_unique<MockThumbnailFetcher>();
+  thumbnail_fetcher_ = thumbnail_fetcher.get();
+  taco_->SetThumbnailFetcher(std::move(thumbnail_fetcher));
+  auto model = std::make_unique<MockOfflinePageModel>();
+  offline_model_ = model.get();
+  taco_->SetOfflinePageModel(std::move(model));
   taco_->CreatePrefetchService();
 
   ASSERT_TRUE(test_urls_.empty());
@@ -169,6 +209,10 @@
                           base::Unretained(this))));
 }
 
+MATCHER(ValidThumbnail, "") {
+  return arg.offline_id == kTestOfflineID && !arg.thumbnail.empty();
+};
+
 TEST_F(PrefetchDispatcherTest, DispatcherDoesNotCrash) {
   // TODO(https://crbug.com/735254): Ensure that Dispatcher unit test keep up
   // with the state of adding tasks, and that the end state is we have tests
@@ -408,4 +452,28 @@
   EXPECT_EQ(nullptr, GetRunningFetcher());
 }
 
+TEST_F(PrefetchDispatcherTest, ThumbnailFetchFailure) {
+  ExpectFetchThumbnail("");
+  EXPECT_CALL(*offline_model_, StoreThumbnail(_)).Times(0);
+  prefetch_dispatcher()->ItemDownloaded(
+      kTestOfflineID, ClientId(kSuggestedArticlesNamespace, kClientID1));
+}
+
+TEST_F(PrefetchDispatcherTest, ThumbnailFetchSuccess) {
+  std::string kThumbnailData =
+      std::string(PrefetchDispatcherImpl::kMaxThumbnailSize, 'x');
+  EXPECT_CALL(*offline_model_, StoreThumbnail(ValidThumbnail()));
+  ExpectFetchThumbnail(kThumbnailData);
+  prefetch_dispatcher()->ItemDownloaded(
+      kTestOfflineID, ClientId(kSuggestedArticlesNamespace, kClientID1));
+}
+
+TEST_F(PrefetchDispatcherTest, ThumbnailFetchTooBig) {
+  ExpectFetchThumbnail(
+      std::string(PrefetchDispatcherImpl::kMaxThumbnailSize + 1, 'x'));
+  EXPECT_CALL(*offline_model_, StoreThumbnail(_)).Times(0);
+  prefetch_dispatcher()->ItemDownloaded(
+      kTestOfflineID, ClientId(kSuggestedArticlesNamespace, kClientID1));
+}
+
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/prefetch_download_flow_unittest.cc b/components/offline_pages/core/prefetch/prefetch_download_flow_unittest.cc
index f86a9c8..83799e3d 100644
--- a/components/offline_pages/core/prefetch/prefetch_download_flow_unittest.cc
+++ b/components/offline_pages/core/prefetch/prefetch_download_flow_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/test/scoped_feature_list.h"
 #include "components/download/public/background_service/test/test_download_service.h"
+#include "components/offline_pages/core/client_namespace_constants.h"
 #include "components/offline_pages/core/offline_page_feature.h"
 #include "components/offline_pages/core/prefetch/prefetch_background_task.h"
 #include "components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h"
@@ -19,13 +20,11 @@
 #include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace offline_pages {
 namespace {
 const version_info::Channel kTestChannel = version_info::Channel::UNKNOWN;
 const base::FilePath kTestFilePath(FILE_PATH_LITERAL("foo"));
 const int64_t kTestFileSize = 88888;
-}  // namespace
-
-namespace offline_pages {
 
 // Tests the interaction between prefetch service and download service to
 // validate the whole prefetch download flow regardless which service is up
@@ -49,6 +48,7 @@
     prefetch_service_taco_->SetPrefetchStore(store_util()->ReleaseStore());
     prefetch_service_taco_->SetPrefetchDownloader(std::move(downloader));
     prefetch_service_taco_->CreatePrefetchService();
+    item_generator()->set_client_namespace(kSuggestedArticlesNamespace);
   }
 
   void TearDown() override {
@@ -195,4 +195,5 @@
   EXPECT_EQ(PrefetchItemState::IMPORTING, found_item->state);
 }
 
+}  // namespace
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/prefetch_service.h b/components/offline_pages/core/prefetch/prefetch_service.h
index 2605833..d9561d5 100644
--- a/components/offline_pages/core/prefetch/prefetch_service.h
+++ b/components/offline_pages/core/prefetch/prefetch_service.h
@@ -7,9 +7,14 @@
 
 #include "components/keyed_service/core/keyed_service.h"
 
+namespace ntp_snippets {
+class ContentSuggestionsService;
+}
+
 namespace offline_pages {
 class OfflineEventLogger;
 class OfflineMetricsCollector;
+class OfflinePageModel;
 class PrefetchBackgroundTaskHandler;
 class PrefetchConfiguration;
 class PrefetchDispatcher;
@@ -19,6 +24,7 @@
 class PrefetchNetworkRequestFactory;
 class PrefetchStore;
 class SuggestedArticlesObserver;
+class ThumbnailFetcher;
 
 // Main class and entry point for the Offline Pages Prefetching feature, that
 // controls the lifetime of all major subcomponents of the prefetching system.
@@ -26,6 +32,9 @@
  public:
   ~PrefetchService() override = default;
 
+  virtual void SetContentSuggestionsService(
+      ntp_snippets::ContentSuggestionsService* content_suggestions) {}
+
   // Subobjects that are created and owned by this service. Creation should be
   // lightweight, all heavy work must be done on-demand only.
   // The service manages lifetime, hookup and initialization of Prefetch
@@ -41,6 +50,8 @@
   virtual PrefetchImporter* GetPrefetchImporter() = 0;
   virtual PrefetchBackgroundTaskHandler* GetPrefetchBackgroundTaskHandler() = 0;
   virtual PrefetchConfiguration* GetPrefetchConfiguration() = 0;
+  virtual ThumbnailFetcher* GetThumbnailFetcher() = 0;
+  virtual OfflinePageModel* GetOfflinePageModel() = 0;
 
   // May be |nullptr| in tests.  The PrefetchService does not depend on the
   // SuggestedArticlesObserver, it merely owns it for lifetime purposes.
diff --git a/components/offline_pages/core/prefetch/prefetch_service_impl.cc b/components/offline_pages/core/prefetch/prefetch_service_impl.cc
index 1b7dd6f..aa8b1e2 100644
--- a/components/offline_pages/core/prefetch/prefetch_service_impl.cc
+++ b/components/offline_pages/core/prefetch/prefetch_service_impl.cc
@@ -20,6 +20,7 @@
 #include "components/offline_pages/core/prefetch/prefetch_network_request_factory.h"
 #include "components/offline_pages/core/prefetch/store/prefetch_store.h"
 #include "components/offline_pages/core/prefetch/suggested_articles_observer.h"
+#include "components/offline_pages/core/prefetch/thumbnail_fetcher.h"
 
 namespace offline_pages {
 
@@ -28,24 +29,28 @@
     std::unique_ptr<PrefetchDispatcher> dispatcher,
     std::unique_ptr<PrefetchGCMHandler> gcm_handler,
     std::unique_ptr<PrefetchNetworkRequestFactory> network_request_factory,
+    OfflinePageModel* offline_page_model,
     std::unique_ptr<PrefetchStore> prefetch_store,
     std::unique_ptr<SuggestedArticlesObserver> suggested_articles_observer,
     std::unique_ptr<PrefetchDownloader> prefetch_downloader,
     std::unique_ptr<PrefetchImporter> prefetch_importer,
     std::unique_ptr<PrefetchBackgroundTaskHandler>
         prefetch_background_task_handler,
-    std::unique_ptr<PrefetchConfiguration> prefetch_configuration)
+    std::unique_ptr<PrefetchConfiguration> prefetch_configuration,
+    std::unique_ptr<ThumbnailFetcher> thumbnail_fetcher)
     : offline_metrics_collector_(std::move(offline_metrics_collector)),
       prefetch_dispatcher_(std::move(dispatcher)),
       prefetch_gcm_handler_(std::move(gcm_handler)),
       network_request_factory_(std::move(network_request_factory)),
+      offline_page_model_(offline_page_model),
       prefetch_store_(std::move(prefetch_store)),
       suggested_articles_observer_(std::move(suggested_articles_observer)),
       prefetch_downloader_(std::move(prefetch_downloader)),
       prefetch_importer_(std::move(prefetch_importer)),
       prefetch_background_task_handler_(
           std::move(prefetch_background_task_handler)),
-      prefetch_configuration_(std::move(prefetch_configuration)) {
+      prefetch_configuration_(std::move(prefetch_configuration)),
+      thumbnail_fetcher_(std::move(thumbnail_fetcher)) {
   prefetch_dispatcher_->SetService(this);
   prefetch_downloader_->SetPrefetchService(this);
   prefetch_gcm_handler_->SetService(this);
@@ -58,6 +63,13 @@
   prefetch_dispatcher_.reset();
 }
 
+void PrefetchServiceImpl::SetContentSuggestionsService(
+    ntp_snippets::ContentSuggestionsService* content_suggestions) {
+  suggested_articles_observer_->SetContentSuggestionsServiceAndObserve(
+      content_suggestions);
+  thumbnail_fetcher_->SetContentSuggestionsService(content_suggestions);
+}
+
 OfflineMetricsCollector* PrefetchServiceImpl::GetOfflineMetricsCollector() {
   return offline_metrics_collector_.get();
 }
@@ -75,6 +87,10 @@
   return network_request_factory_.get();
 }
 
+OfflinePageModel* PrefetchServiceImpl::GetOfflinePageModel() {
+  return offline_page_model_;
+}
+
 PrefetchStore* PrefetchServiceImpl::GetPrefetchStore() {
   return prefetch_store_.get();
 }
@@ -104,6 +120,10 @@
   return prefetch_configuration_.get();
 }
 
+ThumbnailFetcher* PrefetchServiceImpl::GetThumbnailFetcher() {
+  return thumbnail_fetcher_.get();
+}
+
 void PrefetchServiceImpl::Shutdown() {
   suggested_articles_observer_.reset();
   prefetch_downloader_.reset();
diff --git a/components/offline_pages/core/prefetch/prefetch_service_impl.h b/components/offline_pages/core/prefetch/prefetch_service_impl.h
index 7f9b1716..12c0ce5c 100644
--- a/components/offline_pages/core/prefetch/prefetch_service_impl.h
+++ b/components/offline_pages/core/prefetch/prefetch_service_impl.h
@@ -22,20 +22,26 @@
       std::unique_ptr<PrefetchDispatcher> dispatcher,
       std::unique_ptr<PrefetchGCMHandler> gcm_handler,
       std::unique_ptr<PrefetchNetworkRequestFactory> network_request_factory,
+      OfflinePageModel* offline_page_model,
       std::unique_ptr<PrefetchStore> prefetch_store,
       std::unique_ptr<SuggestedArticlesObserver> suggested_articles_observer,
       std::unique_ptr<PrefetchDownloader> prefetch_downloader,
       std::unique_ptr<PrefetchImporter> prefetch_importer,
       std::unique_ptr<PrefetchBackgroundTaskHandler> background_task_handler,
-      std::unique_ptr<PrefetchConfiguration> prefetch_configuration);
+      std::unique_ptr<PrefetchConfiguration> prefetch_configuration,
+      std::unique_ptr<ThumbnailFetcher> thumbnail_fetcher);
 
   ~PrefetchServiceImpl() override;
 
+  void SetContentSuggestionsService(
+      ntp_snippets::ContentSuggestionsService* content_suggestions) override;
+
   // PrefetchService implementation:
   OfflineMetricsCollector* GetOfflineMetricsCollector() override;
   PrefetchDispatcher* GetPrefetchDispatcher() override;
   PrefetchGCMHandler* GetPrefetchGCMHandler() override;
   PrefetchNetworkRequestFactory* GetPrefetchNetworkRequestFactory() override;
+  OfflinePageModel* GetOfflinePageModel() override;
   PrefetchStore* GetPrefetchStore() override;
   SuggestedArticlesObserver* GetSuggestedArticlesObserver() override;
   OfflineEventLogger* GetLogger() override;
@@ -43,6 +49,7 @@
   PrefetchImporter* GetPrefetchImporter() override;
   PrefetchBackgroundTaskHandler* GetPrefetchBackgroundTaskHandler() override;
   PrefetchConfiguration* GetPrefetchConfiguration() override;
+  ThumbnailFetcher* GetThumbnailFetcher() override;
 
   // KeyedService implementation:
   void Shutdown() override;
@@ -54,6 +61,7 @@
   std::unique_ptr<PrefetchDispatcher> prefetch_dispatcher_;
   std::unique_ptr<PrefetchGCMHandler> prefetch_gcm_handler_;
   std::unique_ptr<PrefetchNetworkRequestFactory> network_request_factory_;
+  OfflinePageModel* offline_page_model_;
   std::unique_ptr<PrefetchStore> prefetch_store_;
   std::unique_ptr<SuggestedArticlesObserver> suggested_articles_observer_;
   std::unique_ptr<PrefetchDownloader> prefetch_downloader_;
@@ -61,6 +69,7 @@
   std::unique_ptr<PrefetchBackgroundTaskHandler>
       prefetch_background_task_handler_;
   std::unique_ptr<PrefetchConfiguration> prefetch_configuration_;
+  std::unique_ptr<ThumbnailFetcher> thumbnail_fetcher_;
 
   DISALLOW_COPY_AND_ASSIGN(PrefetchServiceImpl);
 };
diff --git a/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc b/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
index b15e1d2..1eb5be7 100644
--- a/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
+++ b/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
@@ -9,6 +9,8 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/core/offline_page_model.h"
+#include "components/offline_pages/core/prefetch/mock_thumbnail_fetcher.h"
 #include "components/offline_pages/core/prefetch/offline_metrics_collector.h"
 #include "components/offline_pages/core/prefetch/prefetch_background_task_handler.h"
 #include "components/offline_pages/core/prefetch/prefetch_configuration.h"
@@ -25,6 +27,7 @@
 #include "components/offline_pages/core/prefetch/test_prefetch_gcm_handler.h"
 #include "components/offline_pages/core/prefetch/test_prefetch_importer.h"
 #include "components/offline_pages/core/prefetch/test_prefetch_network_request_factory.h"
+#include "components/offline_pages/core/stub_offline_page_model.h"
 
 namespace offline_pages {
 
@@ -80,6 +83,8 @@
   prefetch_background_task_handler_ =
       std::make_unique<StubPrefetchBackgroundTaskHandler>();
   prefetch_configuration_ = std::make_unique<StubPrefetchConfiguration>();
+  offline_page_model_ = std::make_unique<StubOfflinePageModel>();
+  thumbnail_fetcher_ = std::make_unique<MockThumbnailFetcher>();
 }
 
 PrefetchServiceTestTaco::~PrefetchServiceTestTaco() = default;
@@ -146,6 +151,18 @@
   prefetch_configuration_ = std::move(prefetch_configuration);
 }
 
+void PrefetchServiceTestTaco::SetThumbnailFetcher(
+    std::unique_ptr<ThumbnailFetcher> thumbnail_fetcher) {
+  CHECK(!prefetch_service_);
+  thumbnail_fetcher_ = std::move(thumbnail_fetcher);
+}
+
+void PrefetchServiceTestTaco::SetOfflinePageModel(
+    std::unique_ptr<OfflinePageModel> offline_page_model) {
+  CHECK(!prefetch_service_);
+  offline_page_model_ = std::move(offline_page_model);
+}
+
 void PrefetchServiceTestTaco::CreatePrefetchService() {
   CHECK(metrics_collector_ && dispatcher_ && gcm_handler_ &&
         network_request_factory_ && prefetch_store_ &&
@@ -154,10 +171,11 @@
   prefetch_service_ = std::make_unique<PrefetchServiceImpl>(
       std::move(metrics_collector_), std::move(dispatcher_),
       std::move(gcm_handler_), std::move(network_request_factory_),
-      std::move(prefetch_store_), std::move(suggested_articles_observer_),
-      std::move(prefetch_downloader_), std::move(prefetch_importer_),
+      offline_page_model_.get(), std::move(prefetch_store_),
+      std::move(suggested_articles_observer_), std::move(prefetch_downloader_),
+      std::move(prefetch_importer_),
       std::move(prefetch_background_task_handler_),
-      std::move(prefetch_configuration_));
+      std::move(prefetch_configuration_), std::move(thumbnail_fetcher_));
 }
 
 std::unique_ptr<PrefetchService>
diff --git a/components/offline_pages/core/prefetch/prefetch_service_test_taco.h b/components/offline_pages/core/prefetch/prefetch_service_test_taco.h
index 61ac721..5f33b42 100644
--- a/components/offline_pages/core/prefetch/prefetch_service_test_taco.h
+++ b/components/offline_pages/core/prefetch/prefetch_service_test_taco.h
@@ -13,16 +13,18 @@
 
 namespace offline_pages {
 class OfflineMetricsCollector;
+class OfflinePageModel;
 class PrefetchBackgroundTaskHandler;
 class PrefetchConfiguration;
 class PrefetchDispatcher;
 class PrefetchDownloader;
 class PrefetchGCMHandler;
 class PrefetchImporter;
-class PrefetchService;
 class PrefetchNetworkRequestFactory;
+class PrefetchService;
 class PrefetchStore;
 class SuggestedArticlesObserver;
+class ThumbnailFetcher;
 
 // The taco class acts as a wrapper around the prefetch service making
 // it easy to create for tests, using test versions of the dependencies.
@@ -60,6 +62,10 @@
           prefetch_background_task_handler);
   void SetPrefetchConfiguration(
       std::unique_ptr<PrefetchConfiguration> prefetch_configuration);
+  // Default type: MockThumbnailFetcher.
+  void SetThumbnailFetcher(std::unique_ptr<ThumbnailFetcher> thumbnail_fetcher);
+  void SetOfflinePageModel(
+      std::unique_ptr<OfflinePageModel> offline_page_model);
 
   // Creates and caches an instance of PrefetchService, using default or
   // overridden test dependencies.
@@ -88,8 +94,9 @@
   std::unique_ptr<PrefetchBackgroundTaskHandler>
       prefetch_background_task_handler_;
   std::unique_ptr<PrefetchConfiguration> prefetch_configuration_;
-
   std::unique_ptr<PrefetchService> prefetch_service_;
+  std::unique_ptr<ThumbnailFetcher> thumbnail_fetcher_;
+  std::unique_ptr<OfflinePageModel> offline_page_model_;
 };
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/test_prefetch_dispatcher.cc b/components/offline_pages/core/prefetch/test_prefetch_dispatcher.cc
index 19482d1..a535ae5 100644
--- a/components/offline_pages/core/prefetch/test_prefetch_dispatcher.cc
+++ b/components/offline_pages/core/prefetch/test_prefetch_dispatcher.cc
@@ -64,6 +64,11 @@
   download_results.push_back(download_result);
 }
 
+void TestPrefetchDispatcher::ItemDownloaded(int64_t offline_id,
+                                            const ClientId& client_id) {
+  item_downloaded_results.push_back(std::make_pair(offline_id, client_id));
+}
+
 void TestPrefetchDispatcher::ArchiveImported(int64_t offline_id, bool success) {
   import_results.push_back(std::make_pair(offline_id, success));
 }
diff --git a/components/offline_pages/core/prefetch/test_prefetch_dispatcher.h b/components/offline_pages/core/prefetch/test_prefetch_dispatcher.h
index 865e7ac3..4ca398b 100644
--- a/components/offline_pages/core/prefetch/test_prefetch_dispatcher.h
+++ b/components/offline_pages/core/prefetch/test_prefetch_dispatcher.h
@@ -41,6 +41,7 @@
           success_downloads) override;
   void DownloadCompleted(
       const PrefetchDownloadResult& download_result) override;
+  void ItemDownloaded(int64_t offline_id, const ClientId& client_id) override;
   void ArchiveImported(int64_t offline_id, bool success) override;
 
   std::string latest_name_space;
@@ -48,6 +49,7 @@
   std::unique_ptr<ClientId> last_removed_client_id;
   std::vector<std::string> operation_list;
   std::vector<PrefetchDownloadResult> download_results;
+  std::vector<std::pair<int64_t, ClientId>> item_downloaded_results;
   std::vector<std::pair<int64_t, bool>> import_results;
 
   int cleanup_downloads_count = 0;
diff --git a/components/offline_pages/core/prefetch/thumbnail_fetcher.h b/components/offline_pages/core/prefetch/thumbnail_fetcher.h
new file mode 100644
index 0000000..e0c5c78
--- /dev/null
+++ b/components/offline_pages/core/prefetch/thumbnail_fetcher.h
@@ -0,0 +1,38 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_THUMBNAIL_FETCHER_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_THUMBNAIL_FETCHER_H_
+
+#include <string>
+#include "base/callback.h"
+
+namespace ntp_snippets {
+class ContentSuggestionsService;
+}
+
+namespace offline_pages {
+struct ClientId;
+
+// Fetches thumbnails that represent suggested pages.
+class ThumbnailFetcher {
+ public:
+  using ImageDataFetchedCallback =
+      base::OnceCallback<void(const std::string& image_data)>;
+
+  virtual void SetContentSuggestionsService(
+      ntp_snippets::ContentSuggestionsService* content_suggestions) {}
+
+  virtual ~ThumbnailFetcher() {}
+
+  // Fetches a thumbnail for a suggestion. Calls callback when the fetch
+  // completes. |image_data| is empty if the fetch failed, otherwise it will
+  // be raw image data that may be decoded with image_fetcher::ImageDecoder.
+  virtual void FetchSuggestionImageData(const ClientId& client_id,
+                                        ImageDataFetchedCallback callback) = 0;
+};
+
+}  // namespace offline_pages
+
+#endif  // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_THUMBNAIL_FETCHER_H_
diff --git a/components/offline_pages/core/stub_offline_page_model.cc b/components/offline_pages/core/stub_offline_page_model.cc
index 9dccefd0..64c808c 100644
--- a/components/offline_pages/core/stub_offline_page_model.cc
+++ b/components/offline_pages/core/stub_offline_page_model.cc
@@ -64,6 +64,10 @@
     const MultipleOfflinePageItemCallback& callback) {}
 void StubOfflinePageModel::GetPagesSupportedByDownloads(
     const MultipleOfflinePageItemCallback& callback) {}
+void StubOfflinePageModel::StoreThumbnail(const OfflinePageThumbnail& thumb) {}
+void StubOfflinePageModel::GetThumbnailByOfflineId(
+    int64_t offline_id,
+    GetThumbnailCallback callback) {}
 void StubOfflinePageModel::PublishInternalArchive(
     const OfflinePageItem& offline_page,
     std::unique_ptr<OfflinePageArchiver> archiver,
diff --git a/components/offline_pages/core/stub_offline_page_model.h b/components/offline_pages/core/stub_offline_page_model.h
index 1d36257..2927e7a 100644
--- a/components/offline_pages/core/stub_offline_page_model.h
+++ b/components/offline_pages/core/stub_offline_page_model.h
@@ -52,10 +52,9 @@
   void GetPageByOfflineId(
       int64_t offline_id,
       const SingleOfflinePageItemCallback& callback) override;
-  void GetPagesByURL(
-      const GURL& url,
-      URLSearchMode url_search_mode,
-      const MultipleOfflinePageItemCallback& callback) override;
+  void GetPagesByURL(const GURL& url,
+                     URLSearchMode url_search_mode,
+                     const MultipleOfflinePageItemCallback& callback) override;
   void GetPagesByRequestOrigin(
       const std::string& origin,
       const MultipleOfflinePageItemCallback& callback) override;
@@ -70,6 +69,9 @@
       const MultipleOfflinePageItemCallback& callback) override;
   void GetPagesSupportedByDownloads(
       const MultipleOfflinePageItemCallback& callback) override;
+  void StoreThumbnail(const OfflinePageThumbnail& thumb) override;
+  void GetThumbnailByOfflineId(int64_t offline_id,
+                               GetThumbnailCallback callback) override;
   void PublishInternalArchive(
       const OfflinePageItem& offline_page,
       std::unique_ptr<OfflinePageArchiver> archiver,
diff --git a/components/omnibox/browser/omnibox_edit_controller.cc b/components/omnibox/browser/omnibox_edit_controller.cc
index 04312eb5..f6fe7776 100644
--- a/components/omnibox/browser/omnibox_edit_controller.cc
+++ b/components/omnibox/browser/omnibox_edit_controller.cc
@@ -16,6 +16,10 @@
   transition_ = transition;
 }
 
+void OmniboxEditController::OnInputInProgress(bool in_progress) {}
+
+void OmniboxEditController::OnChanged() {}
+
 OmniboxEditController::OmniboxEditController()
     : disposition_(WindowOpenDisposition::CURRENT_TAB),
       transition_(ui::PageTransitionFromInt(
diff --git a/components/omnibox/browser/omnibox_edit_controller.h b/components/omnibox/browser/omnibox_edit_controller.h
index 8782838..b2bb643 100644
--- a/components/omnibox/browser/omnibox_edit_controller.h
+++ b/components/omnibox/browser/omnibox_edit_controller.h
@@ -20,12 +20,12 @@
                                     ui::PageTransition transition,
                                     AutocompleteMatchType::Type match_type);
 
-  virtual void OnInputInProgress(bool in_progress) = 0;
+  virtual void OnInputInProgress(bool in_progress);
 
   // Called when anything has changed that might affect the layout or contents
   // of the views around the edit, including the text of the edit and the
   // status of any keyword- or hint-related state.
-  virtual void OnChanged() = 0;
+  virtual void OnChanged();
 
   virtual ToolbarModel* GetToolbarModel() = 0;
   virtual const ToolbarModel* GetToolbarModel() const = 0;
diff --git a/components/omnibox/browser/test_omnibox_edit_controller.h b/components/omnibox/browser/test_omnibox_edit_controller.h
index 182ec18..8e6702d 100644
--- a/components/omnibox/browser/test_omnibox_edit_controller.h
+++ b/components/omnibox/browser/test_omnibox_edit_controller.h
@@ -13,8 +13,6 @@
   TestOmniboxEditController() {}
 
   // OmniboxEditController:
-  void OnInputInProgress(bool in_progress) override {}
-  void OnChanged() override {}
   TestToolbarModel* GetToolbarModel() override;
   const TestToolbarModel* GetToolbarModel() const override;
 
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc
index e7164c6..15994d5 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -36,6 +36,7 @@
 #include "content/common/browser_plugin/browser_plugin_messages.h"
 #include "content/common/content_constants_internal.h"
 #include "content/common/drag_messages.h"
+#include "content/common/frame_resize_params.h"
 #include "content/common/input/ime_text_span_conversions.h"
 #include "content/common/input_messages.h"
 #include "content/common/text_input_state.h"
@@ -164,6 +165,17 @@
   return GetGuestProxyRoutingID();
 }
 
+void BrowserPluginGuest::EnableAutoResize(const gfx::Size& min_size,
+                                          const gfx::Size& max_size) {
+  SendMessageToEmbedder(std::make_unique<BrowserPluginMsg_EnableAutoResize>(
+      browser_plugin_instance_id_, min_size, max_size));
+}
+
+void BrowserPluginGuest::DisableAutoResize() {
+  SendMessageToEmbedder(std::make_unique<BrowserPluginMsg_DisableAutoResize>(
+      browser_plugin_instance_id_));
+}
+
 void BrowserPluginGuest::ResizeDueToAutoResize(const gfx::Size& new_size,
                                                uint64_t sequence_number) {
   SendMessageToEmbedder(
@@ -1031,13 +1043,11 @@
 
 void BrowserPluginGuest::OnUpdateResizeParams(
     int browser_plugin_instance_id,
-    const gfx::Rect& frame_rect,
-    const ScreenInfo& screen_info,
-    uint64_t sequence_number,
-    const viz::LocalSurfaceId& local_surface_id) {
+    const viz::LocalSurfaceId& local_surface_id,
+    const FrameResizeParams& resize_params) {
   if (local_surface_id_ > local_surface_id ||
-      ((frame_rect_.size() != frame_rect.size() ||
-        screen_info_ != screen_info) &&
+      ((frame_rect_.size() != resize_params.screen_space_rect.size() ||
+        screen_info_ != resize_params.screen_info) &&
        local_surface_id_ == local_surface_id)) {
     SiteInstance* owner_site_instance = delegate_->GetOwnerSiteInstance();
     bad_message::ReceivedBadMessage(
@@ -1046,8 +1056,8 @@
     return;
   }
 
-  screen_info_ = screen_info;
-  frame_rect_ = frame_rect;
+  screen_info_ = resize_params.screen_info;
+  frame_rect_ = resize_params.screen_space_rect;
   GetWebContents()->SendScreenRects();
   local_surface_id_ = local_surface_id;
 
@@ -1059,8 +1069,13 @@
       RenderWidgetHostImpl::From(view->GetRenderWidgetHost());
   DCHECK(render_widget_host);
 
+  render_widget_host->SetAutoResize(resize_params.auto_resize_enabled,
+                                    resize_params.min_size_for_auto_resize,
+                                    resize_params.max_size_for_auto_resize);
+
   if (render_widget_host->auto_resize_enabled()) {
-    render_widget_host->DidAllocateLocalSurfaceIdForAutoResize(sequence_number);
+    render_widget_host->DidAllocateLocalSurfaceIdForAutoResize(
+        resize_params.auto_resize_sequence_number);
     return;
   }
 
diff --git a/content/browser/browser_plugin/browser_plugin_guest.h b/content/browser/browser_plugin/browser_plugin_guest.h
index f1bf1cb..4e42d65 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.h
+++ b/content/browser/browser_plugin/browser_plugin_guest.h
@@ -71,6 +71,7 @@
 class RenderWidgetHostViewBase;
 class SiteInstance;
 struct DropData;
+struct FrameResizeParams;
 struct ScreenInfo;
 struct TextInputState;
 
@@ -178,6 +179,8 @@
 
   BrowserPluginGuestManager* GetBrowserPluginGuestManager() const;
 
+  void EnableAutoResize(const gfx::Size& min_size, const gfx::Size& max_size);
+  void DisableAutoResize();
   void ResizeDueToAutoResize(const gfx::Size& new_size,
                              uint64_t sequence_number);
 
@@ -332,10 +335,8 @@
   void OnUnlockMouse();
   void OnUnlockMouseAck(int instance_id);
   void OnUpdateResizeParams(int instance_id,
-                            const gfx::Rect& frame_rect,
-                            const ScreenInfo& screen_info,
-                            uint64_t sequence_number,
-                            const viz::LocalSurfaceId& local_surface_id);
+                            const viz::LocalSurfaceId& local_surface_id,
+                            const FrameResizeParams& resize_params);
 
   void OnTextInputStateChanged(const TextInputState& params);
   void OnImeSetComposition(
diff --git a/content/browser/frame_host/cross_process_frame_connector.cc b/content/browser/frame_host/cross_process_frame_connector.cc
index 8f24d179..ca91f95 100644
--- a/content/browser/frame_host/cross_process_frame_connector.cc
+++ b/content/browser/frame_host/cross_process_frame_connector.cc
@@ -271,15 +271,12 @@
 }
 
 void CrossProcessFrameConnector::OnUpdateResizeParams(
-    const gfx::Rect& screen_space_rect,
-    const gfx::Size& local_frame_size,
-    const ScreenInfo& screen_info,
-    uint64_t sequence_number,
-    const viz::SurfaceId& surface_id) {
+    const viz::SurfaceId& surface_id,
+    const FrameResizeParams& resize_params) {
   // If the |screen_space_rect| or |screen_info| of the frame has changed, then
   // the viz::LocalSurfaceId must also change.
-  if ((last_received_local_frame_size_ != local_frame_size ||
-       screen_info_ != screen_info) &&
+  if ((last_received_local_frame_size_ != resize_params.local_frame_size ||
+       screen_info_ != resize_params.screen_info) &&
       local_surface_id_ == surface_id.local_surface_id()) {
     bad_message::ReceivedBadMessage(
         frame_proxy_in_parent_renderer_->GetProcess(),
@@ -287,9 +284,8 @@
     return;
   }
 
-  last_received_local_frame_size_ = local_frame_size;
-  UpdateResizeParams(screen_space_rect, local_frame_size, screen_info,
-                     sequence_number, surface_id);
+  last_received_local_frame_size_ = resize_params.local_frame_size;
+  UpdateResizeParams(surface_id, resize_params);
 }
 
 void CrossProcessFrameConnector::OnUpdateViewportIntersection(
@@ -373,6 +369,17 @@
   return nullptr;
 }
 
+void CrossProcessFrameConnector::EnableAutoResize(const gfx::Size& min_size,
+                                                  const gfx::Size& max_size) {
+  frame_proxy_in_parent_renderer_->Send(new FrameMsg_EnableAutoResize(
+      frame_proxy_in_parent_renderer_->GetRoutingID(), min_size, max_size));
+}
+
+void CrossProcessFrameConnector::DisableAutoResize() {
+  frame_proxy_in_parent_renderer_->Send(new FrameMsg_DisableAutoResize(
+      frame_proxy_in_parent_renderer_->GetRoutingID()));
+}
+
 bool CrossProcessFrameConnector::IsInert() const {
   return is_inert_;
 }
diff --git a/content/browser/frame_host/cross_process_frame_connector.h b/content/browser/frame_host/cross_process_frame_connector.h
index 3388f03..95e72d6 100644
--- a/content/browser/frame_host/cross_process_frame_connector.h
+++ b/content/browser/frame_host/cross_process_frame_connector.h
@@ -12,6 +12,7 @@
 #include "components/viz/common/surfaces/surface_id.h"
 #include "content/browser/renderer_host/frame_connector_delegate.h"
 #include "content/common/content_export.h"
+#include "content/common/frame_resize_params.h"
 
 namespace IPC {
 class Message;
@@ -19,7 +20,6 @@
 
 namespace content {
 class RenderFrameProxyHost;
-struct ScreenInfo;
 
 // CrossProcessFrameConnector provides the platform view abstraction for
 // RenderWidgetHostViewChildFrame allowing RWHVChildFrame to remain ignorant
@@ -100,6 +100,9 @@
   void FocusRootView() override;
   bool LockMouse() override;
   void UnlockMouse() override;
+  void EnableAutoResize(const gfx::Size& min_size,
+                        const gfx::Size& max_size) override;
+  void DisableAutoResize() override;
   bool IsInert() const override;
   bool IsHidden() const override;
   bool IsThrottled() const override;
@@ -130,11 +133,8 @@
   void ResetScreenSpaceRect();
 
   // Handlers for messages received from the parent frame.
-  void OnUpdateResizeParams(const gfx::Rect& screen_space_rect,
-                            const gfx::Size& local_frame_size,
-                            const ScreenInfo& screen_info,
-                            uint64_t sequence_number,
-                            const viz::SurfaceId& surface_id);
+  void OnUpdateResizeParams(const viz::SurfaceId& surface_id,
+                            const FrameResizeParams& frame_resize_params);
   void OnUpdateViewportIntersection(const gfx::Rect& viewport_intersection,
                                     const gfx::Rect& compositor_visible_rect);
   void OnVisibilityChanged(bool visible);
diff --git a/content/browser/frame_host/interstitial_page_impl.cc b/content/browser/frame_host/interstitial_page_impl.cc
index e765a82..af9c604 100644
--- a/content/browser/frame_host/interstitial_page_impl.cc
+++ b/content/browser/frame_host/interstitial_page_impl.cc
@@ -58,10 +58,6 @@
 #include "net/url_request/url_request_context_getter.h"
 #include "ui/base/page_transition_types.h"
 
-#if defined(OS_ANDROID)
-#include "content/browser/web_contents/web_contents_view_android.h"
-#endif
-
 using blink::WebDragOperation;
 using blink::WebDragOperationsMask;
 
@@ -798,15 +794,6 @@
       << "InterstitialPage does not support showing full screen popups.";
 }
 
-void InterstitialPageImpl::ShowContextMenu(RenderFrameHost* render_frame_host,
-                                           const ContextMenuParams& params) {
-#if defined(OS_ANDROID)
-  static_cast<WebContentsViewAndroid*>(
-      static_cast<WebContentsImpl*>(web_contents())->GetView())
-      ->ShowContextMenu(render_frame_host, params);
-#endif
-}
-
 void InterstitialPageImpl::ShowCreatedWindow(int process_id,
                                              int main_frame_widget_route_id,
                                              WindowOpenDisposition disposition,
diff --git a/content/browser/frame_host/interstitial_page_impl.h b/content/browser/frame_host/interstitial_page_impl.h
index ef1474b..79df2f48 100644
--- a/content/browser/frame_host/interstitial_page_impl.h
+++ b/content/browser/frame_host/interstitial_page_impl.h
@@ -107,8 +107,6 @@
                const NotificationDetails& details) override;
 
   // RenderFrameHostDelegate implementation:
-  void ShowContextMenu(RenderFrameHost* render_frame_host,
-                       const ContextMenuParams& params) override;
   bool OnMessageReceived(RenderFrameHostImpl* render_frame_host,
                          const IPC::Message& message) override;
   void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
diff --git a/content/browser/frame_host/render_widget_host_view_guest.cc b/content/browser/frame_host/render_widget_host_view_guest.cc
index 507b5d0c..4daea2e9 100644
--- a/content/browser/frame_host/render_widget_host_view_guest.cc
+++ b/content/browser/frame_host/render_widget_host_view_guest.cc
@@ -694,6 +694,17 @@
     RenderWidgetHostViewBase::GetScreenInfo(screen_info);
 }
 
+void RenderWidgetHostViewGuest::EnableAutoResize(const gfx::Size& min_size,
+                                                 const gfx::Size& max_size) {
+  if (guest_)
+    guest_->EnableAutoResize(min_size, max_size);
+}
+
+void RenderWidgetHostViewGuest::DisableAutoResize(const gfx::Size& new_size) {
+  if (guest_)
+    guest_->DisableAutoResize();
+}
+
 viz::ScopedSurfaceIdAllocator RenderWidgetHostViewGuest::ResizeDueToAutoResize(
     const gfx::Size& new_size,
     uint64_t sequence_number) {
diff --git a/content/browser/frame_host/render_widget_host_view_guest.h b/content/browser/frame_host/render_widget_host_view_guest.h
index 707e5fb..ed057fc 100644
--- a/content/browser/frame_host/render_widget_host_view_guest.h
+++ b/content/browser/frame_host/render_widget_host_view_guest.h
@@ -147,6 +147,10 @@
 
   void GetScreenInfo(ScreenInfo* screen_info) const override;
 
+  void EnableAutoResize(const gfx::Size& min_size,
+                        const gfx::Size& max_size) override;
+  void DisableAutoResize(const gfx::Size& new_size) override;
+
   viz::ScopedSurfaceIdAllocator ResizeDueToAutoResize(
       const gfx::Size& new_size,
       uint64_t sequence_number) override;
diff --git a/content/browser/renderer_host/frame_connector_delegate.cc b/content/browser/renderer_host/frame_connector_delegate.cc
index aca73b8..9ec6c75 100644
--- a/content/browser/renderer_host/frame_connector_delegate.cc
+++ b/content/browser/renderer_host/frame_connector_delegate.cc
@@ -7,6 +7,7 @@
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
 #include "content/common/content_switches_internal.h"
+#include "content/common/frame_resize_params.h"
 
 namespace content {
 
@@ -25,16 +26,13 @@
 }
 
 void FrameConnectorDelegate::UpdateResizeParams(
-    const gfx::Rect& screen_space_rect,
-    const gfx::Size& local_frame_size,
-    const ScreenInfo& screen_info,
-    uint64_t sequence_number,
-    const viz::SurfaceId& surface_id) {
-  screen_info_ = screen_info;
+    const viz::SurfaceId& surface_id,
+    const FrameResizeParams& resize_params) {
+  screen_info_ = resize_params.screen_info;
   local_surface_id_ = surface_id.local_surface_id();
 
-  SetScreenSpaceRect(screen_space_rect);
-  SetLocalFrameSize(local_frame_size);
+  SetScreenSpaceRect(resize_params.screen_space_rect);
+  SetLocalFrameSize(resize_params.local_frame_size);
 
   if (!view_)
     return;
@@ -45,8 +43,13 @@
   RenderWidgetHostImpl* render_widget_host = view_->host();
   DCHECK(render_widget_host);
 
+  render_widget_host->SetAutoResize(resize_params.auto_resize_enabled,
+                                    resize_params.min_size_for_auto_resize,
+                                    resize_params.max_size_for_auto_resize);
+
   if (render_widget_host->auto_resize_enabled()) {
-    render_widget_host->DidAllocateLocalSurfaceIdForAutoResize(sequence_number);
+    render_widget_host->DidAllocateLocalSurfaceIdForAutoResize(
+        resize_params.auto_resize_sequence_number);
     return;
   }
 
@@ -83,6 +86,11 @@
   return false;
 }
 
+void FrameConnectorDelegate::EnableAutoResize(const gfx::Size& min_size,
+                                              const gfx::Size& max_size) {}
+
+void FrameConnectorDelegate::DisableAutoResize() {}
+
 bool FrameConnectorDelegate::IsInert() const {
   return false;
 }
diff --git a/content/browser/renderer_host/frame_connector_delegate.h b/content/browser/renderer_host/frame_connector_delegate.h
index f335fd0..577db6d01 100644
--- a/content/browser/renderer_host/frame_connector_delegate.h
+++ b/content/browser/renderer_host/frame_connector_delegate.h
@@ -30,6 +30,7 @@
 class RenderWidgetHostViewBase;
 class RenderWidgetHostViewChildFrame;
 class WebCursor;
+struct FrameResizeParams;
 
 //
 // FrameConnectorDelegate
@@ -72,11 +73,8 @@
       const blink::WebIntrinsicSizingInfo&) {}
 
   // Sends new resize parameters to the sub-frame's renderer.
-  void UpdateResizeParams(const gfx::Rect& screen_space_rect,
-                          const gfx::Size& local_frame_size,
-                          const ScreenInfo& screen_info,
-                          uint64_t sequence_number,
-                          const viz::SurfaceId& surface_id);
+  void UpdateResizeParams(const viz::SurfaceId& surface_id,
+                          const FrameResizeParams& resize_params);
 
   // Return the size of the CompositorFrame to use in the child renderer.
   const gfx::Size& local_frame_size_in_pixels() {
@@ -184,6 +182,14 @@
     screen_info_ = screen_info;
   }
 
+  // Informs the parent the child will enter auto-resize mode, automatically
+  // resizing itself to the provided |min_size| and |max_size| constraints.
+  virtual void EnableAutoResize(const gfx::Size& min_size,
+                                const gfx::Size& max_size);
+
+  // Turns off auto-resize mode.
+  virtual void DisableAutoResize();
+
   // Determines whether the current view's content is inert, either because
   // an HTMLDialogElement is being modally displayed in a higher-level frame,
   // or because the inert attribute has been specified.
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index c416cf45..c4dbfe4f 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -956,21 +956,6 @@
   Send(new ViewMsg_EnablePreferredSizeChangedMode(GetRoutingID()));
 }
 
-void RenderViewHostImpl::EnableAutoResize(const gfx::Size& min_size,
-                                          const gfx::Size& max_size) {
-  GetWidget()->SetAutoResize(true, min_size, max_size);
-}
-
-void RenderViewHostImpl::DisableAutoResize(const gfx::Size& new_size) {
-  if (!new_size.IsEmpty())
-    GetWidget()->GetView()->SetSize(new_size);
-  // This clears the cached value in the WebContents, so that OOPIFs will
-  // stop using it.
-  if (GetWidget()->delegate())
-    GetWidget()->delegate()->ResetAutoResizeSize();
-  GetWidget()->SetAutoResize(false, gfx::Size(), gfx::Size());
-}
-
 void RenderViewHostImpl::ExecuteMediaPlayerActionAtLocation(
   const gfx::Point& location, const blink::WebMediaPlayerAction& action) {
   // TODO(wjmaclean): See if coordinate transforms need to be done for OOPIFs
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index 885fd39..4ccbece5 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -92,9 +92,6 @@
       int request_id,
       const std::vector<base::FilePath>& files) override;
   void DisableScrollbarsForThreshold(const gfx::Size& size) override;
-  void EnableAutoResize(const gfx::Size& min_size,
-                        const gfx::Size& max_size) override;
-  void DisableAutoResize(const gfx::Size& new_size) override;
   void EnablePreferredSizeMode() override;
   void ExecuteMediaPlayerActionAtLocation(
       const gfx::Point& location,
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 35967ca4..24e004f0 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1922,7 +1922,6 @@
   auto_resize_enabled_ = enable;
   min_size_for_auto_resize_ = min_size;
   max_size_for_auto_resize_ = max_size;
-  WasResized();
 }
 
 void RenderWidgetHostImpl::Destroy(bool also_delete) {
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 8fe4e1b..7a729d03 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -2360,7 +2360,7 @@
   viz::LocalSurfaceId local_surface_id1(view_->GetLocalSurfaceId());
   EXPECT_TRUE(local_surface_id1.is_valid());
 
-  widget_host_->SetAutoResize(true, gfx::Size(50, 50), gfx::Size(100, 100));
+  view_->EnableAutoResize(gfx::Size(50, 50), gfx::Size(100, 100));
   sink_->ClearMessages();
   ViewHostMsg_ResizeOrRepaint_ACK_Params params;
   params.view_size = gfx::Size(75, 75);
@@ -2427,7 +2427,7 @@
   viz::LocalSurfaceId local_surface_id1(view_->GetLocalSurfaceId());
   EXPECT_TRUE(local_surface_id1.is_valid());
 
-  widget_host_->SetAutoResize(true, gfx::Size(50, 50), gfx::Size(100, 100));
+  view_->EnableAutoResize(gfx::Size(50, 50), gfx::Size(100, 100));
   sink_->ClearMessages();
   ViewHostMsg_ResizeOrRepaint_ACK_Params params;
   params.view_size = gfx::Size(75, 75);
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
index 9d839162..7655a0f 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -307,6 +307,23 @@
   text_input_manager_ = nullptr;
 }
 
+void RenderWidgetHostViewBase::EnableAutoResize(const gfx::Size& min_size,
+                                                const gfx::Size& max_size) {
+  host()->SetAutoResize(true, min_size, max_size);
+  host()->WasResized();
+}
+
+void RenderWidgetHostViewBase::DisableAutoResize(const gfx::Size& new_size) {
+  if (!new_size.IsEmpty())
+    SetSize(new_size);
+  // This clears the cached value in the WebContents, so that OOPIFs will
+  // stop using it.
+  if (host()->delegate())
+    host()->delegate()->ResetAutoResizeSize();
+  host()->SetAutoResize(false, gfx::Size(), gfx::Size());
+  host()->WasResized();
+}
+
 bool RenderWidgetHostViewBase::IsScrollOffsetAtTop() const {
   return is_scroll_offset_at_top_;
 }
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h
index 2dfadd2..74b17398 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -127,6 +127,9 @@
   viz::mojom::FrameSinkVideoCapturerPtr CreateVideoCapturer() override;
   void FocusedNodeTouched(bool editable) override;
   void GetScreenInfo(ScreenInfo* screen_info) const override;
+  void EnableAutoResize(const gfx::Size& min_size,
+                        const gfx::Size& max_size) override;
+  void DisableAutoResize(const gfx::Size& new_size) override;
   bool IsScrollOffsetAtTop() const override;
   float GetDeviceScaleFactor() const final;
   TouchSelectionControllerClientManager*
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
index d2ef6245..9f9ee99 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -1012,6 +1012,21 @@
     DisplayUtil::GetDefaultScreenInfo(screen_info);
 }
 
+void RenderWidgetHostViewChildFrame::EnableAutoResize(
+    const gfx::Size& min_size,
+    const gfx::Size& max_size) {
+  if (frame_connector_)
+    frame_connector_->EnableAutoResize(min_size, max_size);
+}
+
+void RenderWidgetHostViewChildFrame::DisableAutoResize(
+    const gfx::Size& new_size) {
+  // For child frames, the size comes from the parent when auto-resize is
+  // disabled so we ignore |new_size| here.
+  if (frame_connector_)
+    frame_connector_->DisableAutoResize();
+}
+
 viz::ScopedSurfaceIdAllocator
 RenderWidgetHostViewChildFrame::ResizeDueToAutoResize(
     const gfx::Size& new_size,
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h
index bc1fdc58..033a546 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.h
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -181,6 +181,9 @@
       BrowserAccessibilityDelegate* delegate,
       bool for_root_frame) override;
   void GetScreenInfo(ScreenInfo* screen_info) const override;
+  void EnableAutoResize(const gfx::Size& min_size,
+                        const gfx::Size& max_size) override;
+  void DisableAutoResize(const gfx::Size& new_size) override;
   viz::ScopedSurfaceIdAllocator ResizeDueToAutoResize(
       const gfx::Size& new_size,
       uint64_t sequence_number) override;
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
index fcc9890..a568705e 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
@@ -125,8 +125,10 @@
   FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
                             ->GetFrameTree()
                             ->root();
-  root->current_frame_host()->render_view_host()->EnableAutoResize(
-      gfx::Size(0, 0), gfx::Size(100, 100));
+  root->current_frame_host()
+      ->GetRenderWidgetHost()
+      ->GetView()
+      ->EnableAutoResize(gfx::Size(0, 0), gfx::Size(100, 100));
 
   RenderWidgetHostView* rwhv =
       root->child_at(0)->current_frame_host()->GetRenderWidgetHost()->GetView();
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
index 5d62d996..59dec674 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
@@ -28,6 +28,7 @@
 #include "content/browser/renderer_host/frame_connector_delegate.h"
 #include "content/browser/renderer_host/render_widget_host_delegate.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/common/frame_resize_params.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/common/content_features.h"
@@ -351,9 +352,11 @@
 
   process->sink().ClearMessages();
 
-  test_frame_connector_->UpdateResizeParams(screen_space_rect,
-                                            compositor_viewport_pixel_size,
-                                            ScreenInfo(), 1u, surface_id);
+  FrameResizeParams resize_params;
+  resize_params.screen_space_rect = screen_space_rect;
+  resize_params.local_frame_size = compositor_viewport_pixel_size;
+  resize_params.auto_resize_sequence_number = 1u;
+  test_frame_connector_->UpdateResizeParams(surface_id, resize_params);
 
   ASSERT_EQ(1u, process->sink().message_count());
 
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 79cafd00..48fda7a 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -2632,6 +2632,10 @@
       public ServiceWorkerVersion::Listener {
  public:
   using self = ServiceWorkerVersionBrowserV8CacheTest;
+  ServiceWorkerVersionBrowserV8CacheTest() {
+    scoped_feature_list_.InitAndDisableFeature(
+        features::kServiceWorkerScriptFullCodeCache);
+  }
   ~ServiceWorkerVersionBrowserV8CacheTest() override {
     if (version_)
       version_->RemoveListener(this);
@@ -2655,6 +2659,9 @@
 
   base::Closure cache_updated_closure_;
   size_t metadata_size_ = 0;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserV8CacheTest, Restart) {
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index e58713a..395fe3d 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -138,6 +138,8 @@
     "frame_owner_properties.h",
     "frame_replication_state.cc",
     "frame_replication_state.h",
+    "frame_resize_params.cc",
+    "frame_resize_params.h",
     "gin_java_bridge_messages.h",
     "in_process_child_thread_params.cc",
     "in_process_child_thread_params.h",
diff --git a/content/common/browser_plugin/browser_plugin_messages.h b/content/common/browser_plugin/browser_plugin_messages.h
index 80b3ab8..2f3126e 100644
--- a/content/common/browser_plugin/browser_plugin_messages.h
+++ b/content/common/browser_plugin/browser_plugin_messages.h
@@ -15,6 +15,7 @@
 #include "content/common/content_param_traits.h"
 #include "content/common/cursors/webcursor.h"
 #include "content/common/edit_command.h"
+#include "content/common/frame_resize_params.h"
 #include "content/public/common/drop_data.h"
 #include "content/public/common/screen_info.h"
 #include "ipc/ipc_channel_handle.h"
@@ -155,12 +156,10 @@
                      int /* browser_plugin_instance_id */)
 
 // Sent when plugin's position has changed.
-IPC_MESSAGE_CONTROL5(BrowserPluginHostMsg_UpdateResizeParams,
+IPC_MESSAGE_CONTROL3(BrowserPluginHostMsg_UpdateResizeParams,
                      int /* browser_plugin_instance_id */,
-                     gfx::Rect /* frame_rect */,
-                     content::ScreenInfo /* screen_info */,
-                     uint64_t /* sequence_number */,
-                     viz::LocalSurfaceId /* local_surface_id */)
+                     viz::LocalSurfaceId /* local_surface_id */,
+                     content::FrameResizeParams /* resize_params */)
 
 // -----------------------------------------------------------------------------
 // These messages are from the browser process to the embedder.
@@ -194,6 +193,18 @@
                      int /* browser_plugin_instance_id */,
                      uint64_t /* sequence_number */)
 
+// Requests a viz::LocalSurfaceId to enable auto-resize mode from the parent
+// renderer.
+IPC_MESSAGE_CONTROL3(BrowserPluginMsg_EnableAutoResize,
+                     int /* browser_plugin_instance_id */,
+                     gfx::Size /* min_size */,
+                     gfx::Size /* max_size */)
+
+// Requests a viz::LocalSurfaceId to disable auto-resize-mode from the parent
+// renderer.
+IPC_MESSAGE_CONTROL1(BrowserPluginMsg_DisableAutoResize,
+                     int /* browser_plugin_instance_id */)
+
 // When the guest starts/stops listening to touch events, it needs to notify the
 // plugin in the embedder about it.
 IPC_MESSAGE_CONTROL2(BrowserPluginMsg_ShouldAcceptTouchEvents,
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index c5262f8..8bbf69b 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -29,6 +29,7 @@
 #include "content/common/frame_message_structs.h"
 #include "content/common/frame_owner_properties.h"
 #include "content/common/frame_replication_state.h"
+#include "content/common/frame_resize_params.h"
 #include "content/common/navigation_gesture.h"
 #include "content/common/navigation_params.h"
 #include "content/common/resource_timing_info.h"
@@ -226,6 +227,16 @@
   IPC_STRUCT_TRAITS_MEMBER(required_csp)
 IPC_STRUCT_TRAITS_END()
 
+IPC_STRUCT_TRAITS_BEGIN(content::FrameResizeParams)
+  IPC_STRUCT_TRAITS_MEMBER(screen_info)
+  IPC_STRUCT_TRAITS_MEMBER(auto_resize_enabled)
+  IPC_STRUCT_TRAITS_MEMBER(min_size_for_auto_resize)
+  IPC_STRUCT_TRAITS_MEMBER(max_size_for_auto_resize)
+  IPC_STRUCT_TRAITS_MEMBER(auto_resize_sequence_number)
+  IPC_STRUCT_TRAITS_MEMBER(screen_space_rect)
+  IPC_STRUCT_TRAITS_MEMBER(local_frame_size)
+IPC_STRUCT_TRAITS_END()
+
 IPC_STRUCT_TRAITS_BEGIN(blink::FramePolicy)
   IPC_STRUCT_TRAITS_MEMBER(sandbox_flags)
   IPC_STRUCT_TRAITS_MEMBER(container_policy)
@@ -980,6 +991,16 @@
 IPC_MESSAGE_ROUTED1(FrameMsg_ResizeDueToAutoResize,
                     uint64_t /* sequence_number */)
 
+// Requests a viz::LocalSurfaceId to enable auto-resize mode from the parent
+// renderer.
+IPC_MESSAGE_ROUTED2(FrameMsg_EnableAutoResize,
+                    gfx::Size /* min_size */,
+                    gfx::Size /* max_size */)
+
+// Requests a viz::LocalSurfaceId to disable auto-resize-mode from the parent
+// renderer.
+IPC_MESSAGE_ROUTED0(FrameMsg_DisableAutoResize)
+
 #if defined(OS_ANDROID)
 // Request the distance to the nearest find result in a frame from the point at
 // (x, y), defined in fractions of the content document's width and height. The
@@ -1473,12 +1494,9 @@
 IPC_MESSAGE_ROUTED0(FrameHostMsg_SwapOut_ACK)
 
 // Tells the browser that a child's resize parameters have changed.
-IPC_MESSAGE_ROUTED5(FrameHostMsg_UpdateResizeParams,
-                    gfx::Rect /* screen_space_rect */,
-                    gfx::Size /* local_frame_size */,
-                    content::ScreenInfo /* screen_info */,
-                    uint64_t /* sequence_number */,
-                    viz::SurfaceId /* surface_id */)
+IPC_MESSAGE_ROUTED2(FrameHostMsg_UpdateResizeParams,
+                    viz::SurfaceId /* surface_id */,
+                    content::FrameResizeParams)
 
 // Sent by a parent frame to update its child's viewport intersection rect for
 // use by the IntersectionObserver API.
diff --git a/content/common/frame_resize_params.cc b/content/common/frame_resize_params.cc
new file mode 100644
index 0000000..fc5059d
--- /dev/null
+++ b/content/common/frame_resize_params.cc
@@ -0,0 +1,19 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/frame_resize_params.h"
+
+namespace content {
+
+FrameResizeParams::FrameResizeParams()
+    : auto_resize_enabled(false), auto_resize_sequence_number(0u) {}
+
+FrameResizeParams::FrameResizeParams(const FrameResizeParams& other) = default;
+
+FrameResizeParams::~FrameResizeParams() {}
+
+FrameResizeParams& FrameResizeParams::operator=(
+    const FrameResizeParams& other) = default;
+
+}  // namespace content
diff --git a/content/common/frame_resize_params.h b/content/common/frame_resize_params.h
new file mode 100644
index 0000000..0a1fc4d
--- /dev/null
+++ b/content/common/frame_resize_params.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_FRAME_RESIZE_PARAMS_H_
+#define CONTENT_COMMON_FRAME_RESIZE_PARAMS_H_
+
+#include "content/common/content_export.h"
+#include "content/public/common/screen_info.h"
+#include "third_party/WebKit/public/platform/WebDisplayMode.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+
+// TODO(fsamuel): We might want to unify this with content::ResizeParams.
+struct CONTENT_EXPORT FrameResizeParams {
+  FrameResizeParams();
+  FrameResizeParams(const FrameResizeParams& other);
+  ~FrameResizeParams();
+
+  FrameResizeParams& operator=(const FrameResizeParams& other);
+
+  // Information about the screen (dpi, depth, etc..).
+  ScreenInfo screen_info;
+
+  // Whether or not blink should be in auto-resize mode.
+  bool auto_resize_enabled;
+
+  // The minimum size for Blink if auto-resize is enabled.
+  gfx::Size min_size_for_auto_resize;
+
+  // The maximum size for Blink if auto-resize is enabled.
+  gfx::Size max_size_for_auto_resize;
+
+  // This variable is increased after each auto-resize. If the
+  // renderer receives a ResizeParams with stale auto_resize_seqence_number,
+  // then the resize request is dropped.
+  uint64_t auto_resize_sequence_number;
+
+  gfx::Rect screen_space_rect;
+
+  gfx::Size local_frame_size;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_FRAME_RESIZE_PARAMS_H_
diff --git a/content/public/browser/render_view_host.h b/content/public/browser/render_view_host.h
index 322f3ced..ca7bffa6 100644
--- a/content/public/browser/render_view_host.h
+++ b/content/public/browser/render_view_host.h
@@ -95,14 +95,6 @@
   // threshold.
   virtual void DisableScrollbarsForThreshold(const gfx::Size& size) = 0;
 
-  // Instructs the RenderView to automatically resize and send back updates
-  // for the new size.
-  virtual void EnableAutoResize(const gfx::Size& min_size,
-                                const gfx::Size& max_size) = 0;
-
-  // Turns off auto-resize and gives a new size that the view should be.
-  virtual void DisableAutoResize(const gfx::Size& new_size) = 0;
-
   // Instructs the RenderView to send back updates to the preferred size.
   virtual void EnablePreferredSizeMode() = 0;
 
diff --git a/content/public/browser/render_widget_host_view.h b/content/public/browser/render_widget_host_view.h
index ba9f39f..1dff1b6 100644
--- a/content/public/browser/render_widget_host_view.h
+++ b/content/public/browser/render_widget_host_view.h
@@ -71,6 +71,14 @@
   // Tells the View to size itself to the specified size.
   virtual void SetSize(const gfx::Size& size) = 0;
 
+  // Instructs the View to automatically resize and send back updates
+  // for the new size.
+  virtual void EnableAutoResize(const gfx::Size& min_size,
+                                const gfx::Size& max_size) = 0;
+
+  // Turns off auto-resize and gives a new size that the view should be.
+  virtual void DisableAutoResize(const gfx::Size& new_size) = 0;
+
   // Tells the View to size and move itself to the specified size and point in
   // screen space.
   virtual void SetBounds(const gfx::Rect& rect) = 0;
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 0f4a013..d0ca2a33 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -283,7 +283,7 @@
 
 // Generate V8 full code cache for PWAs.
 const base::Feature kPWAFullCodeCache{"PWAFullCodeCache",
-                                      base::FEATURE_DISABLED_BY_DEFAULT};
+                                      base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enable raster-inducing scroll.
 const base::Feature kRasterInducingScroll{"RasterInducingScroll",
@@ -335,7 +335,7 @@
 
 // Generate V8 full code cache of service worker scripts.
 const base::Feature kServiceWorkerScriptFullCodeCache{
-    "ServiceWorkerScriptFullCodeCache", base::FEATURE_DISABLED_BY_DEFAULT};
+    "ServiceWorkerScriptFullCodeCache", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Establish direct connection from clients to the service worker.
 const base::Feature kServiceWorkerServicification{
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc
index 8a0a5bac..2499e683 100644
--- a/content/renderer/browser_plugin/browser_plugin.cc
+++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -22,6 +22,7 @@
 #include "components/viz/common/surfaces/surface_info.h"
 #include "content/common/browser_plugin/browser_plugin_constants.h"
 #include "content/common/browser_plugin/browser_plugin_messages.h"
+#include "content/common/frame_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
@@ -123,6 +124,8 @@
     IPC_MESSAGE_HANDLER(BrowserPluginMsg_Attach_ACK, OnAttachACK)
     IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestGone, OnGuestGone)
     IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestReady, OnGuestReady)
+    IPC_MESSAGE_HANDLER(BrowserPluginMsg_EnableAutoResize, OnEnableAutoResize)
+    IPC_MESSAGE_HANDLER(BrowserPluginMsg_DisableAutoResize, OnDisableAutoResize)
     IPC_MESSAGE_HANDLER(BrowserPluginMsg_ResizeDueToAutoResize,
                         OnResizeDueToAutoResize)
     IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetCursor, OnSetCursor)
@@ -146,10 +149,10 @@
 
   if (!enable_surface_synchronization_) {
     compositing_helper_->SetPrimarySurfaceId(surface_info.id(),
-                                             frame_rect().size());
+                                             screen_space_rect().size());
   }
   compositing_helper_->SetFallbackSurfaceId(surface_info.id(),
-                                            frame_rect().size());
+                                            screen_space_rect().size());
 }
 
 void BrowserPlugin::UpdateDOMAttribute(const std::string& attribute_name,
@@ -168,7 +171,7 @@
   BrowserPluginHostMsg_Attach_Params attach_params;
   attach_params.focused = ShouldGuestBeFocused();
   attach_params.visible = visible_;
-  attach_params.frame_rect = frame_rect();
+  attach_params.frame_rect = screen_space_rect();
   attach_params.is_full_page_plugin = false;
   if (Container()) {
     blink::WebLocalFrame* frame = Container()->GetDocument().GetFrame();
@@ -248,10 +251,18 @@
 
 void BrowserPlugin::WasResized() {
   bool size_changed = !sent_resize_params_ ||
-                      sent_resize_params_->frame_rect.size() !=
-                          pending_resize_params_.frame_rect.size() ||
-                      sent_resize_params_->sequence_number !=
-                          pending_resize_params_.sequence_number;
+                      sent_resize_params_->auto_resize_enabled !=
+                          pending_resize_params_.auto_resize_enabled ||
+                      sent_resize_params_->min_size_for_auto_resize !=
+                          pending_resize_params_.min_size_for_auto_resize ||
+                      sent_resize_params_->max_size_for_auto_resize !=
+                          pending_resize_params_.max_size_for_auto_resize ||
+                      sent_resize_params_->local_frame_size !=
+                          pending_resize_params_.local_frame_size ||
+                      sent_resize_params_->screen_space_rect.size() !=
+                          pending_resize_params_.screen_space_rect.size() ||
+                      sent_resize_params_->auto_resize_sequence_number !=
+                          pending_resize_params_.auto_resize_sequence_number;
 
   bool synchronized_params_changed =
       !sent_resize_params_ || size_changed ||
@@ -263,24 +274,24 @@
   if (enable_surface_synchronization_ && frame_sink_id_.is_valid()) {
     compositing_helper_->SetPrimarySurfaceId(
         viz::SurfaceId(frame_sink_id_, GetLocalSurfaceId()),
-        frame_rect().size());
+        screen_space_rect().size());
   }
 
-  bool position_changed =
-      !sent_resize_params_ || sent_resize_params_->frame_rect.origin() !=
-                                  pending_resize_params_.frame_rect.origin();
+  bool position_changed = !sent_resize_params_ ||
+                          sent_resize_params_->screen_space_rect.origin() !=
+                              pending_resize_params_.screen_space_rect.origin();
   bool resize_params_changed = synchronized_params_changed || position_changed;
 
   if (resize_params_changed && attached()) {
     // Let the browser know about the updated view rect.
     BrowserPluginManager::Get()->Send(
-        new BrowserPluginHostMsg_UpdateResizeParams(
-            browser_plugin_instance_id_, frame_rect(), screen_info(),
-            auto_size_sequence_number(), GetLocalSurfaceId()));
+        new BrowserPluginHostMsg_UpdateResizeParams(browser_plugin_instance_id_,
+                                                    GetLocalSurfaceId(),
+                                                    pending_resize_params_));
   }
 
   if (delegate_ && size_changed)
-    delegate_->DidResizeElement(frame_rect().size());
+    delegate_->DidResizeElement(screen_space_rect().size());
 
   if (resize_params_changed && attached())
     sent_resize_params_ = pending_resize_params_;
@@ -314,7 +325,7 @@
 
 void BrowserPlugin::OnGuestGone(int browser_plugin_instance_id) {
   guest_crashed_ = true;
-  compositing_helper_->ChildFrameGone(frame_rect().size(),
+  compositing_helper_->ChildFrameGone(screen_space_rect().size(),
                                       screen_info().device_scale_factor);
 }
 
@@ -328,7 +339,21 @@
 
 void BrowserPlugin::OnResizeDueToAutoResize(int browser_plugin_instance_id,
                                             uint64_t sequence_number) {
-  pending_resize_params_.sequence_number = sequence_number;
+  pending_resize_params_.auto_resize_sequence_number = sequence_number;
+  WasResized();
+}
+
+void BrowserPlugin::OnEnableAutoResize(int browser_plugin_instance_id,
+                                       const gfx::Size& min_size,
+                                       const gfx::Size& max_size) {
+  pending_resize_params_.auto_resize_enabled = true;
+  pending_resize_params_.min_size_for_auto_resize = min_size;
+  pending_resize_params_.max_size_for_auto_resize = max_size;
+  WasResized();
+}
+
+void BrowserPlugin::OnDisableAutoResize(int browser_plugin_instance_id) {
+  pending_resize_params_.auto_resize_enabled = false;
   WasResized();
 }
 
@@ -384,8 +409,9 @@
 gfx::Rect BrowserPlugin::FrameRectInPixels() const {
   const float device_scale_factor = GetDeviceScaleFactor();
   return gfx::Rect(
-      gfx::ScaleToFlooredPoint(frame_rect().origin(), device_scale_factor),
-      gfx::ScaleToCeiledSize(frame_rect().size(), device_scale_factor));
+      gfx::ScaleToFlooredPoint(screen_space_rect().origin(),
+                               device_scale_factor),
+      gfx::ScaleToCeiledSize(screen_space_rect().size(), device_scale_factor));
 }
 
 float BrowserPlugin::GetDeviceScaleFactor() const {
@@ -416,7 +442,7 @@
   pending_resize_params_.screen_info = screen_info;
   if (guest_crashed_) {
     // Update the sad page to match the current ScreenInfo.
-    compositing_helper_->ChildFrameGone(frame_rect().size(),
+    compositing_helper_->ChildFrameGone(screen_space_rect().size(),
                                         screen_info.device_scale_factor);
     return;
   }
@@ -537,7 +563,7 @@
   // If this local root belongs to an OOPIF, on the browser side we will have to
   // consider the displacement of the child frame in root window.
   embedding_render_widget_->ConvertViewportToWindow(&rect_in_css);
-  gfx::Rect frame_rect = rect_in_css;
+  gfx::Rect screen_space_rect = rect_in_css;
 
   if (!ready_) {
     if (delegate_)
@@ -545,10 +571,10 @@
     ready_ = true;
   }
 
-  pending_resize_params_.frame_rect = frame_rect;
+  pending_resize_params_.screen_space_rect = screen_space_rect;
   if (guest_crashed_) {
     // Update the sad page to match the current ScreenInfo.
-    compositing_helper_->ChildFrameGone(frame_rect.size(),
+    compositing_helper_->ChildFrameGone(screen_space_rect.size(),
                                         screen_info().device_scale_factor);
     return;
   }
@@ -783,7 +809,7 @@
     return;
 
   compositing_helper_->SetFallbackSurfaceId(surface_info.id(),
-                                            frame_rect().size());
+                                            screen_space_rect().size());
 }
 
 void BrowserPlugin::OnMusEmbeddedFrameSinkIdAllocated(
diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h
index 65dc203..aeea307e 100644
--- a/content/renderer/browser_plugin/browser_plugin.h
+++ b/content/renderer/browser_plugin/browser_plugin.h
@@ -16,6 +16,7 @@
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/common/surfaces/local_surface_id.h"
 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
+#include "content/common/frame_resize_params.h"
 #include "content/public/common/screen_info.h"
 #include "content/renderer/child_frame_compositor.h"
 #include "content/renderer/mouse_lock_dispatcher.h"
@@ -163,8 +164,8 @@
 
   ~BrowserPlugin() override;
 
-  const gfx::Rect& frame_rect() const {
-    return pending_resize_params_.frame_rect;
+  const gfx::Rect& screen_space_rect() const {
+    return pending_resize_params_.screen_space_rect;
   }
   gfx::Rect FrameRectInPixels() const;
   float GetDeviceScaleFactor() const;
@@ -174,7 +175,7 @@
   }
 
   uint64_t auto_size_sequence_number() const {
-    return pending_resize_params_.sequence_number;
+    return pending_resize_params_.auto_resize_sequence_number;
   }
 
   void UpdateInternalInstanceId();
@@ -193,6 +194,10 @@
   void OnGuestReady(int instance_id, const viz::FrameSinkId& frame_sink_id);
   void OnResizeDueToAutoResize(int browser_plugin_instance_id,
                                uint64_t sequence_number);
+  void OnEnableAutoResize(int browser_plugin_instance_id,
+                          const gfx::Size& min_size,
+                          const gfx::Size& max_size);
+  void OnDisableAutoResize(int browser_plugin_instance_id);
   void OnSetChildFrameSurface(int instance_id,
                               const viz::SurfaceInfo& surface_info);
   void OnSetContentsOpaque(int instance_id, bool opaque);
@@ -252,19 +257,12 @@
 
   bool enable_surface_synchronization_ = false;
 
-  // TODO(fsamuel): We might want to unify this with content::ResizeParams.
-  struct ResizeParams {
-    gfx::Rect frame_rect;
-    ScreenInfo screen_info;
-    uint64_t sequence_number = 0lu;
-  };
-
   // The last ResizeParams sent to the browser process, if any.
-  base::Optional<ResizeParams> sent_resize_params_;
+  base::Optional<FrameResizeParams> sent_resize_params_;
 
   // The current set of ResizeParams. This may or may not match
   // |sent_resize_params_|.
-  ResizeParams pending_resize_params_;
+  FrameResizeParams pending_resize_params_;
 
   // We call lifetime managing methods on |delegate_|, but we do not directly
   // own this. The delegate destroys itself.
diff --git a/content/renderer/indexed_db/webidbcursor_impl.cc b/content/renderer/indexed_db/webidbcursor_impl.cc
index 57ed3b3..e49ad93 100644
--- a/content/renderer/indexed_db/webidbcursor_impl.cc
+++ b/content/renderer/indexed_db/webidbcursor_impl.cc
@@ -28,7 +28,8 @@
 
 class WebIDBCursorImpl::IOThreadHelper {
  public:
-  IOThreadHelper();
+  explicit IOThreadHelper(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
   ~IOThreadHelper();
 
   void Bind(CursorAssociatedPtrInfo cursor_info);
@@ -46,6 +47,7 @@
       std::unique_ptr<IndexedDBCallbacksImpl> callbacks);
 
   indexed_db::mojom::CursorAssociatedPtr cursor_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(IOThreadHelper);
 };
@@ -56,7 +58,7 @@
     scoped_refptr<base::SingleThreadTaskRunner> io_runner,
     scoped_refptr<base::SingleThreadTaskRunner> callback_runner)
     : transaction_id_(transaction_id),
-      helper_(new IOThreadHelper()),
+      helper_(new IOThreadHelper(io_runner)),
       io_runner_(std::move(io_runner)),
       callback_runner_(std::move(callback_runner)),
       continue_count_(0),
@@ -250,13 +252,15 @@
   pending_onsuccess_callbacks_ = 0;
 }
 
-WebIDBCursorImpl::IOThreadHelper::IOThreadHelper() {}
+WebIDBCursorImpl::IOThreadHelper::IOThreadHelper(
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+    : task_runner_(std::move(task_runner)) {}
 
 WebIDBCursorImpl::IOThreadHelper::~IOThreadHelper() {}
 
 void WebIDBCursorImpl::IOThreadHelper::Bind(
     CursorAssociatedPtrInfo cursor_info) {
-  cursor_.Bind(std::move(cursor_info));
+  cursor_.Bind(std::move(cursor_info), task_runner_);
 }
 
 void WebIDBCursorImpl::IOThreadHelper::Advance(
diff --git a/content/renderer/indexed_db/webidbdatabase_impl.cc b/content/renderer/indexed_db/webidbdatabase_impl.cc
index 8766e36..2eefcd4f5 100644
--- a/content/renderer/indexed_db/webidbdatabase_impl.cc
+++ b/content/renderer/indexed_db/webidbdatabase_impl.cc
@@ -64,7 +64,8 @@
 
 class WebIDBDatabaseImpl::IOThreadHelper {
  public:
-  IOThreadHelper();
+  explicit IOThreadHelper(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
   ~IOThreadHelper();
 
   void Bind(DatabaseAssociatedPtrInfo database_info);
@@ -158,6 +159,7 @@
       std::unique_ptr<IndexedDBCallbacksImpl> callbacks);
 
   indexed_db::mojom::DatabaseAssociatedPtr database_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(IOThreadHelper);
 };
@@ -166,7 +168,7 @@
     DatabaseAssociatedPtrInfo database_info,
     scoped_refptr<base::SingleThreadTaskRunner> io_runner,
     scoped_refptr<base::SingleThreadTaskRunner> callback_runner)
-    : helper_(new IOThreadHelper()),
+    : helper_(new IOThreadHelper(io_runner)),
       io_runner_(std::move(io_runner)),
       callback_runner_(std::move(callback_runner)) {
   io_runner_->PostTask(FROM_HERE, base::BindOnce(&IOThreadHelper::Bind,
@@ -525,13 +527,15 @@
                                 base::Unretained(helper_), transaction_id));
 }
 
-WebIDBDatabaseImpl::IOThreadHelper::IOThreadHelper() {}
+WebIDBDatabaseImpl::IOThreadHelper::IOThreadHelper(
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+    : task_runner_(std::move(task_runner)) {}
 
 WebIDBDatabaseImpl::IOThreadHelper::~IOThreadHelper() {}
 
 void WebIDBDatabaseImpl::IOThreadHelper::Bind(
     DatabaseAssociatedPtrInfo database_info) {
-  database_.Bind(std::move(database_info));
+  database_.Bind(std::move(database_info), task_runner_);
 }
 
 void WebIDBDatabaseImpl::IOThreadHelper::CreateObjectStore(
diff --git a/content/renderer/pepper/host_globals.cc b/content/renderer/pepper/host_globals.cc
index 057ef4f..1686143 100644
--- a/content/renderer/pepper/host_globals.cc
+++ b/content/renderer/pepper/host_globals.cc
@@ -11,6 +11,7 @@
 #include "base/rand_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_runner.h"
+#include "base/task_scheduler/post_task.h"
 #include "content/public/common/content_switches.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
 #include "content/renderer/pepper/plugin_module.h"
@@ -190,7 +191,9 @@
 }
 
 base::TaskRunner* HostGlobals::GetFileTaskRunner() {
-  return RenderThreadImpl::current()->GetFileThreadTaskRunner().get();
+  if (!file_task_runner_)
+    file_task_runner_ = base::CreateTaskRunnerWithTraits({base::MayBlock()});
+  return file_task_runner_.get();
 }
 
 ppapi::MessageLoopShared* HostGlobals::GetCurrentMessageLoop() {
diff --git a/content/renderer/pepper/host_globals.h b/content/renderer/pepper/host_globals.h
index 0e554cbe..afd803aa 100644
--- a/content/renderer/pepper/host_globals.h
+++ b/content/renderer/pepper/host_globals.h
@@ -104,6 +104,8 @@
   typedef std::map<PP_Module, PluginModule*> ModuleMap;
   ModuleMap module_map_;
 
+  scoped_refptr<base::TaskRunner> file_task_runner_;
+
   DISALLOW_COPY_AND_ASSIGN(HostGlobals);
 };
 
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 252167b..0329d4c 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -38,6 +38,7 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_runner_util.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
@@ -6318,8 +6319,8 @@
       main_thread_use_time);
 
   if (save_status == MhtmlSaveStatus::SUCCESS && has_some_data) {
-    base::PostTaskAndReplyWithResult(
-        RenderThreadImpl::current()->GetFileThreadTaskRunner().get(), FROM_HERE,
+    base::PostTaskWithTraitsAndReplyWithResult(
+        FROM_HERE, {base::MayBlock()},
         base::Bind(&WriteMHTMLToDisk, base::Passed(&mhtml_contents),
                    base::Passed(&file)),
         base::Bind(&RenderFrameImpl::OnWriteMHTMLToDiskComplete,
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index 57fe79c..1f087812 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -417,6 +417,8 @@
     IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateOrigin, OnDidUpdateOrigin)
     IPC_MESSAGE_HANDLER(InputMsg_SetFocus, OnSetPageFocus)
     IPC_MESSAGE_HANDLER(FrameMsg_ResizeDueToAutoResize, OnResizeDueToAutoResize)
+    IPC_MESSAGE_HANDLER(FrameMsg_EnableAutoResize, OnEnableAutoResize)
+    IPC_MESSAGE_HANDLER(FrameMsg_DisableAutoResize, OnDisableAutoResize)
     IPC_MESSAGE_HANDLER(FrameMsg_SetFocusedFrame, OnSetFocusedFrame)
     IPC_MESSAGE_HANDLER(FrameMsg_WillEnterFullscreen, OnWillEnterFullscreen)
     IPC_MESSAGE_HANDLER(FrameMsg_SetHasReceivedUserGesture,
@@ -562,7 +564,20 @@
 }
 
 void RenderFrameProxy::OnResizeDueToAutoResize(uint64_t sequence_number) {
-  pending_resize_params_.sequence_number = sequence_number;
+  pending_resize_params_.auto_resize_sequence_number = sequence_number;
+  WasResized();
+}
+
+void RenderFrameProxy::OnEnableAutoResize(const gfx::Size& min_size,
+                                          const gfx::Size& max_size) {
+  pending_resize_params_.auto_resize_enabled = true;
+  pending_resize_params_.min_size_for_auto_resize = min_size;
+  pending_resize_params_.max_size_for_auto_resize = max_size;
+  WasResized();
+}
+
+void RenderFrameProxy::OnDisableAutoResize() {
+  pending_resize_params_.auto_resize_enabled = false;
   WasResized();
 }
 
@@ -579,13 +594,19 @@
 
   bool synchronized_params_changed =
       !sent_resize_params_ ||
+      sent_resize_params_->auto_resize_enabled !=
+          pending_resize_params_.auto_resize_enabled ||
+      sent_resize_params_->min_size_for_auto_resize !=
+          pending_resize_params_.min_size_for_auto_resize ||
+      sent_resize_params_->max_size_for_auto_resize !=
+          pending_resize_params_.max_size_for_auto_resize ||
       sent_resize_params_->local_frame_size !=
           pending_resize_params_.local_frame_size ||
       sent_resize_params_->screen_space_rect.size() !=
           pending_resize_params_.screen_space_rect.size() ||
       sent_resize_params_->screen_info != pending_resize_params_.screen_info ||
-      sent_resize_params_->sequence_number !=
-          pending_resize_params_.sequence_number;
+      sent_resize_params_->auto_resize_sequence_number !=
+          pending_resize_params_.auto_resize_sequence_number;
 
   if (synchronized_params_changed)
     local_surface_id_ = parent_local_surface_id_allocator_.GenerateId();
@@ -610,9 +631,8 @@
     return;
 
   // Let the browser know about the updated view rect.
-  Send(new FrameHostMsg_UpdateResizeParams(
-      routing_id_, screen_space_rect(), local_frame_size(), screen_info(),
-      auto_size_sequence_number(), surface_id));
+  Send(new FrameHostMsg_UpdateResizeParams(routing_id_, surface_id,
+                                           pending_resize_params_));
   sent_resize_params_ = pending_resize_params_;
 
   // The visible rect that the OOPIF needs to raster depends partially on
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index 608231ebe..9921c0d 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -10,6 +10,7 @@
 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
 #include "content/common/content_export.h"
 #include "content/common/frame_messages.h"
+#include "content/common/frame_resize_params.h"
 #include "content/public/common/screen_info.h"
 #include "content/renderer/child_frame_compositor.h"
 #include "ipc/ipc_listener.h"
@@ -168,7 +169,7 @@
   }
 
   uint64_t auto_size_sequence_number() const {
-    return pending_resize_params_.sequence_number;
+    return pending_resize_params_.auto_resize_sequence_number;
   }
 
   const viz::FrameSinkId& frame_sink_id() const { return frame_sink_id_; }
@@ -250,6 +251,8 @@
   void OnScrollRectToVisible(const gfx::Rect& rect_to_scroll,
                              const blink::WebScrollIntoViewParams& params);
   void OnResizeDueToAutoResize(uint64_t sequence_number);
+  void OnEnableAutoResize(const gfx::Size& min_size, const gfx::Size& max_size);
+  void OnDisableAutoResize();
   void OnSetHasReceivedUserGestureBeforeNavigation(bool value);
 
 #if defined(USE_AURA)
@@ -287,23 +290,15 @@
   // defined by the browser and passed into Blink upon frame creation.
   base::UnguessableToken devtools_frame_token_;
 
-  // TODO(fsamuel): We might want to unify this with content::ResizeParams.
   // TODO(fsamuel): Most RenderFrameProxys don't host viz::Surfaces and
   // therefore don't care to synchronize ResizeParams with viz::LocalSurfaceIds.
   // Perhaps this can be moved to ChildFrameCompositingHelper?
-  struct ResizeParams {
-    gfx::Rect screen_space_rect;
-    gfx::Size local_frame_size;
-    ScreenInfo screen_info;
-    uint64_t sequence_number = 0lu;
-  };
-
   // The last ResizeParams sent to the browser process, if any.
-  base::Optional<ResizeParams> sent_resize_params_;
+  base::Optional<FrameResizeParams> sent_resize_params_;
 
   // The current set of ResizeParams. This may or may not match
   // |sent_resize_params_|.
-  ResizeParams pending_resize_params_;
+  FrameResizeParams pending_resize_params_;
 
   bool crashed_ = false;
 
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index e15561cc..e19ff8267 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -2464,10 +2464,6 @@
                                 mbytes);
 }
 
-scoped_refptr<base::TaskRunner> RenderThreadImpl::GetFileThreadTaskRunner() {
-  return blink_platform_impl_->BaseFileTaskRunner();
-}
-
 scoped_refptr<base::SingleThreadTaskRunner>
 RenderThreadImpl::GetMediaThreadTaskRunner() {
   DCHECK(message_loop()->task_runner()->BelongsToCurrentThread());
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 3cc4d6c..a4e9196 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -404,11 +404,6 @@
   gpu::GpuChannelHost* GetGpuChannel();
 
   // Returns a SingleThreadTaskRunner instance corresponding to the message loop
-  // of the thread on which file operations should be run. Must be called
-  // on the renderer's main thread.
-  scoped_refptr<base::TaskRunner> GetFileThreadTaskRunner();
-
-  // Returns a SingleThreadTaskRunner instance corresponding to the message loop
   // of the thread on which media operations should be run. Must be called
   // on the renderer's main thread.
   scoped_refptr<base::SingleThreadTaskRunner> GetMediaThreadTaskRunner();
diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc
index dde8edd3..4447726 100644
--- a/content/test/content_browser_test_utils_internal.cc
+++ b/content/test/content_browser_test_utils_internal.cc
@@ -23,6 +23,7 @@
 #include "content/browser/frame_host/render_frame_proxy_host.h"
 #include "content/browser/renderer_host/delegated_frame_host.h"
 #include "content/common/frame_messages.h"
+#include "content/common/frame_resize_params.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
@@ -388,18 +389,17 @@
 UpdateResizeParamsMessageFilter::~UpdateResizeParamsMessageFilter() {}
 
 void UpdateResizeParamsMessageFilter::OnUpdateResizeParams(
-    const gfx::Rect& screen_space_rect,
-    const gfx::Size& local_frame_size,
-    const ScreenInfo& screen_info,
-    uint64_t sequence_number,
-    const viz::SurfaceId& surface_id) {
-  gfx::Rect screen_space_rect_in_dip = screen_space_rect;
+    const viz::SurfaceId& surface_id,
+    const FrameResizeParams& resize_params) {
+  gfx::Rect screen_space_rect_in_dip = resize_params.screen_space_rect;
   if (IsUseZoomForDSFEnabled()) {
-    screen_space_rect_in_dip = gfx::Rect(
-        gfx::ScaleToFlooredPoint(screen_space_rect.origin(),
-                                 1.f / screen_info.device_scale_factor),
-        gfx::ScaleToCeiledSize(screen_space_rect.size(),
-                               1.f / screen_info.device_scale_factor));
+    screen_space_rect_in_dip =
+        gfx::Rect(gfx::ScaleToFlooredPoint(
+                      resize_params.screen_space_rect.origin(),
+                      1.f / resize_params.screen_info.device_scale_factor),
+                  gfx::ScaleToCeiledSize(
+                      resize_params.screen_space_rect.size(),
+                      1.f / resize_params.screen_info.device_scale_factor));
   }
   // Track each rect updates.
   content::BrowserThread::PostTask(
diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h
index 0480e2e..070ae81 100644
--- a/content/test/content_browser_test_utils_internal.h
+++ b/content/test/content_browser_test_utils_internal.h
@@ -35,7 +35,7 @@
 class Shell;
 class SiteInstance;
 class ToRenderFrameHost;
-struct ScreenInfo;
+struct FrameResizeParams;
 
 // Navigates the frame represented by |node| to |url|, blocking until the
 // navigation finishes.
@@ -212,11 +212,8 @@
   ~UpdateResizeParamsMessageFilter() override;
 
  private:
-  void OnUpdateResizeParams(const gfx::Rect& screen_space_rect,
-                            const gfx::Size& local_frame_size,
-                            const ScreenInfo& screen_info,
-                            uint64_t sequence_number,
-                            const viz::SurfaceId& surface_id);
+  void OnUpdateResizeParams(const viz::SurfaceId& surface_id,
+                            const FrameResizeParams& resize_params);
   // |rect| is in DIPs.
   void OnUpdatedFrameRectOnUI(const gfx::Rect& rect);
   void OnUpdatedFrameSinkIdOnUI();
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 614cdf2..b38654c 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -220,9 +220,16 @@
     deps += [ "//dbus" ]
   }
 
-  # BLE discovery: works on Linux.
   if (is_linux) {
+    # BLE discovery: works on Linux.
     sources += [ "fido/fido_ble_discovery_unittest.cc" ]
+
+    if (is_chromecast) {
+      sources += [
+        "bluetooth/cast/bluetooth_adapter_cast_unittest.cc",
+        "bluetooth/cast/bluetooth_utils_unittest.cc",
+      ]
+    }
   }
 
   if (is_mac) {
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn
index 8e253ca..8e5253e0 100644
--- a/device/bluetooth/BUILD.gn
+++ b/device/bluetooth/BUILD.gn
@@ -406,6 +406,12 @@
           "cast/bluetooth_remote_gatt_descriptor_cast.h",
           "cast/bluetooth_remote_gatt_service_cast.cc",
           "cast/bluetooth_remote_gatt_service_cast.h",
+          "cast/bluetooth_utils.cc",
+          "cast/bluetooth_utils.h",
+        ]
+
+        public_deps = [
+          "//chromecast/public",
         ]
 
         deps += [
diff --git a/device/bluetooth/cast/DEPS b/device/bluetooth/cast/DEPS
index 5ee2eca..6aee92f 100644
--- a/device/bluetooth/cast/DEPS
+++ b/device/bluetooth/cast/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
-  "+chromecast/device/bluetooth"
+  "+chromecast/device/bluetooth",
+  "+chromecast/public/bluetooth"
 ]
diff --git a/device/bluetooth/cast/bluetooth_adapter_cast.cc b/device/bluetooth/cast/bluetooth_adapter_cast.cc
index ae47064..2a26b70c 100644
--- a/device/bluetooth/cast/bluetooth_adapter_cast.cc
+++ b/device/bluetooth/cast/bluetooth_adapter_cast.cc
@@ -6,26 +6,26 @@
 
 #include "base/bind.h"
 #include "base/location.h"
+#include "base/no_destructor.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "chromecast/device/bluetooth/bluetooth_util.h"
 #include "chromecast/device/bluetooth/le/gatt_client_manager.h"
 #include "chromecast/device/bluetooth/le/le_scan_manager.h"
+#include "chromecast/device/bluetooth/le/remote_characteristic.h"
 #include "chromecast/device/bluetooth/le/remote_device.h"
+#include "chromecast/device/bluetooth/le/remote_service.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_discovery_session_outcome.h"
 #include "device/bluetooth/cast/bluetooth_device_cast.h"
+#include "device/bluetooth/cast/bluetooth_utils.h"
 
 namespace device {
 namespace {
 
-// The classes in //device/bluetooth expect addresses to be in the canonical
-// format: "AA:BB:CC:DD:EE:FF". Use this utility whenever an address from the
-// Cast stack is converted.
-std::string GetCanonicalAddress(
-    const chromecast::bluetooth_v2_shlib::Addr& addr) {
-  return BluetoothDevice::CanonicalizeAddress(
-      chromecast::bluetooth::util::AddrToString(addr));
+BluetoothAdapterCast::FactoryCb& GetFactory() {
+  static base::NoDestructor<BluetoothAdapterCast::FactoryCb> factory_cb;
+  return *factory_cb;
 }
 
 }  // namespace
@@ -201,13 +201,18 @@
   NOTIMPLEMENTED();
 }
 
+base::WeakPtr<BluetoothAdapterCast> BluetoothAdapterCast::GetWeakPtr() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return weak_factory_.GetWeakPtr();
+}
+
 void BluetoothAdapterCast::OnConnectChanged(
     scoped_refptr<chromecast::bluetooth::RemoteDevice> device,
     bool connected) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  auto address = GetCanonicalAddress(device->addr());
-  VLOG(1) << __func__ << " " << address << " connected: " << connected;
+  std::string address = GetCanonicalBluetoothAddress(device->addr());
+  DVLOG(1) << __func__ << " " << address << " connected: " << connected;
 
   // This method could be called before this device is detected in a scan and
   // GetDevice() is called. Add it if needed.
@@ -223,19 +228,26 @@
     int mtu) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  DVLOG(3) << __func__ << " " << GetCanonicalAddress(device->addr())
+  DVLOG(3) << __func__ << " " << GetCanonicalBluetoothAddress(device->addr())
            << " mtu: " << mtu;
 }
 
 void BluetoothAdapterCast::OnServicesUpdated(
     scoped_refptr<chromecast::bluetooth::RemoteDevice> device,
     std::vector<scoped_refptr<chromecast::bluetooth::RemoteService>> services) {
+  DVLOG(1) << __func__;
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  auto it = devices_.find(GetCanonicalAddress(device->addr()));
-  if (it == devices_.end())
+  std::string address = GetCanonicalBluetoothAddress(device->addr());
+  BluetoothDeviceCast* cast_device = GetCastDevice(address);
+  if (!cast_device)
     return;
-  it->second->SetGattServicesDiscoveryComplete(true);
+
+  if (!cast_device->UpdateServices(services))
+    LOG(WARNING) << "The services were not updated. Alerting anyway.";
+
+  cast_device->SetGattServicesDiscoveryComplete(true);
+  NotifyGattServicesDiscovered(cast_device);
 }
 
 void BluetoothAdapterCast::OnCharacteristicNotification(
@@ -244,20 +256,23 @@
     std::vector<uint8_t> value) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  DVLOG(1) << __func__ << " " << GetCanonicalAddress(device->addr())
-           << " updated.";
+  std::string address = GetCanonicalBluetoothAddress(device->addr());
+  BluetoothDeviceCast* cast_device = GetCastDevice(address);
+  if (!cast_device)
+    return;
 
-  // TODO(slan): Add an Observer interface to RemoteCharacteristc so this can be
-  // wired directly to the BluetoothRemoteGattCharacteristicCast proxy, rather
-  // than by performing a search of the services on device for |characteristc|.
-  NOTIMPLEMENTED();
+  cast_device->UpdateCharacteristicValue(
+      std::move(characteristic), std::move(value),
+      base::BindOnce(
+          &BluetoothAdapterCast::NotifyGattCharacteristicValueChanged,
+          weak_factory_.GetWeakPtr()));
 }
 
 void BluetoothAdapterCast::OnNewScanResult(
     chromecast::bluetooth::LeScanManager::ScanResult result) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  auto address = GetCanonicalAddress(result.addr);
+  std::string address = GetCanonicalBluetoothAddress(result.addr);
 
   // If we haven't created a BluetoothDeviceCast for this address yet, we need
   // to send an async request to |gatt_client_manager_| for a handle to the
@@ -300,7 +315,10 @@
 
 BluetoothDeviceCast* BluetoothAdapterCast::GetCastDevice(
     const std::string& address) {
-  return static_cast<BluetoothDeviceCast*>(devices_[address].get());
+  auto it = devices_.find(address);
+  return it == devices_.end()
+             ? nullptr
+             : static_cast<BluetoothDeviceCast*>(it->second.get());
 }
 
 void BluetoothAdapterCast::AddDevice(
@@ -309,7 +327,7 @@
 
   // This method should not be called if we already have a BluetoothDeviceCast
   // registered for this device.
-  auto address = GetCanonicalAddress(remote_device->addr());
+  std::string address = GetCanonicalBluetoothAddress(remote_device->addr());
   DCHECK(devices_.find(address) == devices_.end());
 
   devices_[address] =
@@ -346,7 +364,7 @@
     scoped_refptr<chromecast::bluetooth::RemoteDevice> remote_device) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  auto address = GetCanonicalAddress(remote_device->addr());
+  std::string address = GetCanonicalBluetoothAddress(remote_device->addr());
 
   // This callback could run before or after the device becomes connected and
   // OnConnectChanged() is called for a particular device. If that happened,
@@ -384,17 +402,23 @@
 }
 
 // static
+void BluetoothAdapterCast::SetFactory(FactoryCb factory_cb) {
+  FactoryCb& factory = GetFactory();
+  DCHECK(!factory);
+  factory = std::move(factory_cb);
+}
+
+// static
+void BluetoothAdapterCast::ResetFactoryForTest() {
+  GetFactory().Reset();
+}
+
+// static
 base::WeakPtr<BluetoothAdapter> BluetoothAdapterCast::Create(
     InitCallback callback) {
-  // TODO(slan): We need to figure out how to get these classes properly.
-  chromecast::bluetooth::GattClientManager* gatt_client_manager = nullptr;
-  chromecast::bluetooth::LeScanManager* le_scan_manager = nullptr;
-
-  // TODO(slan): Consider life-cycle management. Currently this just leaks.
-  auto* adapter =
-      new BluetoothAdapterCast(gatt_client_manager, le_scan_manager);
-  base::WeakPtr<BluetoothAdapterCast> weak_ptr =
-      adapter->weak_factory_.GetWeakPtr();
+  FactoryCb& factory = GetFactory();
+  DCHECK(factory) << "SetFactory() must be called before this method!";
+  base::WeakPtr<BluetoothAdapterCast> weak_ptr = factory.Run();
 
   // BluetoothAdapterFactory assumes that |init_callback| will be called
   // asynchronously the first time, and that IsInitialized() will return false.
diff --git a/device/bluetooth/cast/bluetooth_adapter_cast.h b/device/bluetooth/cast/bluetooth_adapter_cast.h
index 58bc596..a97f4591 100644
--- a/device/bluetooth/cast/bluetooth_adapter_cast.h
+++ b/device/bluetooth/cast/bluetooth_adapter_cast.h
@@ -16,6 +16,7 @@
 #include "chromecast/device/bluetooth/le/gatt_client_manager.h"
 #include "chromecast/device/bluetooth/le/le_scan_manager.h"
 #include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_export.h"
 
 namespace device {
 
@@ -31,10 +32,18 @@
 // This class is created and called on a single thread. It makes aysnchronous
 // calls to the Cast bluetooth stack, which may live on another thread. Unless
 // noted otherwise, callbacks will always be posted on the calling thread.
-class BluetoothAdapterCast : public BluetoothAdapter,
-                             chromecast::bluetooth::GattClientManager::Observer,
-                             chromecast::bluetooth::LeScanManager::Observer {
+class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterCast
+    : public BluetoothAdapter,
+      chromecast::bluetooth::GattClientManager::Observer,
+      chromecast::bluetooth::LeScanManager::Observer {
  public:
+  // Do not call this constructor directly; use CreateAdapter() instead. Neither
+  // |gatt_client_manager| nor |le_scan_manager| are owned by this class. Both
+  // must outlive |this|.
+  BluetoothAdapterCast(
+      chromecast::bluetooth::GattClientManager* gatt_client_manager,
+      chromecast::bluetooth::LeScanManager* le_scan_manager);
+
   // BluetoothAdapter implementation:
   std::string GetAddress() const override;
   std::string GetName() const override;
@@ -93,16 +102,30 @@
   void RemovePairingDelegateInternal(
       BluetoothDevice::PairingDelegate* pairing_delegate) override;
 
-  // Creates a BluetoothAdapterCast. |callback| will be executed asynchronously
+  // Return a WeakPtr for this class. Must be called on the sequence on which
+  // this class was created.
+  // TODO(slan): Remove this once this class talks to a dedicated Bluetooth
+  // service (b/76155468)
+  base::WeakPtr<BluetoothAdapterCast> GetWeakPtr();
+
+  // |factory_cb| is used to inject a factory method from ChromecastService into
+  // this class. It will be invoked when Create() is called.
+  // TODO(slan): Remove this once this class talks to a dedicated Bluetooth
+  // service (b/76155468)
+  using FactoryCb =
+      base::RepeatingCallback<base::WeakPtr<BluetoothAdapterCast>()>;
+  static void SetFactory(FactoryCb factory_cb);
+
+  // Resets the factory callback for test scenarios.
+  static void ResetFactoryForTest();
+
+  // Creates a BluetoothAdapterCast using the |factory_cb| set in SetFactory().
+  // This method is intended to be called only by the WebBluetooth code in
+  // //device/blutooth/. |callback| will be executed asynchronously
   // on the calling sequence.
   static base::WeakPtr<BluetoothAdapter> Create(InitCallback callback);
 
  private:
-  // Neither |gatt_client_manager| nor |le_scan_manager| are owned by this
-  // class. Both must outlive |this|.
-  BluetoothAdapterCast(
-      chromecast::bluetooth::GattClientManager* gatt_client_manager,
-      chromecast::bluetooth::LeScanManager* le_scan_manager);
   ~BluetoothAdapterCast() override;
 
   // chromecast::bluetooth::GattClientManager::Observer implementation:
diff --git a/device/bluetooth/cast/bluetooth_adapter_cast_unittest.cc b/device/bluetooth/cast/bluetooth_adapter_cast_unittest.cc
new file mode 100644
index 0000000..affde95
--- /dev/null
+++ b/device/bluetooth/cast/bluetooth_adapter_cast_unittest.cc
@@ -0,0 +1,59 @@
+// Copyright 2018 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 "device/bluetooth/cast/bluetooth_adapter_cast.h"
+
+#include "base/bind_helpers.h"
+#include "base/test/gtest_util.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+
+class BluetoothAdapterCastTest : public testing::Test {
+ public:
+  BluetoothAdapterCastTest() = default;
+  ~BluetoothAdapterCastTest() override {
+    BluetoothAdapterCast::ResetFactoryForTest();
+  };
+
+ private:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+  DISALLOW_COPY_AND_ASSIGN(BluetoothAdapterCastTest);
+};
+
+TEST_F(BluetoothAdapterCastTest, TestSetFactory) {
+  // Test that the callback set with SetFactory() is called by Create().
+  base::MockCallback<BluetoothAdapterCast::FactoryCb> callback;
+  BluetoothAdapterCast::SetFactory(callback.Get());
+
+  // Call the method once.
+  EXPECT_CALL(callback, Run());
+  BluetoothAdapterCast::Create(base::DoNothing());
+
+  // Call it again.
+  EXPECT_CALL(callback, Run());
+  BluetoothAdapterCast::Create(base::DoNothing());
+}
+
+#if DCHECK_IS_ON()
+TEST_F(BluetoothAdapterCastTest, TestSetFactoryTwiceCrashes) {
+  // Test that calling SetFactory() more than once causes a crash.
+  base::MockCallback<BluetoothAdapterCast::FactoryCb> callback;
+  BluetoothAdapterCast::SetFactory(callback.Get());
+
+  // The factory has already been set. Crash.
+  EXPECT_DCHECK_DEATH(BluetoothAdapterCast::SetFactory(callback.Get()));
+}
+
+TEST_F(BluetoothAdapterCastTest, TestNoSetFactoryCrashes) {
+  // Test that calling BluetoothAdapterCast::Create() without calling
+  // SetFactory() causes a crash.
+  EXPECT_DCHECK_DEATH(BluetoothAdapterCast::Create(base::DoNothing()));
+}
+#endif  // DCHECK_IS_ON()
+
+}  // namespace device
diff --git a/device/bluetooth/cast/bluetooth_device_cast.cc b/device/bluetooth/cast/bluetooth_device_cast.cc
index 30a8f8c..bfcdce30 100644
--- a/device/bluetooth/cast/bluetooth_device_cast.cc
+++ b/device/bluetooth/cast/bluetooth_device_cast.cc
@@ -6,7 +6,11 @@
 
 #include "base/bind.h"
 #include "base/strings/stringprintf.h"
-#include "chromecast/device/bluetooth/bluetooth_util.h"
+#include "chromecast/device/bluetooth/le/remote_characteristic.h"
+#include "chromecast/device/bluetooth/le/remote_service.h"
+#include "device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h"
+#include "device/bluetooth/cast/bluetooth_remote_gatt_service_cast.h"
+#include "device/bluetooth/cast/bluetooth_utils.h"
 
 namespace device {
 namespace {
@@ -52,8 +56,7 @@
     scoped_refptr<chromecast::bluetooth::RemoteDevice> device)
     : BluetoothDevice(adapter),
       remote_device_(std::move(device)),
-      address_(CanonicalizeAddress(
-          chromecast::bluetooth::util::AddrToString(remote_device_->addr()))),
+      address_(GetCanonicalBluetoothAddress(remote_device_->addr())),
       weak_factory_(this) {}
 
 BluetoothDeviceCast::~BluetoothDeviceCast() {}
@@ -257,20 +260,84 @@
 
 bool BluetoothDeviceCast::SetConnected(bool connected) {
   DVLOG(2) << __func__ << " connected: " << connected;
-  bool changed = false;
-  if (!connected_ && connected) {
+  bool was_connected = connected_;
+
+  // Set the new state *before* calling the protected methods below. They may
+  // synchronously query the state of the device.
+  connected_ = connected;
+
+  // Update state in the base class. This will cause pending callbacks to be
+  // fired.
+  if (!was_connected && connected) {
     DidConnectGatt();
-    changed = true;
-  } else if (connected_ && !connected) {
+  } else if (was_connected && !connected) {
     DidDisconnectGatt();
+  }
+
+  // Return true if the value of |connected_| changed.
+  return was_connected != connected;
+}
+
+bool BluetoothDeviceCast::UpdateServices(
+    std::vector<scoped_refptr<chromecast::bluetooth::RemoteService>> services) {
+  DVLOG(2) << __func__;
+  bool changed = false;
+
+  // Create a look-up for the updated list of services.
+  std::unordered_set<std::string> new_service_uuids;
+  for (const auto& service : services)
+    new_service_uuids.insert(GetCanonicalBluetoothUuid(service->uuid()));
+
+  // Remove any services in |gatt_services_| that are not present in |services|.
+  for (auto it = gatt_services_.cbegin(); it != gatt_services_.cend();) {
+    if (new_service_uuids.find(it->first) == new_service_uuids.end()) {
+      gatt_services_.erase(it++);
+      changed = true;
+    } else {
+      ++it;
+    }
+  }
+
+  // Add new services.
+  for (auto& service : services) {
+    auto key = GetCanonicalBluetoothUuid(service->uuid());
+
+    if (gatt_services_.find(key) != gatt_services_.end())
+      continue;
+
+    auto cast_service = std::make_unique<BluetoothRemoteGattServiceCast>(
+        this, std::move(service));
+    DCHECK_EQ(key, cast_service->GetIdentifier());
+    gatt_services_[key] = std::move(cast_service);
     changed = true;
   }
 
-  connected_ = connected;
   return changed;
 }
 
+bool BluetoothDeviceCast::UpdateCharacteristicValue(
+    scoped_refptr<chromecast::bluetooth::RemoteCharacteristic> characteristic,
+    std::vector<uint8_t> value,
+    OnValueUpdatedCallback callback) {
+  auto uuid = UuidToBluetoothUUID(characteristic->uuid());
+  // TODO(slan): Consider using a look-up to find characteristics instead. This
+  // approach could be inefficient if a device has a lot of characteristics.
+  for (const auto& it : gatt_services_) {
+    for (auto* c : it.second->GetCharacteristics()) {
+      if (c->GetUUID() == uuid) {
+        static_cast<BluetoothRemoteGattCharacteristicCast*>(c)->SetValue(value);
+        std::move(callback).Run(c, value);
+        return true;
+      }
+    }
+  }
+  LOG(WARNING) << GetAddress() << " does not have a service with "
+               << " characteristic " << uuid.canonical_value();
+  return false;
+}
+
 void BluetoothDeviceCast::CreateGattConnectionImpl() {
+  DVLOG(2) << __func__ << " " << pending_connect_;
   if (pending_connect_)
     return;
   pending_connect_ = true;
@@ -279,6 +346,7 @@
 }
 
 void BluetoothDeviceCast::DisconnectGatt() {
+  DVLOG(2) << __func__ << " pending:" << pending_disconnect_;
   if (pending_disconnect_)
     return;
   pending_disconnect_ = true;
@@ -287,6 +355,7 @@
 }
 
 void BluetoothDeviceCast::OnConnect(bool success) {
+  DVLOG(2) << __func__ << " success:" << success;
   pending_connect_ = false;
   if (success)
     SetConnected(true);
@@ -295,6 +364,7 @@
 }
 
 void BluetoothDeviceCast::OnDisconnect(bool success) {
+  DVLOG(2) << __func__ << " success:" << success;
   pending_disconnect_ = false;
   if (success)
     SetConnected(false);
diff --git a/device/bluetooth/cast/bluetooth_device_cast.h b/device/bluetooth/cast/bluetooth_device_cast.h
index 5e91a72..2152448 100644
--- a/device/bluetooth/cast/bluetooth_device_cast.h
+++ b/device/bluetooth/cast/bluetooth_device_cast.h
@@ -97,6 +97,26 @@
   // connection state changed as a result.
   bool SetConnected(bool connected);
 
+  // Called by BluetoothAdapterCast when the GATT services for this device are
+  // updated. Updates the services in this devices to reflect |services|.
+  // Returns true if a service was added or removed.
+  bool UpdateServices(
+      std::vector<scoped_refptr<chromecast::bluetooth::RemoteService>>
+          services);
+
+  // Called by BluetoothAdapterCast when the value of a characteristic in one of
+  // this device's services has changed, resulting in a notification to the
+  // device. Locate the characteristc and update the underluing value. If the
+  // value is updated, run |callback| synchronously. Return true if that value
+  // changed.
+  using OnValueUpdatedCallback =
+      base::OnceCallback<void(BluetoothRemoteGattCharacteristic*,
+                              const std::vector<uint8_t>&)>;
+  bool UpdateCharacteristicValue(
+      scoped_refptr<chromecast::bluetooth::RemoteCharacteristic> characteristic,
+      std::vector<uint8_t> value,
+      OnValueUpdatedCallback callback);
+
  private:
   // Implements platform specific operations to initiate a GATT connection.
   // Subclasses must also call DidConnectGatt, DidFailToConnectGatt, or
@@ -129,4 +149,4 @@
 
 }  // namespace device
 
-#endif  // DEVICE_BLUETOOTH_CAST_BLUETOOTH_DEVICE_CAST_H_
+#endif  // DEVICE_BLUETOOTH_CAST_BLUETOOTH_DEVICE_CAST_H_
\ No newline at end of file
diff --git a/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc b/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc
index 96ef0bf7..b0ae0d4 100644
--- a/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc
+++ b/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc
@@ -10,16 +10,67 @@
 #include "base/containers/queue.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "chromecast/device/bluetooth/bluetooth_util.h"
 #include "chromecast/device/bluetooth/le/remote_characteristic.h"
 #include "chromecast/device/bluetooth/le/remote_descriptor.h"
 #include "device/bluetooth/bluetooth_uuid.h"
 #include "device/bluetooth/cast/bluetooth_remote_gatt_descriptor_cast.h"
 #include "device/bluetooth/cast/bluetooth_remote_gatt_service_cast.h"
+#include "device/bluetooth/cast/bluetooth_utils.h"
 
 namespace device {
 namespace {
 
+BluetoothGattCharacteristic::Permissions ConvertPermissions(
+    chromecast::bluetooth_v2_shlib::Gatt::Permissions input) {
+  BluetoothGattCharacteristic::Permissions output =
+      BluetoothGattCharacteristic::PERMISSION_NONE;
+  if (input & chromecast::bluetooth_v2_shlib::Gatt::PERMISSION_READ)
+    output |= BluetoothGattCharacteristic::PERMISSION_READ;
+  if (input & chromecast::bluetooth_v2_shlib::Gatt::PERMISSION_READ_ENCRYPTED)
+    output |= BluetoothGattCharacteristic::PERMISSION_READ_ENCRYPTED;
+  if (input & chromecast::bluetooth_v2_shlib::Gatt::PERMISSION_WRITE)
+    output |= BluetoothGattCharacteristic::PERMISSION_WRITE;
+  if (input & chromecast::bluetooth_v2_shlib::Gatt::PERMISSION_WRITE_ENCRYPTED)
+    output |= BluetoothGattCharacteristic::PERMISSION_WRITE_ENCRYPTED;
+
+  // NOTE(slan): Determine the proper mapping for these.
+  // if (input & chromecast::bluetooth_v2_shlib::PERMISSION_READ_ENCRYPTED_MITM)
+  //   output |= BluetoothGattCharacteristic::PERMISSION_READ_ENCRYPTED_MITM;
+  // if (input &
+  // chromecast::bluetooth_v2_shlib::PERMISSION_WRITE_ENCRYPTED_MITM)
+  //   output |= BluetoothGattCharacteristic::PERMISSION_WRITE_ENCRYPTED_MITM;
+  // if (input & chromecast::bluetooth_v2_shlib::PERMISSION_WRITE_SIGNED)
+  //   output |= BluetoothGattCharacteristic::PERMISSION_WRITE_SIGNED;
+  // if (input & chromecast::bluetooth_v2_shlib::PERMISSION_WRITE_SIGNED_MITM)
+  //   output |= BluetoothGattCharacteristic::PERMISSION_WRITE_SIGNED_MITM;
+
+  return output;
+}
+
+BluetoothGattCharacteristic::Properties ConvertProperties(
+    chromecast::bluetooth_v2_shlib::Gatt::Properties input) {
+  BluetoothGattCharacteristic::Properties output =
+      BluetoothGattCharacteristic::PROPERTY_NONE;
+  if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_BROADCAST)
+    output |= BluetoothGattCharacteristic::PROPERTY_BROADCAST;
+  if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_READ)
+    output |= BluetoothGattCharacteristic::PROPERTY_READ;
+  if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_WRITE_NO_RESPONSE)
+    output |= BluetoothGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE;
+  if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_WRITE)
+    output |= BluetoothGattCharacteristic::PROPERTY_WRITE;
+  if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_NOTIFY)
+    output |= BluetoothGattCharacteristic::PROPERTY_NOTIFY;
+  if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_INDICATE)
+    output |= BluetoothGattCharacteristic::PROPERTY_INDICATE;
+  if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_SIGNED_WRITE)
+    output |= BluetoothGattCharacteristic::PROPERTY_AUTHENTICATED_SIGNED_WRITES;
+  if (input & chromecast::bluetooth_v2_shlib::Gatt::PROPERTY_EXTENDED_PROPS)
+    output |= BluetoothGattCharacteristic::PROPERTY_EXTENDED_PROPERTIES;
+
+  return output;
+}
+
 // Called back when subscribing or unsubscribing to a remote characteristic.
 // If |success| is true, run |callback|. Otherwise run |error_callback|.
 void OnSubscribeOrUnsubscribe(
@@ -52,29 +103,21 @@
     ~BluetoothRemoteGattCharacteristicCast() {}
 
 std::string BluetoothRemoteGattCharacteristicCast::GetIdentifier() const {
-  return chromecast::bluetooth::util::UuidToString(
-      remote_characteristic_->uuid());
+  return GetUUID().canonical_value();
 }
 
 BluetoothUUID BluetoothRemoteGattCharacteristicCast::GetUUID() const {
-  return BluetoothUUID(chromecast::bluetooth::util::UuidToString(
-      remote_characteristic_->uuid()));
+  return UuidToBluetoothUUID(remote_characteristic_->uuid());
 }
 
 BluetoothGattCharacteristic::Properties
 BluetoothRemoteGattCharacteristicCast::GetProperties() const {
-  // TODO(slan): Convert these from
-  // bluetooth_v2_shlib::Characteristic::properties.
-  NOTIMPLEMENTED();
-  return Properties();
+  return ConvertProperties(remote_characteristic_->properties());
 }
 
 BluetoothGattCharacteristic::Permissions
 BluetoothRemoteGattCharacteristicCast::GetPermissions() const {
-  // TODO(slan): Convert these from
-  // bluetooth_v2_shlib::Characteristic::permissions.
-  NOTIMPLEMENTED();
-  return Permissions();
+  return ConvertPermissions(remote_characteristic_->permissions());
 }
 
 const std::vector<uint8_t>& BluetoothRemoteGattCharacteristicCast::GetValue()
@@ -132,9 +175,11 @@
     BluetoothRemoteGattDescriptor* ccc_descriptor,
     const base::Closure& callback,
     const ErrorCallback& error_callback) {
+  DVLOG(2) << __func__ << " " << GetIdentifier();
+
   // |remote_characteristic_| exposes a method which writes the CCCD after
   // subscribing the GATT client to the notification. This is syntactically
-  // nicer and saves us a thread-hop, so we can ignore |ccc_descriptor| for now.
+  // nicer and saves us a thread-hop, so we can ignore |ccc_descriptor|.
   (void)ccc_descriptor;
 
   remote_characteristic_->SetRegisterNotification(
@@ -146,14 +191,14 @@
     BluetoothRemoteGattDescriptor* ccc_descriptor,
     const base::Closure& callback,
     const ErrorCallback& error_callback) {
+  DVLOG(2) << __func__ << " " << GetIdentifier();
+
   // |remote_characteristic_| exposes a method which writes the CCCD after
-  // subscribing the GATT client to the notification. This is syntactically
-  // nicer and saves us a thread-hop, so we can ignore |ccc_descriptor| for now.
+  // unsubscribing the GATT client from the notification. This is syntactically
+  // nicer and saves us a thread-hop, so we can ignore |ccc_descriptor|.
   (void)ccc_descriptor;
 
-  // TODO(slan|bcf): Should we actually be using SetRegisterNotification() here
-  // to unset the CCCD bit on the peripheral? What does the standard say?
-  remote_characteristic_->SetNotification(
+  remote_characteristic_->SetRegisterNotification(
       false,
       base::BindOnce(&OnSubscribeOrUnsubscribe, callback, error_callback));
 }
diff --git a/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h b/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h
index f521770..8c5a2e3 100644
--- a/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h
+++ b/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h
@@ -56,7 +56,7 @@
 
   // Called by BluetoothAdapterCast to set the value when a new notification
   // comes in.
-  void SetValue(const std::vector<uint8_t>& value) { value_ = value; }
+  void SetValue(std::vector<uint8_t> value) { value_ = std::move(value); }
 
  private:
   // BluetoothRemoteGattCharacteristic implementation:
diff --git a/device/bluetooth/cast/bluetooth_remote_gatt_descriptor_cast.cc b/device/bluetooth/cast/bluetooth_remote_gatt_descriptor_cast.cc
index f4505c5..e33002c 100644
--- a/device/bluetooth/cast/bluetooth_remote_gatt_descriptor_cast.cc
+++ b/device/bluetooth/cast/bluetooth_remote_gatt_descriptor_cast.cc
@@ -9,10 +9,10 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "chromecast/device/bluetooth/bluetooth_util.h"
 #include "chromecast/device/bluetooth/le/remote_descriptor.h"
 #include "device/bluetooth/bluetooth_gatt_service.h"
 #include "device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h"
+#include "device/bluetooth/cast/bluetooth_utils.h"
 
 namespace device {
 
@@ -26,12 +26,11 @@
 BluetoothRemoteGattDescriptorCast::~BluetoothRemoteGattDescriptorCast() {}
 
 std::string BluetoothRemoteGattDescriptorCast::GetIdentifier() const {
-  return chromecast::bluetooth::util::UuidToString(remote_descriptor_->uuid());
+  return GetUUID().canonical_value();
 }
 
 BluetoothUUID BluetoothRemoteGattDescriptorCast::GetUUID() const {
-  return BluetoothUUID(
-      chromecast::bluetooth::util::UuidToString(remote_descriptor_->uuid()));
+  return UuidToBluetoothUUID(remote_descriptor_->uuid());
 }
 
 BluetoothGattCharacteristic::Permissions
diff --git a/device/bluetooth/cast/bluetooth_remote_gatt_service_cast.cc b/device/bluetooth/cast/bluetooth_remote_gatt_service_cast.cc
index d36f2b9..96f43d9e 100644
--- a/device/bluetooth/cast/bluetooth_remote_gatt_service_cast.cc
+++ b/device/bluetooth/cast/bluetooth_remote_gatt_service_cast.cc
@@ -8,11 +8,11 @@
 #include <vector>
 
 #include "base/bind.h"
-#include "chromecast/device/bluetooth/bluetooth_util.h"
 #include "chromecast/device/bluetooth/le/remote_characteristic.h"
 #include "chromecast/device/bluetooth/le/remote_service.h"
 #include "device/bluetooth/cast/bluetooth_device_cast.h"
 #include "device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h"
+#include "device/bluetooth/cast/bluetooth_utils.h"
 
 namespace device {
 
@@ -34,12 +34,11 @@
 BluetoothRemoteGattServiceCast::~BluetoothRemoteGattServiceCast() {}
 
 std::string BluetoothRemoteGattServiceCast::GetIdentifier() const {
-  return chromecast::bluetooth::util::UuidToString(remote_service_->uuid());
+  return GetUUID().canonical_value();
 }
 
 BluetoothUUID BluetoothRemoteGattServiceCast::GetUUID() const {
-  return BluetoothUUID(
-      chromecast::bluetooth::util::UuidToString(remote_service_->uuid()));
+  return UuidToBluetoothUUID(remote_service_->uuid());
 }
 
 bool BluetoothRemoteGattServiceCast::IsPrimary() const {
diff --git a/device/bluetooth/cast/bluetooth_utils.cc b/device/bluetooth/cast/bluetooth_utils.cc
new file mode 100644
index 0000000..8ed347a
--- /dev/null
+++ b/device/bluetooth/cast/bluetooth_utils.cc
@@ -0,0 +1,28 @@
+// Copyright 2018 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 "device/bluetooth/cast/bluetooth_utils.h"
+
+#include "chromecast/device/bluetooth/bluetooth_util.h"
+#include "device/bluetooth/bluetooth_device.h"
+
+namespace device {
+
+std::string GetCanonicalBluetoothAddress(
+    const chromecast::bluetooth_v2_shlib::Addr& addr) {
+  return device::BluetoothDevice::CanonicalizeAddress(
+      chromecast::bluetooth::util::AddrToString(addr));
+}
+
+BluetoothUUID UuidToBluetoothUUID(
+    const chromecast::bluetooth_v2_shlib::Uuid& uuid) {
+  return BluetoothUUID(chromecast::bluetooth::util::UuidToString(uuid));
+}
+
+std::string GetCanonicalBluetoothUuid(
+    const chromecast::bluetooth_v2_shlib::Uuid& uuid) {
+  return UuidToBluetoothUUID(uuid).canonical_value();
+}
+
+}  // namespace device
\ No newline at end of file
diff --git a/device/bluetooth/cast/bluetooth_utils.h b/device/bluetooth/cast/bluetooth_utils.h
new file mode 100644
index 0000000..2b49a9b3
--- /dev/null
+++ b/device/bluetooth/cast/bluetooth_utils.h
@@ -0,0 +1,38 @@
+// Copyright 2018 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 DEVICE_BLUETOOTH_CAST_BLUETOOTH_UTILS_H_
+#define DEVICE_BLUETOOTH_CAST_BLUETOOTH_UTILS_H_
+
+#include <string>
+
+#include "chromecast/public/bluetooth/bluetooth_types.h"
+#include "device/bluetooth/bluetooth_export.h"
+#include "device/bluetooth/bluetooth_uuid.h"
+
+// This file contains common utilities for implementing Chromium bluetooth
+// interfaces with the Cast Bluetooth stack.
+namespace device {
+
+// Return |addr| in the canonical format used by Chromium Bluetooth code,
+// which is a 48-bit mac address with strictly uppercase digits (ex.
+// "AA:BB:CC:DD:EE:FF"). Any class implementing a Bluetooth interface which
+// needs to reference an address should use this function to obtain the correct
+// string.
+std::string DEVICE_BLUETOOTH_EXPORT
+GetCanonicalBluetoothAddress(const chromecast::bluetooth_v2_shlib::Addr& addr);
+
+// Convert |uuid| to BluetoothUUID, the type used by Chromium Bluetooth code.
+device::BluetoothUUID DEVICE_BLUETOOTH_EXPORT
+UuidToBluetoothUUID(const chromecast::bluetooth_v2_shlib::Uuid& uuid);
+
+// Return |uuid| in the canonical format used by Chromium Bluetooth code,
+// which is a 128-bit lowercase uuid:
+// This is the same as calling UuidToBluetoothUUID(uuid).canonical_value().
+std::string DEVICE_BLUETOOTH_EXPORT
+GetCanonicalBluetoothUuid(const chromecast::bluetooth_v2_shlib::Uuid& uuid);
+
+}  // namespace device
+
+#endif  // DEVICE_BLUETOOTH_CAST_BLUETOOTH_UTILS_H_
\ No newline at end of file
diff --git a/device/bluetooth/cast/bluetooth_utils_unittest.cc b/device/bluetooth/cast/bluetooth_utils_unittest.cc
new file mode 100644
index 0000000..b40fb621
--- /dev/null
+++ b/device/bluetooth/cast/bluetooth_utils_unittest.cc
@@ -0,0 +1,57 @@
+// Copyright 2018 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 "device/bluetooth/cast/bluetooth_utils.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+
+TEST(BluetoothUtilsTest, TestGetCanonicalBluetoothAddress) {
+  // Test that the correct canonical address is returned for a variety of
+  // addresses.
+  ASSERT_EQ("AA:BB:CC:DD:EE:FF", GetCanonicalBluetoothAddress(
+                                     {{0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa}}));
+  ASSERT_EQ("44:55:66:77:88:99", GetCanonicalBluetoothAddress(
+                                     {{0x99, 0x88, 0x77, 0x66, 0x55, 0x44}}));
+  ASSERT_EQ("00:00:00:00:00:00", GetCanonicalBluetoothAddress(
+                                     {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}));
+}
+
+TEST(BluetoothUtilsTest, TestUuidToBluetoothUUID_128bit) {
+  // Test a 128-bit UUID.
+  BluetoothUUID uuid =
+      UuidToBluetoothUUID({{0x12, 0x3e, 0x45, 0x67, 0xe8, 0x9b, 0x12, 0xd3,
+                            0xa4, 0x56, 0x42, 0x66, 0x55, 0x44, 0x00, 0x00}});
+  ASSERT_TRUE(uuid.IsValid());
+  ASSERT_EQ(BluetoothUUID::kFormat128Bit, uuid.format());
+  ASSERT_EQ("123e4567-e89b-12d3-a456-426655440000", uuid.value());
+  ASSERT_EQ("123e4567-e89b-12d3-a456-426655440000", uuid.canonical_value());
+}
+
+TEST(BluetoothUtilsTest, TestUuidToBluetoothUUID_16bit) {
+  // Test a 16-bit UUID. Note that since chromecast::bluetooth_v2_shlib::Uuid
+  // always has 128 bits, the underlying value of every BluetoothUUID returned
+  // from this function will look like "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx".
+  // For information on how a 16-bit UUID is represented as a 128-bit UUID, see
+  // http://www.argenox.com/a-ble-advertising-primer.
+
+  // Get BluetoothUUID for 0xFE34.
+  BluetoothUUID uuid =
+      UuidToBluetoothUUID({{0x00, 0x00, 0xfe, 0x34, 0x00, 0x00, 0x10, 0x00,
+                            0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}});
+  ASSERT_TRUE(uuid.IsValid());
+  ASSERT_EQ(BluetoothUUID::kFormat128Bit, uuid.format());
+  ASSERT_EQ("0000fe34-0000-1000-8000-00805f9b34fb", uuid.value());
+  ASSERT_EQ("0000fe34-0000-1000-8000-00805f9b34fb", uuid.canonical_value());
+}
+
+TEST(BluetoothUtilsTest, TestGetCanonicalBluetoothUuid) {
+  std::string uuid = GetCanonicalBluetoothUuid(
+      {{0x12, 0x3e, 0x45, 0x67, 0xe8, 0x9b, 0x12, 0xd3, 0xa4, 0x56, 0x42, 0x66,
+        0x55, 0x44, 0x00, 0x00}});
+  ASSERT_EQ("123e4567-e89b-12d3-a456-426655440000", uuid);
+}
+
+}  // namespace device
diff --git a/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc b/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc
index efaebcd..0604c13 100644
--- a/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc
+++ b/extensions/browser/api/declarative_net_request/declarative_net_request_api.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/strings/stringprintf.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/api/declarative_net_request/rules_monitor_service.h"
 #include "extensions/browser/api/declarative_net_request/ruleset_manager.h"
@@ -74,8 +75,12 @@
       break;
   }
 
-  // TODO(crbug.com/811460): Impost a limit on the number of patterns that can
-  // be whitelisted by an extension.
+  if (static_cast<int>(new_set.size()) >
+      api::declarative_net_request::MAX_NUMBER_OF_WHITELISTED_PAGES) {
+    return RespondNow(Error(base::StringPrintf(
+        "The number of whitelisted page patterns can't exceed %d",
+        api::declarative_net_request::MAX_NUMBER_OF_WHITELISTED_PAGES)));
+  }
 
   // Persist |new_set| as part of preferences.
   prefs->SetDNRWhitelistedPages(extension_id(), new_set);
diff --git a/extensions/common/api/declarative_net_request.idl b/extensions/common/api/declarative_net_request.idl
index cea3881..32d0e09c6 100644
--- a/extensions/common/api/declarative_net_request.idl
+++ b/extensions/common/api/declarative_net_request.idl
@@ -117,15 +117,24 @@
     // Adds |page_patterns| to the set of whitelisted pages. Requests from these
     // pages are not intercepted by the extension. These are persisted across
     // browser sessions.
+    // Note: MAX_NUMBER_OF_WHITELISTED_PAGES is the maximum number of
+    // whitelisted page an extension can add. Also, adding page patterns is
+    // atomic. In case of an error, no page pattern is added.
     // |page_patterns| : Array of match patterns which are to be added to the
     // whitelist.
     // |callback|: Called after the |page_patterns| have been added.
+    // chrome.runtime.lastError will be set in case of an error, for example if
+    // an invalid page pattern is specified or the extension exceeded the
+    // maximum page patterns limit.
     static void addWhitelistedPages(DOMString[] page_patterns, optional EmptyCallback callback);
 
     // Removes |page_patterns| from the set of whitelisted pages.
+    // Note: Removing page patterns is atomic. In case of an error, no page
+    // pattern is removed.
     // |page_patterns| : Array of match patterns which are to be removed from
     // the whitelist.
     // |callback|: Called after the |page_patterns| have been removed.
+    // chrome.runtime.lastError will be set in case of an error.
     static void removeWhitelistedPages(DOMString[] page_patterns, optional EmptyCallback callback);
 
     // Returns the current set of whitelisted pages.
@@ -133,4 +142,8 @@
     static void getWhitelistedPages(GetWhitelistedPagesCallback callback);
   };
 
+  interface Properties {
+    // The maximum number of whitelisted pages that an extension can add.
+    [value=100] static long MAX_NUMBER_OF_WHITELISTED_PAGES();
+  };
 };
diff --git a/gpu/OWNERS b/gpu/OWNERS
index e6dc6d87..cb1b32e 100644
--- a/gpu/OWNERS
+++ b/gpu/OWNERS
@@ -1,3 +1,4 @@
+ericrk@chromium.org
 kbr@chromium.org
 piman@chromium.org
 vmiura@chromium.org
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 45e25b8..37cfeeb8 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -283,6 +283,14 @@
 }
 
 builder_mixins {
+  name: "mac-gpu-ci"
+  mixins: "mac"
+  recipe {
+    properties: "mastername:chromium.gpu"
+  }
+}
+
+builder_mixins {
   name: "mac-gpu-fyi-ci"
   mixins: "mac"
   mixins: "gpu-fyi-ci"
@@ -695,6 +703,40 @@
       mixins: "mac-ci"
     }
 
+    builders {
+      name: "GPU Mac Builder"
+      mixins: "mac-gpu-ci"
+    }
+    builders {
+      name: "Mac Release (Intel)"
+      mixins: "mac-gpu-ci"
+      # TODO(tandrii,kbr): this builder doesn't actually run tests locally,
+      # and so can perhaps run on cheaper linux hardware.
+    }
+    builders {
+      name: "Mac Retina Release (AMD)"
+      mixins: "mac-gpu-ci"
+      # TODO(tandrii,kbr): this builder doesn't actually run tests locally,
+      # and so can perhaps run on cheaper linux hardware.
+    }
+
+    builders {
+      name: "GPU Mac Builder (dbg)"
+      mixins: "mac-gpu-ci"
+    }
+    builders {
+      name: "Mac Debug (Intel)"
+      mixins: "mac-gpu-ci"
+      # TODO(tandrii,kbr): this builder doesn't actually run tests locally,
+      # and so can perhaps run on cheaper linux hardware.
+    }
+    builders {
+      name: "Mac Retina Debug (AMD)"
+      mixins: "mac-gpu-ci"
+      # TODO(tandrii,kbr): this builder doesn't actually run tests locally,
+      # and so can perhaps run on cheaper linux hardware.
+    }
+
     # chromium.gpu.fyi
     builders {
       name: "GPU FYI Mac Builder"
diff --git a/infra/config/global/luci-milo-dev.cfg b/infra/config/global/luci-milo-dev.cfg
index ff68595..bc220a4 100644
--- a/infra/config/global/luci-milo-dev.cfg
+++ b/infra/config/global/luci-milo-dev.cfg
@@ -403,7 +403,7 @@
     short_name: "tst"
   }
   builders: {
-    name: "buildbot/luci.chromium.ci/linux-gcc-rel"
+    name: "buildbucket/luci.chromium.ci/linux-gcc-rel"
     category: "chromium.linux|release"
     short_name: "gcc"
   }
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index a9ed5bb..f3b324f 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -413,7 +413,7 @@
     short_name: "tst"
   }
   builders: {
-    name: "buildbot/luci.chromium.ci/linux-gcc-rel"
+    name: "buildbucket/luci.chromium.ci/linux-gcc-rel"
     category: "chromium.linux|release"
     short_name: "gcc"
   }
@@ -938,21 +938,25 @@
   }
   builders: {
     name: "buildbot/chromium.linux/Fuchsia ARM64 Cast Audio"
+    name: "buildbucket/luci.chromium.ci/Fuchsia ARM64 Cast Audio"
     category: "fuchsia|Cast"
     short_name: "a64"
   }
   builders: {
     name: "buildbot/chromium.linux/Fuchsia x64 Cast Audio"
+    name: "buildbucket/luci.chromium.ci/Fuchsia x64 Cast Audio"
     category: "fuchsia|Cast"
     short_name: "x64"
   }
   builders: {
     name: "buildbot/chromium.linux/Fuchsia ARM64"
+    name: "buildbucket/luci.chromium.ci/Fuchsia ARM64"
     category: "fuchsia"
     short_name: "a64"
   }
   builders: {
     name: "buildbot/chromium.linux/Fuchsia x64"
+    name: "buildbucket/luci.chromium.ci/Fuchsia x64"
     category: "fuchsia"
     short_name: "x64"
   }
@@ -1892,6 +1896,72 @@
     category: "tester|10.13"
     short_name: "old"
   }
+
+  builders: {
+    name: "buildbucket/luci.chromium.ci/GPU Mac Builder"
+    category: "gpu|builder"
+    short_name: "new"
+  }
+  builders: {
+    name: "buildbot/chromium.gpu/GPU Mac Builder"
+    category: "gpu|builder"
+    short_name: "old"
+  }
+
+  builders: {
+    name: "buildbucket/luci.chromium.ci/Mac Release (Intel)"
+    category: "gpu|tester|intel"
+    short_name: "new"
+  }
+  builders: {
+    name: "buildbot/chromium.gpu/Mac Release (Intel)"
+    category: "gpu|tester|intel"
+    short_name: "old"
+  }
+
+  builders: {
+    name: "buildbucket/luci.chromium.ci/Mac Retina Release (AMD)"
+    category: "gpu|tester|amd"
+    short_name: "new"
+  }
+  builders: {
+    name: "buildbot/chromium.gpu/Mac Retina Release (AMD)"
+    category: "gpu|tester|amd"
+    short_name: "old"
+  }
+
+  builders: {
+    name: "buildbucket/luci.chromium.ci/GPU Mac Builder (dbg)"
+    category: "debug-gpu|builder"
+    short_name: "new"
+  }
+  builders: {
+    name: "buildbot/chromium.gpu/GPU Mac Builder (dbg)"
+    category: "debug-gpu|builder"
+    short_name: "old"
+  }
+
+  builders: {
+    name: "buildbucket/luci.chromium.ci/Mac Debug (Intel)"
+    category: "debug-gpu|tester|intel"
+    short_name: "new"
+  }
+  builders: {
+    name: "buildbot/chromium.gpu/Mac Debug (Intel)"
+    category: "debug-gpu|tester|intel"
+    short_name: "old"
+  }
+
+  builders: {
+    name: "buildbucket/luci.chromium.ci/Mac Retina Debug (AMD)"
+    category: "debug-gpu|tester|amd"
+    short_name: "new"
+  }
+  builders: {
+    name: "buildbot/chromium.gpu/Mac Retina Debug (AMD)"
+    category: "debug-gpu|tester|amd"
+    short_name: "old"
+  }
 }
 
 # Everything below was generated from buildermap.json.
@@ -2892,26 +2962,32 @@
   }
   builders: {
     name: "buildbot/chromium.gpu/GPU Mac Builder"
+    name: "buildbucket/luci.chromium.ci/GPU Mac Builder"
     category: "Mac"
   }
   builders: {
     name: "buildbot/chromium.gpu/GPU Mac Builder (dbg)"
+    name: "buildbucket/luci.chromium.ci/GPU Mac Builder (dbg)"
     category: "Mac"
   }
   builders: {
     name: "buildbot/chromium.gpu/Mac Debug (Intel)"
+    name: "buildbucket/luci.chromium.ci/Mac Debug (Intel)"
     category: "Mac"
   }
   builders: {
     name: "buildbot/chromium.gpu/Mac Release (Intel)"
+    name: "buildbucket/luci.chromium.ci/Mac Release (Intel)"
     category: "Mac"
   }
   builders: {
     name: "buildbot/chromium.gpu/Mac Retina Debug (AMD)"
+    name: "buildbucket/luci.chromium.ci/Mac Retina Debug (AMD)"
     category: "Mac"
   }
   builders: {
     name: "buildbot/chromium.gpu/Mac Retina Release (AMD)"
+    name: "buildbucket/luci.chromium.ci/Mac Retina Release (AMD)"
     category: "Mac"
   }
   builders: {
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index 992c02c..4d9365d1 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -97,6 +97,8 @@
   triggers: "GPU FYI Mac Builder"
   triggers: "GPU FYI Mac Builder (dbg)"
   triggers: "GPU FYI Mac dEQP Builder"
+  triggers: "GPU Mac Builder"
+  triggers: "GPU Mac Builder (dbg)"
   triggers: "Mac Builder"
   triggers: "Mac Builder (dbg)"
   triggers: "Mac FYI GPU ASAN Release"
@@ -726,6 +728,37 @@
 }
 
 job {
+  id: "GPU Mac Builder"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "GPU Mac Builder"
+  }
+}
+
+job {
+  id: "GPU Mac Builder (dbg)"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "GPU Mac Builder (dbg)"
+  }
+}
+
+job {
+  id: "Mac Debug (Intel)"
+  # Triggered by "GPU Mac Builder (dbg)".
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Mac Release (Intel)"
+  }
+}
+
+job {
   id: "Mac FYI Experimental Release (Intel)"
   # Triggered by "GPU FYI Mac Builder".
   acl_sets: "triggered-by-parent-builders"
@@ -803,6 +836,39 @@
 }
 
 job {
+  id: "Mac Release (Intel)"
+  # Triggered by "GPU Mac Builder".
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Mac Release (Intel)"
+  }
+}
+
+job {
+  id: "Mac Retina Debug (AMD)"
+  # Triggered by "GPU Mac Builder (dbg)".
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Mac Retina Release (AMD)"
+  }
+}
+
+job {
+  id: "Mac Retina Release (AMD)"
+  # Triggered by "GPU Mac Builder".
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Mac Retina Release (AMD)"
+  }
+}
+
+job {
   id: "Optional Mac Release (Intel)"
   # Triggered by "GPU FYI Mac Builder".
   acl_sets: "triggered-by-parent-builders"
diff --git a/ios/chrome/browser/download/download_manager_metric_names.h b/ios/chrome/browser/download/download_manager_metric_names.h
index d342f70b..dfbef65 100644
--- a/ios/chrome/browser/download/download_manager_metric_names.h
+++ b/ios/chrome/browser/download/download_manager_metric_names.h
@@ -5,8 +5,9 @@
 #ifndef IOS_CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_METRIC_NAMES_H_
 #define IOS_CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_METRIC_NAMES_H_
 
-// Values of the UMA Download.IOSDownloadedFileAction histogram. This enum is
-// append only.
+// Values of the UMA Download.IOSDownloadedFileAction histogram. These values
+// are persisted to logs. Entries should not be renumbered and numeric values
+// should never be reused.
 enum class DownloadedFileAction {
   // Downloaded file was uploaded to Google Drive.
   OpenedInDrive = 0,
@@ -16,11 +17,12 @@
   // manager UI) or opened via Extension (Chrome is not notified if the download
   // was open in the extension).
   NoActionOrOpenedViaExtension = 2,
-  Count,
+  Count
 };
 
-// Values of the UMA Download.IOSDownloadFileResult histogram. This action is
-// reported only for started downloads.
+// Values of the UMA Download.IOSDownloadFileResult histogram. This histogram is
+// reported only for started downloads. These values are persisted to logs.
+// Entries should not be renumbered and numeric values should never be reused.
 enum class DownloadFileResult {
   // Download has successfully completed.
   Completed = 0,
@@ -36,4 +38,28 @@
   Count
 };
 
+// Values of Download.IOSDownloadFileInBackground histogram. This histogram can
+// help to understand the value of background downloads. These values are
+// persisted to logs. Entries should not be renumbered and numeric values should
+// never be reused.
+enum class DownloadFileInBackground {
+  // The download failed. This task was running when the app was active.
+  FailedWithoutBackgrounding = 0,
+  // The download failed. This task was fully or partially running when the app
+  // was not active.
+  FailedWithBackgrounding = 1,
+  // The download successfully completed. This task was running when the app was
+  // active.
+  SucceededWithoutBackgrounding = 2,
+  // The download successfully completed. This task was fully or partially
+  // running when the app was not active.
+  SucceededWithBackgrounding = 3,
+  // The download was cancelled, because the app was quit by the user. Some of
+  // these downloads can be salvaged by supporting
+  // application:handleEventsForBackgroundURLSession:completionHandler:
+  // AppDelegate callback.
+  CanceledAfterAppQuit = 4,
+  Count
+};
+
 #endif  // IOS_CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_METRIC_NAMES_H_
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 86873cc0..20fa7f3 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -1021,11 +1021,6 @@
     _snackbarCoordinator.dispatcher = _dispatcher;
     [_snackbarCoordinator start];
 
-    _downloadManagerCoordinator =
-        [[DownloadManagerCoordinator alloc] initWithBaseViewController:self];
-    _downloadManagerCoordinator.presenter =
-        [[VerticalAnimationContainer alloc] init];
-
     _storeKitCoordinator =
         [[StoreKitCoordinator alloc] initWithBaseViewController:self];
 
@@ -1560,6 +1555,8 @@
   self.primaryToolbarCoordinator = nil;
   [self.secondaryToolbarCoordinator stop];
   self.secondaryToolbarCoordinator = nil;
+  [_downloadManagerCoordinator stop];
+  _downloadManagerCoordinator = nil;
   self.toolbarInterface = nil;
   self.tabStripView = nil;
   _infoBarContainer = nil;
@@ -2237,6 +2234,12 @@
       [self.primaryToolbarCoordinator QRScannerResultLoader];
   _qrScannerCoordinator.presentationProvider = self;
 
+  _downloadManagerCoordinator =
+      [[DownloadManagerCoordinator alloc] initWithBaseViewController:self];
+  _downloadManagerCoordinator.webStateList = [_model webStateList];
+  _downloadManagerCoordinator.presenter =
+      [[VerticalAnimationContainer alloc] init];
+
   if (IsUIRefreshPhase1Enabled()) {
     self.popupMenuCoordinator = [[PopupMenuCoordinator alloc]
         initWithBaseViewController:self
diff --git a/ios/chrome/browser/ui/download/BUILD.gn b/ios/chrome/browser/ui/download/BUILD.gn
index e118268..18fb307 100644
--- a/ios/chrome/browser/ui/download/BUILD.gn
+++ b/ios/chrome/browser/ui/download/BUILD.gn
@@ -49,6 +49,7 @@
     "//ios/chrome/browser/ui/presenters",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/web:web_internal",
+    "//ios/chrome/browser/web_state_list:web_state_list",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/images",
     "//ios/third_party/material_components_ios",
@@ -83,6 +84,8 @@
     "//ios/chrome/browser/store_kit",
     "//ios/chrome/browser/ui:ui_util",
     "//ios/chrome/browser/web:test_support",
+    "//ios/chrome/browser/web_state_list:test_support",
+    "//ios/chrome/browser/web_state_list:web_state_list",
     "//ios/chrome/test:test_support",
     "//ios/chrome/test/app:test_support",
     "//ios/chrome/test/fakes",
diff --git a/ios/chrome/browser/ui/download/download_manager_coordinator.h b/ios/chrome/browser/ui/download/download_manager_coordinator.h
index a6ec494..d48fe11 100644
--- a/ios/chrome/browser/ui/download/download_manager_coordinator.h
+++ b/ios/chrome/browser/ui/download/download_manager_coordinator.h
@@ -11,6 +11,7 @@
 namespace web {
 class DownloadTask;
 }  // namespace web
+class WebStateList;
 
 @protocol ContainedPresenter;
 
@@ -28,6 +29,9 @@
 // stop method is called.
 @property(nonatomic) web::DownloadTask* downloadTask;
 
+// Needed to observe web state closing. Set to null when stop method is called.
+@property(nonatomic) WebStateList* webStateList;
+
 // Underlying UIViewController presented by this coordinator.
 @property(nonatomic, readonly) UIViewController* viewController;
 
diff --git a/ios/chrome/browser/ui/download/download_manager_coordinator.mm b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
index e570f9e5..7e12570 100644
--- a/ios/chrome/browser/ui/download/download_manager_coordinator.mm
+++ b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
@@ -23,6 +23,8 @@
 #import "ios/chrome/browser/ui/download/download_manager_view_controller.h"
 #import "ios/chrome/browser/ui/presenters/contained_presenter.h"
 #import "ios/chrome/browser/ui/presenters/contained_presenter_delegate.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
+#import "ios/chrome/browser/web_state_list/web_state_list_observer.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/web/public/download/download_task.h"
 #include "net/base/net_errors.h"
@@ -36,7 +38,8 @@
 namespace {
 // Tracks download tasks which were not opened by the user yet. Reports various
 // metrics in DownloadTaskObserver callbacks.
-class UnopenedDownloadsTracker : public web::DownloadTaskObserver {
+class UnopenedDownloadsTracker : public web::DownloadTaskObserver,
+                                 public WebStateListObserver {
  public:
   // Starts tracking this download task.
   void Add(web::DownloadTask* task) { task->AddObserver(this); }
@@ -54,6 +57,19 @@
         base::UmaHistogramSparse("Download.IOSDownloadedFileNetError",
                                  -task->GetErrorCode());
       }
+
+      bool backgrounded = task->HasPerformedBackgroundDownload();
+      DownloadFileInBackground histogram_value =
+          task->GetErrorCode()
+              ? (backgrounded
+                     ? DownloadFileInBackground::FailedWithBackgrounding
+                     : DownloadFileInBackground::FailedWithoutBackgrounding)
+              : (backgrounded
+                     ? DownloadFileInBackground::SucceededWithBackgrounding
+                     : DownloadFileInBackground::SucceededWithoutBackgrounding);
+      UMA_HISTOGRAM_ENUMERATION("Download.IOSDownloadFileInBackground",
+                                histogram_value,
+                                DownloadFileInBackground::Count);
     }
   }
   void OnDownloadDestroyed(web::DownloadTask* task) override {
@@ -64,6 +80,15 @@
       UMA_HISTOGRAM_ENUMERATION("Download.IOSDownloadFileResult",
                                 DownloadFileResult::Other,
                                 DownloadFileResult::Count);
+
+      if (did_close_web_state_without_user_action) {
+        // web state can be closed without user action only during the app
+        // shutdown.
+        UMA_HISTOGRAM_ENUMERATION(
+            "Download.IOSDownloadFileInBackground",
+            DownloadFileInBackground::CanceledAfterAppQuit,
+            DownloadFileInBackground::Count);
+      }
     }
 
     if (task->IsDone() && task->GetErrorCode() == net::OK) {
@@ -73,6 +98,19 @@
           DownloadedFileAction::Count);
     }
   }
+  // WebStateListObserver overrides:
+  void WillCloseWebStateAt(WebStateList* web_state_list,
+                           web::WebState* web_state,
+                           int index,
+                           bool user_action) override {
+    if (!user_action) {
+      did_close_web_state_without_user_action = true;
+    }
+  }
+
+ private:
+  // True if a web state was closed without user action.
+  bool did_close_web_state_without_user_action = false;
 };
 }  // namespace
 
@@ -101,6 +139,7 @@
 @synthesize presenter = _presenter;
 @synthesize animatesPresentation = _animatesPresentation;
 @synthesize downloadTask = _downloadTask;
+@synthesize webStateList = _webStateList;
 
 - (void)dealloc {
   [[InstallationNotifier sharedInstance] unregisterForNotifications:self];
@@ -134,6 +173,7 @@
                                           completion:nil];
   _confirmationDialog = nil;
   _downloadTask = nullptr;
+  self.webStateList = nullptr;
 
   [_storeKitCoordinator stop];
   _storeKitCoordinator = nil;
@@ -141,6 +181,19 @@
   _installDriveAlertCoordinator = nil;
 }
 
+- (void)setWebStateList:(WebStateList*)webStateList {
+  if (_webStateList == webStateList)
+    return;
+
+  if (_webStateList)
+    _webStateList->RemoveObserver(&_unopenedDownloads);
+
+  _webStateList = webStateList;
+
+  if (_webStateList)
+    _webStateList->AddObserver(&_unopenedDownloads);
+}
+
 - (UIViewController*)viewController {
   return _viewController;
 }
diff --git a/ios/chrome/browser/ui/download/download_manager_coordinator_unittest.mm b/ios/chrome/browser/ui/download/download_manager_coordinator_unittest.mm
index cb66b2a..251db17 100644
--- a/ios/chrome/browser/ui/download/download_manager_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/download/download_manager_coordinator_unittest.mm
@@ -18,6 +18,9 @@
 #import "ios/chrome/browser/download/download_manager_tab_helper.h"
 #import "ios/chrome/browser/download/google_drive_app_util.h"
 #import "ios/chrome/browser/ui/download/download_manager_view_controller.h"
+#import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
+#import "ios/chrome/browser/web_state_list/web_state_opener.h"
 #import "ios/chrome/test/fakes/fake_contained_presenter.h"
 #import "ios/chrome/test/fakes/fake_document_interaction_controller.h"
 #import "ios/chrome/test/scoped_key_window.h"
@@ -406,7 +409,7 @@
   ASSERT_EQ(view, document_interaction_controller.presentedOpenInMenu.view);
   ASSERT_TRUE(document_interaction_controller.presentedOpenInMenu.animated);
 
-  // Complete the download to log Download.IOSDownloadFileResult.
+  // Complete the download to log UMA.
   task->SetDone(true);
 
   // Download task is destroyed without opening the file.
@@ -421,6 +424,11 @@
       static_cast<base::HistogramBase::Sample>(
           DownloadedFileAction::NoActionOrOpenedViaExtension),
       1);
+  histogram_tester_.ExpectUniqueSample(
+      "Download.IOSDownloadedFileAction",
+      static_cast<base::HistogramBase::Sample>(
+          DownloadFileInBackground::SucceededWithoutBackgrounding),
+      1);
 }
 
 // Tests destroying download task for in progress download.
@@ -452,11 +460,61 @@
   task = nullptr;
   histogram_tester_.ExpectTotalCount("Download.IOSDownloadedFileNetError", 0);
   histogram_tester_.ExpectTotalCount("Download.IOSDownloadedFileAction", 0);
+  histogram_tester_.ExpectTotalCount("Download.IOSDownloadFileInBackground", 0);
   histogram_tester_.ExpectUniqueSample(
       "Download.IOSDownloadFileResult",
       static_cast<base::HistogramBase::Sample>(DownloadFileResult::Other), 1);
 }
 
+// Tests quitting the app during in-progress download.
+TEST_F(DownloadManagerCoordinatorTest, QuitDuringInProgressDownload) {
+  auto task = CreateTestTask();
+  coordinator_.downloadTask = task.get();
+  web::DownloadTask* task_ptr = task.get();
+  FakeWebStateListDelegate web_state_list_delegate;
+  WebStateList web_state_list(&web_state_list_delegate);
+  auto web_state = std::make_unique<web::TestWebState>();
+  web_state_list.InsertWebState(
+      0, std::move(web_state), WebStateList::INSERT_NO_FLAGS, WebStateOpener());
+  coordinator_.webStateList = &web_state_list;
+  [coordinator_ start];
+
+  EXPECT_EQ(1U, base_view_controller_.childViewControllers.count);
+  DownloadManagerViewController* viewController =
+      base_view_controller_.childViewControllers.firstObject;
+  ASSERT_EQ([DownloadManagerViewController class], [viewController class]);
+
+  // Start and the download.
+  @autoreleasepool {
+    // This call will retain coordinator, which should outlive thread bundle.
+    [viewController.delegate
+        downloadManagerViewControllerDidStartDownload:viewController];
+  }
+
+  // Starting download is async for model.
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForDownloadTimeout, ^{
+    base::RunLoop().RunUntilIdle();
+    return task_ptr->GetState() == web::DownloadTask::State::kInProgress;
+  }));
+
+  // Web States are closed without user action only during app termination.
+  web_state_list.CloseAllWebStates(WebStateList::CLOSE_NO_FLAGS);
+
+  // Download task is destroyed before the download is complete.
+  task = nullptr;
+  histogram_tester_.ExpectTotalCount("Download.IOSDownloadedFileNetError", 0);
+  histogram_tester_.ExpectTotalCount("Download.IOSDownloadedFileAction", 0);
+  histogram_tester_.ExpectUniqueSample(
+      "Download.IOSDownloadFileInBackground",
+      static_cast<base::HistogramBase::Sample>(
+          DownloadFileInBackground::CanceledAfterAppQuit),
+      1);
+  histogram_tester_.ExpectUniqueSample(
+      "Download.IOSDownloadFileResult",
+      static_cast<base::HistogramBase::Sample>(DownloadFileResult::Other), 1);
+  coordinator_.webStateList = nullptr;
+}
+
 // Tests opening the download in Google Drive app.
 TEST_F(DownloadManagerCoordinatorTest, OpenInDrive) {
   web::FakeDownloadTask task(GURL(kTestUrl), kTestMimeType);
@@ -716,6 +774,7 @@
   ASSERT_TRUE(GetDownloadsDirectory(&download_dir));
   EXPECT_TRUE(download_dir.IsParent(file));
 
+  histogram_tester_.ExpectTotalCount("Download.IOSDownloadFileInBackground", 0);
   ASSERT_EQ(0,
             user_action_tester_.GetActionCount("MobileDownloadRetryDownload"));
 }
@@ -758,10 +817,74 @@
   histogram_tester_.ExpectUniqueSample(
       "Download.IOSDownloadFileResult",
       static_cast<base::HistogramBase::Sample>(DownloadFileResult::Failure), 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Download.IOSDownloadFileInBackground",
+      static_cast<base::HistogramBase::Sample>(
+          DownloadFileInBackground::FailedWithoutBackgrounding),
+      1);
   ASSERT_EQ(1,
             user_action_tester_.GetActionCount("MobileDownloadRetryDownload"));
 }
 
+// Tests download failure in background.
+TEST_F(DownloadManagerCoordinatorTest, FailingInBackground) {
+  web::FakeDownloadTask task(GURL(kTestUrl), kTestMimeType);
+  task.SetSuggestedFilename(base::SysNSStringToUTF16(kTestSuggestedFileName));
+  coordinator_.downloadTask = &task;
+  [coordinator_ start];
+
+  // Start and immediately fail the download.
+  DownloadManagerViewController* viewController =
+      base_view_controller_.childViewControllers.firstObject;
+  ASSERT_EQ([DownloadManagerViewController class], [viewController class]);
+  @autoreleasepool {
+    // This call will retain coordinator, which should outlive thread bundle.
+    [viewController.delegate
+        downloadManagerViewControllerDidStartDownload:viewController];
+  }
+  task.SetPerformedBackgroundDownload(true);
+  task.SetErrorCode(net::ERR_INTERNET_DISCONNECTED);
+  task.SetDone(true);
+
+  histogram_tester_.ExpectUniqueSample(
+      "Download.IOSDownloadFileResult",
+      static_cast<base::HistogramBase::Sample>(DownloadFileResult::Failure), 1);
+  histogram_tester_.ExpectUniqueSample(
+      "Download.IOSDownloadFileInBackground",
+      static_cast<base::HistogramBase::Sample>(
+          DownloadFileInBackground::FailedWithBackgrounding),
+      1);
+}
+
+// Tests successful download in background.
+TEST_F(DownloadManagerCoordinatorTest, SucceedingInBackground) {
+  web::FakeDownloadTask task(GURL(kTestUrl), kTestMimeType);
+  task.SetSuggestedFilename(base::SysNSStringToUTF16(kTestSuggestedFileName));
+  coordinator_.downloadTask = &task;
+  [coordinator_ start];
+
+  EXPECT_EQ(1U, base_view_controller_.childViewControllers.count);
+  DownloadManagerViewController* viewController =
+      base_view_controller_.childViewControllers.firstObject;
+  ASSERT_EQ([DownloadManagerViewController class], [viewController class]);
+
+  // Start the download.
+  @autoreleasepool {
+    // This call will retain coordinator, which should outlive thread bundle.
+    [viewController.delegate
+        downloadManagerViewControllerDidStartDownload:viewController];
+  }
+
+  // Complete the download to log UMA.
+  task.SetPerformedBackgroundDownload(true);
+  task.SetDone(true);
+  histogram_tester_.ExpectUniqueSample(
+      "Download.IOSDownloadFileInBackground",
+      static_cast<base::HistogramBase::Sample>(
+          DownloadFileInBackground::SucceededWithBackgrounding),
+      1);
+}
+
 // Tests that viewController returns correct view controller if coordinator is
 // started and nil when stopped.
 TEST_F(DownloadManagerCoordinatorTest, ViewController) {
diff --git a/ios/chrome/browser/ui/history/BUILD.gn b/ios/chrome/browser/ui/history/BUILD.gn
index 21632a2..0d57d9e7 100644
--- a/ios/chrome/browser/ui/history/BUILD.gn
+++ b/ios/chrome/browser/ui/history/BUILD.gn
@@ -91,6 +91,7 @@
 source_set("history_ui") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
+    "history_consumer.h",
     "history_entries_status_item.h",
     "history_entries_status_item.mm",
     "history_entries_status_item_delegate.h",
@@ -140,6 +141,7 @@
     ":resources_unit_tests",
     "//base",
     "//base/test:test_support",
+    "//components/browser_sync",
     "//components/favicon/core",
     "//components/favicon/core/test:test_support",
     "//components/favicon_base",
diff --git a/ios/chrome/browser/ui/history/history_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/history/history_collection_view_controller_unittest.mm
index 63de7cd8..e9117b1 100644
--- a/ios/chrome/browser/ui/history/history_collection_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/history/history_collection_view_controller_unittest.mm
@@ -10,8 +10,11 @@
 #include "base/strings/string16.h"
 #import "base/test/ios/wait_util.h"
 #include "base/time/time.h"
+#include "components/browser_sync/profile_sync_service.h"
 #include "components/history/core/browser/browsing_history_service.h"
+#include "components/keyed_service/core/service_access_type.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#include "ios/chrome/browser/history/history_service_factory.h"
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
 #include "ios/chrome/browser/signin/authentication_service_fake.h"
 #include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
@@ -20,6 +23,7 @@
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
 #include "ios/chrome/browser/sync/sync_setup_service_mock.h"
 #import "ios/chrome/browser/ui/history/ios_browsing_history_driver.h"
+#include "ios/chrome/browser/ui/history/ios_browsing_history_driver.h"
 #import "ios/chrome/browser/ui/url_loader.h"
 #include "ios/chrome/test/block_cleanup_test.h"
 #include "ios/web/public/test/test_web_thread.h"
@@ -65,8 +69,7 @@
 
 }  // namespace
 
-@interface LegacyHistoryCollectionViewController (
-    Testing)<BrowsingHistoryDriverDelegate>
+@interface LegacyHistoryCollectionViewController (Testing)<HistoryConsumer>
 - (void)didPressClearBrowsingBar;
 @end
 
@@ -96,6 +99,19 @@
             initWithLoader:mock_url_loader_
               browserState:mock_browser_state_.get()
                   delegate:mock_delegate_];
+
+    _browsingHistoryDriver = std::make_unique<IOSBrowsingHistoryDriver>(
+        mock_browser_state_.get(), history_collection_view_controller_);
+
+    _browsingHistoryService = std::make_unique<history::BrowsingHistoryService>(
+        _browsingHistoryDriver.get(),
+        ios::HistoryServiceFactory::GetForBrowserState(
+            mock_browser_state_.get(), ServiceAccessType::EXPLICIT_ACCESS),
+        IOSChromeProfileSyncServiceFactory::GetForBrowserState(
+            mock_browser_state_.get()));
+
+    history_collection_view_controller_.historyService =
+        _browsingHistoryService.get();
   }
 
   void TearDown() override {
@@ -109,9 +125,9 @@
     BrowsingHistoryService::QueryResultsInfo query_results_info;
     query_results_info.reached_beginning = true;
     [history_collection_view_controller_
-        onQueryCompleteWithResults:results
-                  queryResultsInfo:query_results_info
-               continuationClosure:base::OnceClosure()];
+        historyQueryWasCompletedWithResults:results
+                           queryResultsInfo:query_results_info
+                        continuationClosure:base::OnceClosure()];
   }
 
  protected:
@@ -123,6 +139,8 @@
   bool privacy_settings_opened_;
   SyncSetupServiceMock* sync_setup_service_mock_;
   DISALLOW_COPY_AND_ASSIGN(LegacyHistoryCollectionViewControllerTest);
+  std::unique_ptr<IOSBrowsingHistoryDriver> _browsingHistoryDriver;
+  std::unique_ptr<history::BrowsingHistoryService> _browsingHistoryService;
 };
 
 // Tests that isEmpty property returns NO after entries have been received.
diff --git a/ios/chrome/browser/ui/history/history_consumer.h b/ios/chrome/browser/ui/history/history_consumer.h
new file mode 100644
index 0000000..e65d563f
--- /dev/null
+++ b/ios/chrome/browser/ui/history/history_consumer.h
@@ -0,0 +1,33 @@
+// Copyright 2018 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_CHROME_BROWSER_UI_HISTORY_HISTORY_CONSUMER_H_
+#define IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_CONSUMER_H_
+
+#include <vector>
+
+#include "components/history/core/browser/browsing_history_service.h"
+
+// Defines methods to manage history query results and deletion actions.
+@protocol HistoryConsumer
+
+// Tells the consumer that the result of a history query has been retrieved.
+// Entries in |result| are already sorted.
+- (void)
+historyQueryWasCompletedWithResults:
+    (const std::vector<history::BrowsingHistoryService::HistoryEntry>&)results
+                   queryResultsInfo:(const history::BrowsingHistoryService::
+                                         QueryResultsInfo&)queryResultsInfo
+                continuationClosure:(base::OnceClosure)continuationClosure;
+
+// Tells the consumer that history entries have been deleted by a different
+// client.
+- (void)historyWasDeleted;
+
+// Tells the consumer whether to show notice about other forms of
+// browsing history or not.
+- (void)showNoticeAboutOtherFormsOfBrowsingHistory:(BOOL)shouldShowNotice;
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/history/history_coordinator.mm b/ios/chrome/browser/ui/history/history_coordinator.mm
index 26fc067..2ffb493 100644
--- a/ios/chrome/browser/ui/history/history_coordinator.mm
+++ b/ios/chrome/browser/ui/history/history_coordinator.mm
@@ -4,9 +4,17 @@
 
 #include "ios/chrome/browser/ui/history/history_coordinator.h"
 
+#include <memory>
+
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/history/core/browser/browsing_history_service.h"
+#include "components/keyed_service/core/service_access_type.h"
 #include "components/strings/grit/components_strings.h"
+#include "ios/chrome/browser/history/history_service_factory.h"
+#include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
 #import "ios/chrome/browser/ui/history/history_table_container_view_controller.h"
 #include "ios/chrome/browser/ui/history/history_table_view_controller.h"
+#include "ios/chrome/browser/ui/history/ios_browsing_history_driver.h"
 #import "ios/chrome/browser/ui/util/form_sheet_navigation_controller.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -14,7 +22,12 @@
 #error "This file requires ARC support."
 #endif
 
-@interface HistoryCoordinator ()
+@interface HistoryCoordinator () {
+  // Provides dependencies and funnels callbacks from BrowsingHistoryService.
+  std::unique_ptr<IOSBrowsingHistoryDriver> _browsingHistoryDriver;
+  // Abstraction to communicate with HistoryService and WebHistoryService.
+  std::unique_ptr<history::BrowsingHistoryService> _browsingHistoryService;
+}
 // ViewController being managed by this Coordinator.
 @property(nonatomic, strong)
     HistoryTableContainerViewController* historyContainerViewController;
@@ -32,6 +45,17 @@
   historyTableViewController.browserState = self.browserState;
   historyTableViewController.loader = self.loader;
 
+  // Initialize and configure HistoryServices.
+  _browsingHistoryDriver = std::make_unique<IOSBrowsingHistoryDriver>(
+      self.browserState, historyTableViewController);
+  _browsingHistoryService = std::make_unique<history::BrowsingHistoryService>(
+      _browsingHistoryDriver.get(),
+      ios::HistoryServiceFactory::GetForBrowserState(
+          self.browserState, ServiceAccessType::EXPLICIT_ACCESS),
+      IOSChromeProfileSyncServiceFactory::GetForBrowserState(
+          self.browserState));
+  historyTableViewController.historyService = _browsingHistoryService.get();
+
   // Initialize and configure HistoryContainerViewController.
   self.historyContainerViewController =
       [[HistoryTableContainerViewController alloc]
diff --git a/ios/chrome/browser/ui/history/history_panel_view_controller.mm b/ios/chrome/browser/ui/history/history_panel_view_controller.mm
index 29b19bf7..0a3c30c 100644
--- a/ios/chrome/browser/ui/history/history_panel_view_controller.mm
+++ b/ios/chrome/browser/ui/history/history_panel_view_controller.mm
@@ -4,14 +4,22 @@
 
 #import "ios/chrome/browser/ui/history/history_panel_view_controller.h"
 
+#include <memory>
+
 #include "base/ios/block_types.h"
 #include "base/ios/ios_util.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/history/core/browser/browsing_history_service.h"
+#include "components/keyed_service/core/service_access_type.h"
 #include "components/strings/grit/components_strings.h"
+#include "ios/chrome/browser/history/history_service_factory.h"
+#include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/history/clear_browsing_bar.h"
 #import "ios/chrome/browser/ui/history/history_search_view_controller.h"
+#include "ios/chrome/browser/ui/history/ios_browsing_history_driver.h"
 #import "ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h"
 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
 #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
@@ -57,6 +65,10 @@
   UIBarButtonItem* _rightBarButtonItem;
   // YES if NSLayoutConstraits were added.
   BOOL _addedConstraints;
+  // Provides dependencies and funnels callbacks from BrowsingHistoryService.
+  std::unique_ptr<IOSBrowsingHistoryDriver> _browsingHistoryDriver;
+  // Abstraction to communicate with HistoryService and WebHistoryService.
+  std::unique_ptr<history::BrowsingHistoryService> _browsingHistoryService;
 }
 // Closes history.
 - (void)closeHistory;
@@ -99,6 +111,18 @@
             initWithLoader:loader
               browserState:browserState
                   delegate:self];
+
+    _browsingHistoryDriver = std::make_unique<IOSBrowsingHistoryDriver>(
+        browserState, _historyCollectionController);
+
+    _browsingHistoryService = std::make_unique<history::BrowsingHistoryService>(
+        _browsingHistoryDriver.get(),
+        ios::HistoryServiceFactory::GetForBrowserState(
+            browserState, ServiceAccessType::EXPLICIT_ACCESS),
+        IOSChromeProfileSyncServiceFactory::GetForBrowserState(browserState));
+
+    _historyCollectionController.historyService = _browsingHistoryService.get();
+
     _dispatcher = dispatcher;
 
     // Configure modal presentation.
diff --git a/ios/chrome/browser/ui/history/history_table_view_controller.h b/ios/chrome/browser/ui/history/history_table_view_controller.h
index 85ad50b..033d7f24 100644
--- a/ios/chrome/browser/ui/history/history_table_view_controller.h
+++ b/ios/chrome/browser/ui/history/history_table_view_controller.h
@@ -7,6 +7,8 @@
 
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller.h"
 
+#include "ios/chrome/browser/ui/history/history_consumer.h"
+
 namespace ios {
 class ChromeBrowserState;
 }
@@ -14,9 +16,13 @@
 @protocol UrlLoader;
 
 // ChromeTableViewController for displaying history items.
-@interface HistoryTableViewController : ChromeTableViewController
+@interface HistoryTableViewController
+    : ChromeTableViewController<HistoryConsumer>
 // The ViewController's BrowserState.
 @property(nonatomic, assign) ios::ChromeBrowserState* browserState;
+// Abstraction to communicate with HistoryService and WebHistoryService.
+// Not owned by HistoryTableViewController.
+@property(nonatomic, assign) history::BrowsingHistoryService* historyService;
 // The UrlLoader used by this ViewController.
 @property(nonatomic, weak) id<UrlLoader> loader;
 @end
diff --git a/ios/chrome/browser/ui/history/history_table_view_controller.mm b/ios/chrome/browser/ui/history/history_table_view_controller.mm
index f5521f67..c2c4bdd 100644
--- a/ios/chrome/browser/ui/history/history_table_view_controller.mm
+++ b/ios/chrome/browser/ui/history/history_table_view_controller.mm
@@ -10,5 +10,26 @@
 
 @implementation HistoryTableViewController
 @synthesize browserState = _browserState;
+@synthesize historyService = _historyService;
 @synthesize loader = _loader;
+
+#pragma mark - HistoryConsumer
+
+- (void)
+historyQueryWasCompletedWithResults:
+    (const std::vector<history::BrowsingHistoryService::HistoryEntry>&)results
+                   queryResultsInfo:(const history::BrowsingHistoryService::
+                                         QueryResultsInfo&)queryResultsInfo
+                continuationClosure:(base::OnceClosure)continuationClosure {
+  // TODO(crbug.com/805190): Implement HistoryConsumer.
+}
+
+- (void)historyWasDeleted {
+  // TODO(crbug.com/805190): Implement HistoryConsumer.
+}
+
+- (void)showNoticeAboutOtherFormsOfBrowsingHistory:(BOOL)shouldShowNotice {
+  // TODO(crbug.com/805190): Implement HistoryConsumer.
+}
+
 @end
diff --git a/ios/chrome/browser/ui/history/ios_browsing_history_driver.h b/ios/chrome/browser/ui/history/ios_browsing_history_driver.h
index c5d7857..ba5f729 100644
--- a/ios/chrome/browser/ui/history/ios_browsing_history_driver.h
+++ b/ios/chrome/browser/ui/history/ios_browsing_history_driver.h
@@ -21,35 +21,14 @@
 class ChromeBrowserState;
 }
 
-// Defines methods to manage history query results and deletion actions.
-@protocol BrowsingHistoryDriverDelegate<NSObject>
-
-// Notifies the delegate that the result of a history query has been retrieved.
-// Entries in |result| are already sorted.
-- (void)onQueryCompleteWithResults:
-            (const std::vector<history::BrowsingHistoryService::HistoryEntry>&)
-                results
-                  queryResultsInfo:
-                      (const history::BrowsingHistoryService::QueryResultsInfo&)
-                          queryResultsInfo
-               continuationClosure:(base::OnceClosure)continuationClosure;
-
-// Notifies the delegate that history entries have been deleted by a different
-// client and that the UI should be updated.
-- (void)didObserverHistoryDeletion;
-
-// Indicates to the delegate whether to show notice about other forms of
-// browsing history.
-- (void)shouldShowNoticeAboutOtherFormsOfBrowsingHistory:(BOOL)shouldShowNotice;
-
-@end
+@protocol HistoryConsumer;
 
 // A simple implementation of BrowsingHistoryServiceHandler that delegates to
-// objective-c object BrowsingHistoryDriverDelegate for most actions.
+// objective-c object HistoryConsumer for most actions.
 class IOSBrowsingHistoryDriver : public history::BrowsingHistoryDriver {
  public:
   IOSBrowsingHistoryDriver(ios::ChromeBrowserState* browser_state,
-                           id<BrowsingHistoryDriverDelegate> delegate);
+                           id<HistoryConsumer> consumer);
   ~IOSBrowsingHistoryDriver() override;
 
  private:
@@ -77,8 +56,8 @@
   // The current browser state.
   ios::ChromeBrowserState* browser_state_;  // weak
 
-  // Delegate for IOSBrowsingHistoryDriver. Serves as client for HistoryService.
-  __weak id<BrowsingHistoryDriverDelegate> delegate_;
+  // Consumer for IOSBrowsingHistoryDriver. Serves as client for HistoryService.
+  __weak id<HistoryConsumer> consumer_;
 
   DISALLOW_COPY_AND_ASSIGN(IOSBrowsingHistoryDriver);
 };
diff --git a/ios/chrome/browser/ui/history/ios_browsing_history_driver.mm b/ios/chrome/browser/ui/history/ios_browsing_history_driver.mm
index cde9ee3..f4ed65c3 100644
--- a/ios/chrome/browser/ui/history/ios_browsing_history_driver.mm
+++ b/ios/chrome/browser/ui/history/ios_browsing_history_driver.mm
@@ -13,6 +13,7 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/history/history_utils.h"
 #include "ios/chrome/browser/history/web_history_service_factory.h"
+#include "ios/chrome/browser/ui/history/history_consumer.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -24,13 +25,13 @@
 
 IOSBrowsingHistoryDriver::IOSBrowsingHistoryDriver(
     ios::ChromeBrowserState* browser_state,
-    id<BrowsingHistoryDriverDelegate> delegate)
-    : browser_state_(browser_state), delegate_(delegate) {
+    id<HistoryConsumer> consumer)
+    : browser_state_(browser_state), consumer_(consumer) {
   DCHECK(browser_state_);
 }
 
 IOSBrowsingHistoryDriver::~IOSBrowsingHistoryDriver() {
-  delegate_ = nil;
+  consumer_ = nil;
 }
 
 #pragma mark - Private methods
@@ -39,9 +40,10 @@
     const std::vector<BrowsingHistoryService::HistoryEntry>& results,
     const BrowsingHistoryService::QueryResultsInfo& query_results_info,
     base::OnceClosure continuation_closure) {
-  [delegate_ onQueryCompleteWithResults:results
-                       queryResultsInfo:query_results_info
-                    continuationClosure:std::move(continuation_closure)];
+  [consumer_
+      historyQueryWasCompletedWithResults:results
+                         queryResultsInfo:query_results_info
+                      continuationClosure:std::move(continuation_closure)];
 }
 
 void IOSBrowsingHistoryDriver::OnRemoveVisitsComplete() {
@@ -58,13 +60,13 @@
 }
 
 void IOSBrowsingHistoryDriver::HistoryDeleted() {
-  [delegate_ didObserverHistoryDeletion];
+  [consumer_ historyWasDeleted];
 }
 
 void IOSBrowsingHistoryDriver::HasOtherFormsOfBrowsingHistory(
     bool has_other_forms,
     bool has_synced_results) {
-  [delegate_ shouldShowNoticeAboutOtherFormsOfBrowsingHistory:has_other_forms];
+  [consumer_ showNoticeAboutOtherFormsOfBrowsingHistory:has_other_forms];
 }
 
 bool IOSBrowsingHistoryDriver::AllowHistoryDeletions() {
diff --git a/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h b/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h
index 01da280..a319554 100644
--- a/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h
+++ b/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h
@@ -8,6 +8,7 @@
 #import "ios/chrome/browser/ui/collection_view/collection_view_controller.h"
 
 #include "base/ios/block_types.h"
+#include "ios/chrome/browser/ui/history/history_consumer.h"
 
 namespace ios {
 class ChromeBrowserState;
@@ -35,7 +36,8 @@
 @end
 
 // View controller for displaying a collection of history entries.
-@interface LegacyHistoryCollectionViewController : CollectionViewController
+@interface LegacyHistoryCollectionViewController
+    : CollectionViewController<HistoryConsumer>
 // YES if the collection view is in editing mode. Setting |editing| turns
 // editing mode on or off accordingly.
 @property(nonatomic, assign, getter=isEditing) BOOL editing;
@@ -45,6 +47,9 @@
 @property(nonatomic, assign, readonly, getter=isEmpty) BOOL empty;
 // YES if the collection view has selected entries while in editing mode.
 @property(nonatomic, assign, readonly) BOOL hasSelectedEntries;
+// Abstraction to communicate with HistoryService and WebHistoryService.
+// Not owned by LegacyHistoryCollectionViewController.
+@property(nonatomic, assign) history::BrowsingHistoryService* historyService;
 
 - (instancetype)
 initWithLoader:(id<UrlLoader>)loader
diff --git a/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.mm b/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.mm
index 963c39d3..3c9a569 100644
--- a/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.mm
@@ -14,20 +14,14 @@
 #include "base/metrics/user_metrics_action.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "components/browser_sync/profile_sync_service.h"
 #include "components/browsing_data/core/history_notice_utils.h"
-#include "components/history/core/browser/browsing_history_driver.h"
-#include "components/history/core/browser/browsing_history_service.h"
-#include "components/keyed_service/core/service_access_type.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/url_formatter/url_formatter.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
-#include "ios/chrome/browser/history/history_service_factory.h"
 #import "ios/chrome/browser/metrics/new_tab_page_uma.h"
 #import "ios/chrome/browser/signin/authentication_service.h"
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
-#include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
 #include "ios/chrome/browser/sync/sync_setup_service.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
@@ -41,7 +35,6 @@
 #include "ios/chrome/browser/ui/history/history_entry_inserter.h"
 #import "ios/chrome/browser/ui/history/history_entry_item_delegate.h"
 #include "ios/chrome/browser/ui/history/history_util.h"
-#include "ios/chrome/browser/ui/history/ios_browsing_history_driver.h"
 #include "ios/chrome/browser/ui/history/legacy_history_entries_status_item.h"
 #import "ios/chrome/browser/ui/history/legacy_history_entry_item.h"
 #import "ios/chrome/browser/ui/url_loader.h"
@@ -80,12 +73,7 @@
 @interface LegacyHistoryCollectionViewController ()<
     HistoryEntriesStatusItemDelegate,
     HistoryEntryInserterDelegate,
-    HistoryEntryItemDelegate,
-    BrowsingHistoryDriverDelegate> {
-  // Abstraction to communicate with HistoryService and WebHistoryService.
-  std::unique_ptr<BrowsingHistoryService> _browsingHistoryService;
-  // Provides dependencies and funnels callbacks from BrowsingHistoryService.
-  std::unique_ptr<IOSBrowsingHistoryDriver> _browsingHistoryDriver;
+    HistoryEntryItemDelegate> {
   // The main browser state. Not owned by HistoryCollectionViewController.
   ios::ChromeBrowserState* _browserState;
   // Backing ivar for delegate property.
@@ -166,6 +154,7 @@
 @synthesize loading = _loading;
 @synthesize finishedLoading = _finishedLoading;
 @synthesize filterQueryResult = _filterQueryResult;
+@synthesize historyService = _historyService;
 
 - (instancetype)
 initWithLoader:(id<UrlLoader>)loader
@@ -175,13 +164,6 @@
   self =
       [super initWithLayout:layout style:CollectionViewControllerStyleDefault];
   if (self) {
-    _browsingHistoryDriver =
-        std::make_unique<IOSBrowsingHistoryDriver>(browserState, self);
-    _browsingHistoryService = std::make_unique<BrowsingHistoryService>(
-        _browsingHistoryDriver.get(),
-        ios::HistoryServiceFactory::GetForBrowserState(
-            browserState, ServiceAccessType::EXPLICIT_ACCESS),
-        IOSChromeProfileSyncServiceFactory::GetForBrowserState(browserState));
     _browserState = browserState;
     _delegate = delegate;
     _URLLoader = loader;
@@ -196,13 +178,13 @@
         [[HistoryEntryInserter alloc] initWithModel:self.collectionViewModel];
     _entryInserter.delegate = self;
     _empty = YES;
-    [self showHistoryMatchingQuery:nil];
   }
   return self;
 }
 
 - (void)viewDidLoad {
   [super viewDidLoad];
+  [self showHistoryMatchingQuery:nil];
   self.styler.cellLayoutType = MDCCollectionViewCellLayoutTypeList;
   self.styler.separatorInset =
       UIEdgeInsetsMake(0, kSeparatorInset, 0, kSeparatorInset);
@@ -272,7 +254,7 @@
     entry.all_timestamps.insert(object.timestamp.ToInternalValue());
     entries.push_back(entry);
   }
-  _browsingHistoryService->RemoveVisits(entries);
+  self.historyService->RemoveVisits(entries);
   [self removeSelectedItemsFromCollection];
 }
 
@@ -365,14 +347,15 @@
   }
 }
 
-#pragma mark - BrowsingHistoryDriverDelegate
+#pragma mark - HistoryConsumer
 
-- (void)onQueryCompleteWithResults:
+- (void)historyQueryWasCompletedWithResults:
             (const std::vector<BrowsingHistoryService::HistoryEntry>&)results
-                  queryResultsInfo:
-                      (const BrowsingHistoryService::QueryResultsInfo&)
-                          queryResultsInfo
-               continuationClosure:(base::OnceClosure)continuationClosure {
+                           queryResultsInfo:
+                               (const BrowsingHistoryService::QueryResultsInfo&)
+                                   queryResultsInfo
+                        continuationClosure:
+                            (base::OnceClosure)continuationClosure {
   self.loading = NO;
   _query_history_continuation = std::move(continuationClosure);
 
@@ -472,8 +455,7 @@
   }
 }
 
-- (void)shouldShowNoticeAboutOtherFormsOfBrowsingHistory:
-    (BOOL)shouldShowNotice {
+- (void)showNoticeAboutOtherFormsOfBrowsingHistory:(BOOL)shouldShowNotice {
   self.shouldShowNoticeAboutOtherFormsOfBrowsingHistory = shouldShowNotice;
   // Update the history entries status message if there is no query in progress.
   if (!self.isLoading) {
@@ -481,7 +463,7 @@
   }
 }
 
-- (void)didObserverHistoryDeletion {
+- (void)historyWasDeleted {
   // If history has been deleted, reload history filtering for the current
   // results. This only observes local changes to history, i.e. removing
   // history via the clear browsing data page.
@@ -648,7 +630,7 @@
     options.max_count = kMaxFetchCount;
     options.matching_algorithm =
         query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH;
-    _browsingHistoryService->QueryHistory(queryString, options);
+    self.historyService->QueryHistory(queryString, options);
   }
 }
 
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
index 9cf0ba1..cfc0b84 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
@@ -65,9 +65,9 @@
   // longer than its associated VC.
   if (!self.mediator) {
     self.mediator = [[RecentTabsMediator alloc] init];
+    self.mediator.browserState = self.browserState;
     [self.mediator initObservers];
   }
-  self.mediator.browserState = self.browserState;
   self.mediator.consumer = recentTabsTableViewController;
   [self.mediator reloadSessions];
 
diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc
index 78fd797..2194a60 100644
--- a/media/base/pipeline_impl.cc
+++ b/media/base/pipeline_impl.cc
@@ -229,6 +229,9 @@
   DCHECK(state_ == kCreated || state_ == kStopped)
       << "Received start in unexpected state: " << state_;
 
+  // Tracking down http://crbug.com/827990
+  CHECK(renderer);
+
   SetState(kStarting);
 
   DCHECK(!demuxer_);
@@ -400,6 +403,9 @@
                                            base::TimeDelta timestamp) {
   DCHECK(media_task_runner_->BelongsToCurrentThread());
 
+  // Tracking down http://crbug.com/827990
+  CHECK(renderer);
+
   // Suppress resuming if we're not suspended.
   if (state_ != kSuspended) {
     DCHECK(state_ == kStopping || state_ == kStopped)
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index 28e4258..8c2e3258 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -1234,6 +1234,12 @@
   // It is possible that a pushed stream has been opened by a server since last
   // time Job checked above.
   if (!existing_spdy_session_) {
+    // WebSocket over HTTP/2 is only allowed to use existing HTTP/2 connections.
+    // Therefore |using_spdy_| could not have been set unless a connection had
+    // already been found.
+    // TODO(bnc): Change to DCHECK once https://crbug.com/819101 is fixed.
+    CHECK(!try_websocket_over_http2_);
+
     session_->spdy_session_pool()->push_promise_index()->ClaimPushedStream(
         spdy_session_key_, origin_url_, request_info_, &existing_spdy_session_,
         &pushed_stream_id_);
diff --git a/net/proxy_resolution/multi_threaded_proxy_resolver_unittest.cc b/net/proxy_resolution/multi_threaded_proxy_resolver_unittest.cc
index ec445f1..3f559d9f 100644
--- a/net/proxy_resolution/multi_threaded_proxy_resolver_unittest.cc
+++ b/net/proxy_resolution/multi_threaded_proxy_resolver_unittest.cc
@@ -13,8 +13,8 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
-#include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
@@ -90,31 +90,44 @@
 
 // A mock synchronous ProxyResolver which can be set to block upon reaching
 // GetProxyForURL().
-// TODO(eroman): WaitUntilBlocked() *must* be called before calling Unblock(),
-//               otherwise there will be a race on |should_block_| since it is
-//               read without any synchronization.
 class BlockableProxyResolver : public MockProxyResolver {
  public:
-  BlockableProxyResolver()
-      : should_block_(false),
-        unblocked_(base::WaitableEvent::ResetPolicy::MANUAL,
-                   base::WaitableEvent::InitialState::SIGNALED),
-        blocked_(base::WaitableEvent::ResetPolicy::MANUAL,
-                 base::WaitableEvent::InitialState::NOT_SIGNALED) {}
+  enum class State {
+    NONE,
+    BLOCKED,
+    WILL_BLOCK,
+  };
 
+  BlockableProxyResolver() : state_(State::NONE), condition_(&lock_) {}
+
+  ~BlockableProxyResolver() override {
+    base::AutoLock lock(lock_);
+    EXPECT_NE(State::BLOCKED, state_);
+  }
+
+  // Causes the next call into GetProxyForURL() to block. Must be followed by
+  // a call to Unblock().
   void Block() {
-    should_block_ = true;
-    unblocked_.Reset();
+    base::AutoLock lock(lock_);
+    EXPECT_EQ(State::NONE, state_);
+    state_ = State::WILL_BLOCK;
+    condition_.Broadcast();
   }
 
+  // Unblocks the ProxyResolver. The ProxyResolver must already be in a
+  // blocked state prior to calling.
   void Unblock() {
-    should_block_ = false;
-    blocked_.Reset();
-    unblocked_.Signal();
+    base::AutoLock lock(lock_);
+    EXPECT_EQ(State::BLOCKED, state_);
+    state_ = State::NONE;
+    condition_.Broadcast();
   }
 
+  // Waits until the proxy resolver is blocked within GetProxyForURL().
   void WaitUntilBlocked() {
-    blocked_.Wait();
+    base::AutoLock lock(lock_);
+    while (state_ != State::BLOCKED)
+      condition_.Wait();
   }
 
   int GetProxyForURL(const GURL& query_url,
@@ -122,9 +135,18 @@
                      const CompletionCallback& callback,
                      std::unique_ptr<Request>* request,
                      const NetLogWithSource& net_log) override {
-    if (should_block_) {
-      blocked_.Signal();
-      unblocked_.Wait();
+    {
+      base::AutoLock lock(lock_);
+
+      EXPECT_NE(State::BLOCKED, state_);
+
+      if (state_ == State::WILL_BLOCK) {
+        state_ = State::BLOCKED;
+        condition_.Broadcast();
+
+        while (state_ == State::BLOCKED)
+          condition_.Wait();
+      }
     }
 
     return MockProxyResolver::GetProxyForURL(
@@ -132,9 +154,11 @@
   }
 
  private:
-  bool should_block_;
-  base::WaitableEvent unblocked_;
-  base::WaitableEvent blocked_;
+  State state_;
+  base::Lock lock_;
+  base::ConditionVariable condition_;
+
+  DISALLOW_COPY_AND_ASSIGN(BlockableProxyResolver);
 };
 
 // This factory returns new instances of BlockableProxyResolver.
diff --git a/notification_helper/notification_helper.cc b/notification_helper/notification_helper.cc
index 9e4119b..29d90f1 100644
--- a/notification_helper/notification_helper.cc
+++ b/notification_helper/notification_helper.cc
@@ -38,8 +38,10 @@
   // "-Embedding" flag to the command line. If this flag is not found, the
   // process should exit immediately.
   // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683844.aspx
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch("embedding"))
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch("embedding")) {
+    persistent_histogram_storage.Disable();
     return 0;
+  }
 
   install_static::InitializeProductDetailsForPrimaryModule();
 
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 4e8d765..4d787a9e 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -1771,6 +1771,66 @@
       },
       {
         "args": [
+          "rendering.mobile",
+          "-v",
+          "--upload-results",
+          "--browser=android-chromium",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.mobile",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "id": "build48-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.mobile",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.mobile.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "id": "build48-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -6464,6 +6524,66 @@
       },
       {
         "args": [
+          "rendering.mobile",
+          "-v",
+          "--upload-results",
+          "--browser=android-chromium",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.mobile",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "id": "build75-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.mobile",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.mobile.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "id": "build75-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -10207,6 +10327,36 @@
       },
       {
         "args": [
+          "rendering.mobile",
+          "-v",
+          "--upload-results",
+          "--browser=android-webview",
+          "--output-format=chartjson",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "rendering.mobile",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "id": "build166-b1--device1",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -13369,6 +13519,66 @@
       },
       {
         "args": [
+          "rendering.mobile",
+          "-v",
+          "--upload-results",
+          "--browser=android-chromium",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.mobile",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "id": "build45-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.mobile",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.mobile.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "id": "build45-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -17112,6 +17322,36 @@
       },
       {
         "args": [
+          "rendering.mobile",
+          "-v",
+          "--upload-results",
+          "--browser=android-webview",
+          "--output-format=chartjson",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "rendering.mobile",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "id": "build114-b1--device1",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -20296,6 +20536,66 @@
       },
       {
         "args": [
+          "rendering.mobile",
+          "-v",
+          "--upload-results",
+          "--browser=android-chromium",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.mobile",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "id": "build49-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.mobile",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.mobile.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "id": "build49-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -24907,6 +25207,66 @@
       },
       {
         "args": [
+          "rendering.mobile",
+          "-v",
+          "--upload-results",
+          "--browser=android-chromium",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.mobile",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "id": "build17-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.mobile",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.mobile.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "id": "build17-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -29586,6 +29946,68 @@
       },
       {
         "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=release",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3",
+              "id": "build29-a9",
+              "os": "Ubuntu-14.04",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3",
+              "id": "build29-a9",
+              "os": "Ubuntu-14.04",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -33628,6 +34050,68 @@
       },
       {
         "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=release",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "id": "build160-m1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "id": "build160-m1",
+              "os": "Mac-10.12",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -37608,6 +38092,68 @@
       },
       {
         "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=release",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1626",
+              "id": "build125-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1626",
+              "id": "build125-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -41572,6 +42118,68 @@
       },
       {
         "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=release",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6821",
+              "id": "build130-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6821",
+              "id": "build130-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -45386,6 +45994,68 @@
       },
       {
         "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=release_x64",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1616",
+              "id": "build119-b1",
+              "os": "Windows-10",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1616",
+              "id": "build119-b1",
+              "os": "Windows-10",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -49242,6 +49912,68 @@
       },
       {
         "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=release_x64",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912",
+              "id": "build191-a9",
+              "os": "Windows-10",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912",
+              "id": "build191-a9",
+              "os": "Windows-10",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -53140,6 +53872,68 @@
       },
       {
         "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=release_x64",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6613",
+              "id": "build103-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6613",
+              "id": "build103-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -57017,6 +57811,68 @@
       },
       {
         "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=release_x64",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:041a",
+              "id": "build166-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:041a",
+              "id": "build166-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -60918,6 +61774,68 @@
       },
       {
         "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=release_x64",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3",
+              "id": "build94-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3",
+              "id": "build94-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -64819,6 +65737,68 @@
       },
       {
         "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=release",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build187-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build187-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -68675,6 +69655,68 @@
       },
       {
         "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=release_x64",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build140-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build140-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
@@ -72552,6 +73594,68 @@
       },
       {
         "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=release_x64",
+          "--output-format=chartjson"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build145-m1",
+              "os": "Windows-2012ServerR2-SP0",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
+          "rendering.desktop",
+          "-v",
+          "--upload-results",
+          "--browser=reference",
+          "--output-format=chartjson",
+          "--max-failures=5",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "rendering.desktop.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build145-m1",
+              "os": "Windows-2012ServerR2-SP0",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 1200,
+          "upload_test_results": true
+        }
+      },
+      {
+        "args": [
           "scheduler.tough_scheduling_cases",
           "-v",
           "--upload-results",
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index ab6bb9a4..f2e7044 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -5,7 +5,6 @@
 -BackgroundXhrTest.HttpAuth
 -BackgroundXhrTest.TlsClientAuth
 -ChromeSecurityExploitBrowserTest.CreateFilesystemURLInExtensionOrigin
--DevToolsSanityTest.TestRawHeadersWithRedirectAndHSTS
 -DisabledSignInIsolationBrowserTest.SyntheticTrial
 -DomainReliabilityBrowserTest.Upload
 -EnabledSignInIsolationBrowserTest.SyntheticTrial
diff --git a/testing/test.gni b/testing/test.gni
index 251b003fa..0f92985 100644
--- a/testing/test.gni
+++ b/testing/test.gni
@@ -110,6 +110,9 @@
         unwind_table_asset(_unwind_table_asset_name) {
           testonly = true
           library_target = _library_target
+          deps = [
+            ":$_library_target",
+          ]
         }
       }
 
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 29f45e0f..3613d7f 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -119,8 +119,9 @@
 crbug.com/591099 animations/interpolation/backdrop-filter-interpolation.html [ Timeout ]
 crbug.com/591099 animations/interpolation/line-height-interpolation.html [ Timeout ]
 crbug.com/591099 animations/interpolation/svg-stroke-dasharray-interpolation.html [ Timeout ]
-crbug.com/591099 animations/interpolation/webkit-clip-path-interpolation.html [ Timeout ]
+crbug.com/591099 animations/interpolation/webkit-clip-path-interpolation.html [ Pass Timeout ]
 crbug.com/591099 animations/rotate-transform-equivalent.html [ Failure ]
+crbug.com/591099 animations/svg/animated-filter-svg-element.html [ Timeout ]
 crbug.com/591099 animations/timing/timing-model.html [ Timeout ]
 crbug.com/714962 compositing/background-color/view-blending-base-background.html [ Failure ]
 crbug.com/591099 compositing/draws-content/canvas-background-layer.html [ Failure ]
@@ -136,7 +137,7 @@
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-on-promoted-overflow-div-scrolled.html [ Failure ]
 crbug.com/591099 compositing/iframes/floating-self-painting-frame.html [ Failure ]
 crbug.com/591099 compositing/layer-creation/rotate3d-overlap.html [ Failure ]
-crbug.com/591099 compositing/masks/mask-with-added-filters.html [ Timeout ]
+crbug.com/591099 compositing/masks/mask-with-added-filters.html [ Pass Timeout ]
 crbug.com/591099 compositing/overflow/border-radius-above-composited-subframe.html [ Failure ]
 crbug.com/591099 compositing/overflow/nested-border-radius-clipping.html [ Failure ]
 crbug.com/591099 compositing/overflow/overflow-scroll-with-local-image-background.html [ Failure ]
@@ -214,7 +215,6 @@
 crbug.com/591099 editing/execCommand/format-block-multiple-paragraphs-in-pre.html [ Failure ]
 crbug.com/591099 editing/execCommand/format-block-multiple-paragraphs.html [ Failure ]
 crbug.com/591099 editing/execCommand/query-format-block.html [ Pass Timeout ]
-crbug.com/591099 editing/execCommand/remove-list-from-range-selection.html [ Failure ]
 crbug.com/591099 editing/inserting/4875189-1.html [ Failure ]
 crbug.com/591099 editing/inserting/4959067.html [ Failure ]
 crbug.com/591099 editing/inserting/editable-inline-element.html [ Failure ]
@@ -687,6 +687,7 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/wm-propagation-body-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/cssom-view/elementFromPoint-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/cssom-view/elementFromPoint-003.html [ Failure ]
+crbug.com/591099 external/wpt/css/cssom/interfaces.html [ Timeout ]
 crbug.com/591099 external/wpt/css/geometry/interfaces.worker.html [ Pass ]
 crbug.com/591099 external/wpt/css/selectors/focus-within-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-content-vert-001a.xhtml [ Failure ]
@@ -1516,7 +1517,7 @@
 crbug.com/591099 fast/table/percent-height-content-in-fixed-height-border-box-sized-cell-with-collapsed-border.html [ Failure ]
 crbug.com/591099 fast/table/percent-height-content-in-fixed-height-content-box-sized-cell.html [ Failure ]
 crbug.com/591099 fast/table/percent-height-overflow-auto-content-in-cell.html [ Failure Pass ]
-crbug.com/591099 fast/table/percent-height-overflow-scroll-content-in-cell.html [ Failure ]
+crbug.com/591099 fast/table/percent-height-overflow-scroll-content-in-cell.html [ Failure Pass ]
 crbug.com/591099 fast/table/percent-height-replaced-content-in-cell.html [ Failure ]
 crbug.com/591099 fast/table/percent-widths-stretch-vertical.html [ Failure ]
 crbug.com/591099 fast/table/table-display-types-vertical.html [ Failure ]
@@ -1722,8 +1723,10 @@
 crbug.com/591099 http/tests/devtools/console/console-viewport-control.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-1.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-2.js [ Timeout ]
+crbug.com/591099 http/tests/devtools/editor/text-editor-enter-behaviour.js [ Timeout ]
 crbug.com/714962 http/tests/devtools/editor/text-editor-formatter.js [ Pass Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-indent-autodetection.js [ Pass Timeout ]
+crbug.com/591099 http/tests/devtools/editor/text-editor-reveal-line.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-word-jumps.js [ Pass ]
 crbug.com/714962 http/tests/devtools/elements/edit/edit-dom-actions-4.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/elements-inspect-iframe-from-different-domain.js [ Timeout ]
@@ -2166,7 +2169,7 @@
 crbug.com/591099 svg/custom/use-event-retargeting.html [ Failure ]
 crbug.com/591099 svg/custom/use-font-face-crash.svg [ Failure ]
 crbug.com/591099 svg/dom/svgangle-units.html [ Pass Timeout ]
-crbug.com/591099 svg/filters/feTurbulence-bad-seeds.html [ Failure Pass ]
+crbug.com/591099 svg/filters/feTurbulence-bad-seeds.html [ Failure ]
 crbug.com/591099 svg/hixie/error/012.xml [ Failure ]
 crbug.com/591099 svg/hixie/error/dumpAsText/004.xml [ Failure ]
 crbug.com/591099 svg/hixie/error/dumpAsText/005.xml [ Failure ]
@@ -2176,7 +2179,7 @@
 crbug.com/591099 svg/parser/whitespace-length-invalid-1.html [ Pass Timeout ]
 crbug.com/591099 svg/parser/whitespace-length-invalid-2.html [ Pass Timeout ]
 crbug.com/591099 svg/parser/whitespace-length-invalid-3.html [ Pass Timeout ]
-crbug.com/591099 svg/parser/whitespace-length-invalid-4.html [ Timeout ]
+crbug.com/591099 svg/parser/whitespace-length-invalid-4.html [ Pass Timeout ]
 crbug.com/591099 svg/parser/whitespace-number.html [ Timeout ]
 crbug.com/591099 svg/text/foreignObject-text-clipping-bug.xml [ Failure ]
 crbug.com/714962 svg/text/tspan-multiple-outline.svg [ Failure ]
@@ -2250,22 +2253,23 @@
 crbug.com/591099 virtual/exotic-color-space/ [ Skip ]
 crbug.com/591099 virtual/feature-policy-vibrate/ [ Skip ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-background-clip-text.html [ Failure ]
+crbug.com/591099 virtual/gpu-rasterization/images/color-profile-filter.html [ Timeout ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-group.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-image-shape.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-layer-filter.html [ Timeout ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-layer.html [ Failure ]
-crbug.com/591099 virtual/gpu-rasterization/images/color-profile-mask-image-svg.html [ Timeout ]
+crbug.com/591099 virtual/gpu-rasterization/images/color-profile-mask-image-svg.html [ Pass Timeout ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-reflection.html [ Failure ]
+crbug.com/591099 virtual/gpu-rasterization/images/cross-fade-overflow-position.html [ Timeout ]
 crbug.com/591099 virtual/gpu-rasterization/images/percent-height-image.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/rendering-broken-block-flow-images.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/rendering-broken-images.html [ Failure ]
 crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-2d-pattern-in-worker.html [ Pass ]
-crbug.com/591099 virtual/gpu/fast/canvas/canvas-composite.html [ Pass Timeout ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-drawImage-video-imageSmoothingEnabled.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-imageSmoothingQuality.html [ Pass ]
-crbug.com/591099 virtual/gpu/fast/canvas/fillrect_gradient.html [ Timeout ]
-crbug.com/591099 virtual/gpu/fast/canvas/shadow-huge-blur.html [ Timeout ]
+crbug.com/591099 virtual/gpu/fast/canvas/fillrect_gradient.html [ Pass Timeout ]
+crbug.com/591099 virtual/gpu/fast/canvas/shadow-huge-blur.html [ Pass Timeout ]
 crbug.com/591099 virtual/incremental-shadow-dom/external/wpt/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html [ Failure ]
 crbug.com/714962 virtual/incremental-shadow-dom/fast/dom/shadow/scrollbar.html [ Crash ]
 crbug.com/591099 virtual/incremental-shadow-dom/fast/dom/shadow/selections-in-shadow.html [ Timeout ]
@@ -2294,11 +2298,14 @@
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/sequential-focus-navigation-starting-point.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-scroll.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
+crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/scroll-without-mouse-lacks-mousemove-events.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/wheel/mainthread-touchpad-fling-latching.html [ Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Pass ]
 crbug.com/591099 virtual/navigation-mojo-response/external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/registration-attribute.https.html [ Failure Pass ]
 crbug.com/591099 virtual/navigation-mojo-response/http/tests/serviceworker/webexposed/global-interface-listing-service-worker.html [ Timeout ]
 crbug.com/591099 virtual/new-remote-playback-pipeline/ [ Skip ]
+crbug.com/591099 virtual/off-main-thread-websocket/http/tests/websocket/invalid-subprotocol-characters.html [ Timeout ]
+crbug.com/591099 virtual/off-main-thread-websocket/http/tests/websocket/multiple-connections-throttled.html [ Pass ]
 crbug.com/591099 virtual/outofblink-cors/ [ Skip ]
 crbug.com/591099 virtual/paint-timing/external/wpt/paint-timing/sibling-painting-first-image.html [ Failure ]
 crbug.com/591099 virtual/prefer_compositing_to_lcd_text/ [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 02f18c7..c873a35 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1624,9 +1624,21 @@
 crbug.com/803558 external/wpt/websockets/constructor/014.html?wss [ Timeout ]
 crbug.com/803558 external/wpt/websockets/keeping-connection-open/001.html?wss [ Timeout ]
 crbug.com/803558 external/wpt/websockets/opening-handshake/003-sets-origin.worker.html [ Timeout ]
+crbug.com/803358 virtual/off-main-thread-websocket/external/wpt/websockets/Create-Secure-extensions-empty.htm [ Timeout ]
+crbug.com/803558 virtual/off-main-thread-websocket/external/wpt/websockets/constructor/014.html?wss [ Timeout ]
+crbug.com/803558 virtual/off-main-thread-websocket/external/wpt/websockets/keeping-connection-open/001.html?wss [ Timeout ]
+crbug.com/803558 virtual/off-main-thread-websocket/external/wpt/websockets/opening-handshake/003-sets-origin.worker.html [ Timeout ]
 # Cannot be rebaselined because the output contains a timestamp and a random number.
 crbug.com/803200 external/wpt/websockets/cookies/006.html?wss [ Failure ]
 crbug.com/803200 external/wpt/websockets/opening-handshake/005.html?wss [ Pass Failure ]
+crbug.com/803200 virtual/off-main-thread-websocket/external/wpt/websockets/cookies/006.html?wss [ Failure ]
+crbug.com/803200 virtual/off-main-thread-websocket/external/wpt/websockets/opening-handshake/005.html?wss [ Pass Failure ]
+# These tests are failing because of experimental off-main-thread WebSocket
+# implementation.
+crbug.com/825740 virtual/off-main-thread-websocket/http/tests/security/mixedContent/websocket/insecure-websocket-in-secure-page-worker.html [ Failure ]
+crbug.com/825740 virtual/off-main-thread-websocket/http/tests/websocket/multiple-connections-throttled.html [ Timeout ]
+crbug.com/825740 virtual/off-main-thread-websocket/http/tests/websocket/workers/close-code-and-reason.html [ Failure ]
+crbug.com/825740 virtual/off-main-thread-websocket/http/tests/websocket/workers/close.html [ Failure ]
 
 crbug.com/805463 external/wpt/acid/acid3/numbered-tests.html [ Skip ]
 
@@ -3356,14 +3368,3 @@
 crbug.com/826936 external/wpt/webauthn/getcredential-extensions.https.html [ Pass Timeout ]
 crbug.com/826936 external/wpt/webauthn/getcredential-passing.https.html [ Pass Timeout ]
 crbug.com/826936 external/wpt/webauthn/getcredential-timeout.https.html [ Pass Timeout ]
-
-crbug.com/825740 virtual/off-main-thread-websocket/external/wpt/websockets/Create-Secure-extensions-empty.htm [ Timeout ]
-crbug.com/825740 virtual/off-main-thread-websocket/external/wpt/websockets/constructor/014.html?wss [ Timeout ]
-crbug.com/825740 virtual/off-main-thread-websocket/external/wpt/websockets/cookies/006.html?wss [ Failure ]
-crbug.com/825740 virtual/off-main-thread-websocket/external/wpt/websockets/keeping-connection-open/001.html?wss [ Timeout ]
-crbug.com/825740 virtual/off-main-thread-websocket/external/wpt/websockets/opening-handshake/003-sets-origin.worker.html [ Timeout ]
-crbug.com/825740 virtual/off-main-thread-websocket/external/wpt/websockets/opening-handshake/005.html?wss [ Failure ]
-crbug.com/825740 virtual/off-main-thread-websocket/http/tests/security/mixedContent/websocket/insecure-websocket-in-secure-page-worker.html [ Failure ]
-crbug.com/825740 virtual/off-main-thread-websocket/http/tests/websocket/multiple-connections-throttled.html [ Timeout ]
-crbug.com/825740 virtual/off-main-thread-websocket/http/tests/websocket/workers/close-code-and-reason.html [ Failure ]
-crbug.com/825740 virtual/off-main-thread-websocket/http/tests/websocket/workers/close.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/editing/execCommand/5138441.html b/third_party/WebKit/LayoutTests/editing/execCommand/5138441.html
index 53fbbc3..4201763 100644
--- a/third_party/WebKit/LayoutTests/editing/execCommand/5138441.html
+++ b/third_party/WebKit/LayoutTests/editing/execCommand/5138441.html
@@ -1,26 +1,27 @@
-<html>
-<head>
-<style>
-blockquote {
-    border: 1px dashed #aaa;
-    padding: 0.5em;
-    margin: 0.5em;
-}
-</style>
-</head>
-<body>
-<p>This tests for a bug where indented text would appear quoted in GoogleDocs.  Google docs uses blockquotes and FormatBlock to implement a "Quote Text" feature, and style rules for blockquotes appeared on the blockquotes that we use to implement indenting.</p>
-<div contenteditable="true">
-<div id="div">This should be indented, not quoted.</div>
-<blockquote>This text should be Quoted.</blockquote>
-</div>
-
+<!doctype HTML>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../assert_selection.js"></script>
 <script>
-var selection = window.getSelection();
-var div = document.getElementById("div");
-
-selection.collapse(div, 0);
-document.execCommand("Indent");
+// This tests for a bug where indented text would appear quoted in GoogleDocs.
+// Google docs uses blockquotes and FormatBlock to implement a "Quote Text"
+// feature, and style rules for blockquotes appeared on the blockquotes that we
+// use to implement indenting.
+selection_test(
+  [
+    '<div contenteditable>',
+     '<div>|ab</div>',
+     '<blockquote>CD</blockquote>',
+   '</div>',
+  ],
+  'indent',
+  [
+    '<div contenteditable>',
+     '<blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;">',
+       '<div>|ab</div>',
+     '</blockquote>',
+     '<blockquote>CD</blockquote>',
+   '</div>',
+  ],
+  'Indent before BLOCKQUOTE');
 </script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/editing/execCommand/5569741.html b/third_party/WebKit/LayoutTests/editing/execCommand/5569741.html
index 37141eb..d2295da5 100644
--- a/third_party/WebKit/LayoutTests/editing/execCommand/5569741.html
+++ b/third_party/WebKit/LayoutTests/editing/execCommand/5569741.html
@@ -1,11 +1,26 @@
-<p>This tests for a bug where hitting return inside an empty paragraph in a non-empty list item would remove it.</p>
-<div id="div" contenteditable="true">
-<ul><li id="li">foo<br><br></li></ul>
-</div>
-
+<!doctype HTML>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../assert_selection.js"></script>
 <script>
-li = document.getElementById("li");
-sel = window.getSelection();
-sel.collapse(li, li.childNodes.length);
-document.execCommand("InsertParagraph");
+// This tests for a bug where hitting return inside an empty paragraph in a
+// non-empty list item would remove it.
+selection_test(
+  [
+    '<div contenteditable>',
+      '<ul>',
+        '<li>foo<br><br>|</li>',
+      '</ul>',
+    '</div>',
+  ],
+  'insertParagraph',
+  [
+    '<div contenteditable>',
+      '<ul>',
+        '<li>foo<br><br></li>',
+        '<li>|<br></li>',
+      '</ul>',
+    '</div>',
+  ],
+  'insertParagraph at empty paragraph in list item');
 </script>
diff --git a/third_party/WebKit/LayoutTests/editing/execCommand/remove-list-from-range-selection.html b/third_party/WebKit/LayoutTests/editing/execCommand/remove-list-from-range-selection.html
index a9b9e11f..16325cc 100644
--- a/third_party/WebKit/LayoutTests/editing/execCommand/remove-list-from-range-selection.html
+++ b/third_party/WebKit/LayoutTests/editing/execCommand/remove-list-from-range-selection.html
@@ -1,14 +1,28 @@
+<!doctype HTML>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../assert_selection.js"></script>
 <script>
-if (window.testRunner)
-     testRunner.dumpEditingCallbacks();
-</script>
-<p>This tests Insert{Un}OrderedList on a range selection that is entirely within one list.</p>
-<div id="test" contenteditable="true"><ol><li><span id="start">None of the</span></li><li>selected content</li><li>should be</li><li><span id="end">in a list.</span></li></ol><ol><li>This should be in a list and should not be selected.</li></ol></div>
-<script>
-var s = window.getSelection();
-var start = document.getElementById("start").firstChild;
-var end = document.getElementById("end").firstChild;
-s.setBaseAndExtent(start, 2, end, 2);
-
-document.execCommand("InsertOrderedList", false, "foo");
+// This tests Insert{Un}OrderedList on a range selection that is entirely within
+// one list.
+selection_test(
+  [
+    '<div contenteditable>',
+      '<ol>',
+        '<li><span>a^B</span></li>',
+        '<li>CD</li>',
+        '<li>EF</li>',
+        '<li><span>G|h</span></li>',
+      '</ol>',
+      '<ol><li>ij</li></ol>',
+    '</div>',
+  ],
+  'insertOrderedList',
+  [
+    '<div contenteditable>',
+      'a^B<br>CD<br>EF<br>G|h<br>',
+      '<ol><li>ij</li></ol>',
+    '</div>',
+  ],
+  'Remove list from range selection');
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-variables/variable-definition-border-shorthand-serialize-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-variables/variable-definition-border-shorthand-serialize-expected.txt
deleted file mode 100644
index f77e628..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-variables/variable-definition-border-shorthand-serialize-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL border-color should serialize to empty when border shorthand references a variable assert_equals: expected "" but got "var(--borderwidth) solid black"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-variables/vars-border-shorthand-serialize-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-variables/vars-border-shorthand-serialize-expected.txt
deleted file mode 100644
index 1d482c67e..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-variables/vars-border-shorthand-serialize-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-FAIL border-color should serialize to the empty string when border references a variable assert_equals: expected "" but got "var(--border)"
-FAIL border-style should serialize to the empty string when border references a variable assert_equals: expected "" but got "var(--border)"
-FAIL border-width should serialize to the empty string when border references a variable assert_equals: expected "" but got "var(--border)"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/shorthand-serialization-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/shorthand-serialization-expected.txt
deleted file mode 100644
index 1e2c5e68..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/shorthand-serialization-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-PASS Shorthand serialization with shorthand and longhands mixed.
-PASS Shorthand serialization with just longhands.
-FAIL Shorthand serialization with variable and variable from other shorthand. assert_equals: expected "" but got "var(--a)"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-combinations.html b/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-combinations.html
index 599e5fe..322da215 100644
--- a/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-combinations.html
+++ b/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-combinations.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <head>
 <style>
 .outer {
diff --git a/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-composited-parent.html b/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-composited-parent.html
index 44800021..5adb7116 100644
--- a/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-composited-parent.html
+++ b/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-composited-parent.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <head>
 <style>
 .outer {
diff --git a/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-composited.html b/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-composited.html
index 0e427f6..310657c 100644
--- a/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-composited.html
+++ b/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-composited.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <head>
 <style>
 .outer {
diff --git a/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-transformed.html b/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-transformed.html
index 8f57f70..a1c8d42 100644
--- a/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-transformed.html
+++ b/third_party/WebKit/LayoutTests/fast/clip/overflow-border-radius-transformed.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <head>
 <style>
 .outer {
diff --git a/third_party/WebKit/LayoutTests/fast/css/variables/longhand-pending-shorthand-substitution.html b/third_party/WebKit/LayoutTests/fast/css/variables/longhand-pending-shorthand-substitution.html
index 5b536bc..0ff0c16c 100644
--- a/third_party/WebKit/LayoutTests/fast/css/variables/longhand-pending-shorthand-substitution.html
+++ b/third_party/WebKit/LayoutTests/fast/css/variables/longhand-pending-shorthand-substitution.html
@@ -38,11 +38,11 @@
 
 test(function() {
   var style = testElem3.style;
-  assert_equals(style.cssText, '--b1: 1px solid grey; --b2: 2px dashed green; border-top: var(--b1); border-bottom: var(--b1); border-left: var(--b1); border-image: var(--b1); border-right: var(--b2);')
+  assert_equals(style.cssText, '--b1: 1px solid grey; --b2: 2px dashed green; border-top-color: ; border-top-style: ; border-top-width: ; border-bottom-color: ; border-bottom-style: ; border-bottom-width: ; border-left-color: ; border-left-style: ; border-left-width: ; border-image-source: ; border-image-slice: ; border-image-width: ; border-image-outset: ; border-image-repeat: ; border-right: var(--b2);')
   assert_equals(style.border, '');
-  assert_equals(style.borderLeft, 'var(--b1)');
-  assert_equals(style.borderTop, 'var(--b1)');
-  assert_equals(style.borderBottom, 'var(--b1)');
+  assert_equals(style.borderLeft, '');
+  assert_equals(style.borderTop, '');
+  assert_equals(style.borderBottom, '');
   assert_equals(style.borderRight, 'var(--b2)');
 }, "Test serialization for shorthands within shorthands.");
 
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/box_properties/border_color_inline-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/box_properties/border_color_inline-expected.png
deleted file mode 100644
index 4e10acb5..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/box_properties/border_color_inline-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/box_properties/float_margin-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/box_properties/float_margin-expected.png
deleted file mode 100644
index 82697a1..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/box_properties/float_margin-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/box_properties/margin-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/box_properties/margin-expected.png
deleted file mode 100644
index ad3a669..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/box_properties/margin-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/color_and_background/background_color-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/color_and_background/background_color-expected.png
deleted file mode 100644
index d11bf2b8..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/color_and_background/background_color-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/font_properties/font-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/font_properties/font-expected.png
deleted file mode 100644
index 433c296d..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/font_properties/font-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/font_properties/font_variant-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/font_properties/font_variant-expected.png
deleted file mode 100644
index e414882..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/font_properties/font_variant-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/formatting_model/canvas-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/formatting_model/canvas-expected.png
deleted file mode 100644
index 908420b..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/formatting_model/canvas-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/formatting_model/floating_elements-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/formatting_model/floating_elements-expected.png
deleted file mode 100644
index c45b207..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/formatting_model/floating_elements-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/formatting_model/height_of_lines-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/formatting_model/height_of_lines-expected.png
deleted file mode 100644
index fbf1794f..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/formatting_model/height_of_lines-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/pseudo/firstline-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/pseudo/firstline-expected.png
deleted file mode 100644
index 9d5eacc..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/pseudo/firstline-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/pseudo/pseudo_elements_in_selectors-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/pseudo/pseudo_elements_in_selectors-expected.png
deleted file mode 100644
index 21dbe410..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/pseudo/pseudo_elements_in_selectors-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/text_properties/text_align-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/text_properties/text_align-expected.png
deleted file mode 100644
index 588a4ce..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/text_properties/text_align-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/text_properties/text_decoration-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/text_properties/text_decoration-expected.png
deleted file mode 100644
index 9ad774c..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/text_properties/text_decoration-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/units/length_units-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/units/length_units-expected.png
deleted file mode 100644
index 1a09bee..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css1/units/length_units-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css2.1/t1505-c524-font-var-00-b-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css2.1/t1505-c524-font-var-00-b-expected.png
deleted file mode 100644
index c41b099e..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/css2.1/t1505-c524-font-var-00-b-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/editing/unsupported-content/list-delete-001-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/editing/unsupported-content/list-delete-001-expected.png
deleted file mode 100644
index f54f855..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/editing/unsupported-content/list-delete-001-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/animation/request-animation-frame-detach-element-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/animation/request-animation-frame-detach-element-expected.txt
deleted file mode 100644
index c9fc479a..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/animation/request-animation-frame-detach-element-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test passes is there is no crash. 
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/animation/request-animation-frame-detach-element2-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/animation/request-animation-frame-detach-element2-expected.txt
deleted file mode 100644
index c9fc479a..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/animation/request-animation-frame-detach-element2-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test passes is there is no crash. 
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/basic/014-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/basic/014-expected.png
deleted file mode 100644
index ee0f175..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/basic/014-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/margin-collapse/103-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/margin-collapse/103-expected.png
deleted file mode 100644
index b7785b9..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/margin-collapse/103-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/positioning/absolute-in-inline-rtl-2-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/positioning/absolute-in-inline-rtl-2-expected.png
deleted file mode 100644
index 71551fd..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/positioning/absolute-in-inline-rtl-2-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/positioning/absolute-in-inline-rtl-3-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/positioning/absolute-in-inline-rtl-3-expected.png
deleted file mode 100644
index 58bc210..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/positioning/absolute-in-inline-rtl-3-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/positioning/absolute-in-inline-rtl-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/positioning/absolute-in-inline-rtl-expected.png
deleted file mode 100644
index f094ac7..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/block/positioning/absolute-in-inline-rtl-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css/beforeSelectorOnCodeElement-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css/beforeSelectorOnCodeElement-expected.png
deleted file mode 100644
index 7ab21086..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css/beforeSelectorOnCodeElement-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css/line-height-determined-by-primary-font-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css/line-height-determined-by-primary-font-expected.png
deleted file mode 100644
index 3482e74..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css/line-height-determined-by-primary-font-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css/universal-hover-quirk-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css/universal-hover-quirk-expected.png
deleted file mode 100644
index e504a0e7..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css/universal-hover-quirk-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css3-text/css3-text-justify/text-justify-8bits-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css3-text/css3-text-justify/text-justify-8bits-expected.png
deleted file mode 100644
index f3a88412..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/css3-text/css3-text-justify/text-justify-8bits-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/events/js-keyboard-event-creation-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/events/js-keyboard-event-creation-expected.txt
deleted file mode 100644
index 505f2f7..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/events/js-keyboard-event-creation-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
- 
-This tests that DOMKeyboardEvents are created correctly in the JavaScript API.
-
-keydown - key: Tab@DOM_KEY_LOCATION_STANDARD (keyCode/charCode: 9/0) modifiers: false,false,false,false
-
-keyup - key: Tab@DOM_KEY_LOCATION_STANDARD (keyCode/charCode: 9/0) modifiers: false,false,true,false
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
deleted file mode 100644
index 37cd686..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
deleted file mode 100644
index e25a701..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/datalist/input-appearance-range-with-transform-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/datalist/input-appearance-range-with-transform-expected.png
deleted file mode 100644
index 59d6942..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/datalist/input-appearance-range-with-transform-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/placeholder-position-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/placeholder-position-expected.png
deleted file mode 100644
index ca1ee97..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/placeholder-position-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select-popup/popup-menu-appearance-transform-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select-popup/popup-menu-appearance-transform-expected.png
deleted file mode 100644
index e8da1b8..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select-popup/popup-menu-appearance-transform-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/menulist-option-wrap-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/menulist-option-wrap-expected.png
deleted file mode 100644
index a45b545..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/menulist-option-wrap-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/targeted-frame-submission-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/targeted-frame-submission-expected.png
deleted file mode 100644
index 6b067a2..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/targeted-frame-submission-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/text/input-element-attach-crash-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/text/input-element-attach-crash-expected.txt
deleted file mode 100644
index ce9a6b2..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/text/input-element-attach-crash-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
- 
-PASS  
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/text/textfield-focus-ring-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/text/textfield-focus-ring-expected.png
deleted file mode 100644
index 9541b5f..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/text/textfield-focus-ring-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/textarea/basic-textareas-quirks-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/textarea/basic-textareas-quirks-expected.png
deleted file mode 100644
index 17796eb3..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/textarea/basic-textareas-quirks-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/validation-bubble-appearance-rtl-ui-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
deleted file mode 100644
index 3ad7384..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/frames/unique-name-set-same-name-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/frames/unique-name-set-same-name-expected.txt
deleted file mode 100644
index ec64759..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/frames/unique-name-set-same-name-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
---------
-Frame: '<!--framePath //<!--frame1-->-->'
---------
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/absolute-table-at-bottom-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/absolute-table-at-bottom-expected.png
deleted file mode 100644
index e392b0f..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/absolute-table-at-bottom-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/border-collapsing/border-collapsing-head-foot-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/border-collapsing/border-collapsing-head-foot-expected.png
deleted file mode 100644
index f07d81b5..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/border-collapsing/border-collapsing-head-foot-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/prepend-in-anonymous-table-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/prepend-in-anonymous-table-expected.png
deleted file mode 100644
index 0648084..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/prepend-in-anonymous-table-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/basic/013-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/basic/013-expected.png
deleted file mode 100644
index 580bb43..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/basic/013-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/basic/generic-family-changes-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/basic/generic-family-changes-expected.png
deleted file mode 100644
index 65506141..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/basic/generic-family-changes-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/font-ligature-letter-spacing-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/font-ligature-letter-spacing-expected.txt
deleted file mode 100644
index e0825d0..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/font-ligature-letter-spacing-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = 1 duplicate test name: "Ligature expected not to be applied due to letter spacing."
-FAIL Ligature expected not to be applied due to letter spacing. assert_equals: Ligature not applied due to letter spacing. expected 288 but got 140
-FAIL Ligature expected not to be applied due to letter spacing. assert_equals: Ligature not applied due to letter spacing. expected 288 but got 140
-PASS Non-ligature font feature expected to be applied despite letter spacing.
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/international/unicode-bidi-plaintext-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/international/unicode-bidi-plaintext-expected.png
deleted file mode 100644
index d22f2bd..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/international/unicode-bidi-plaintext-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/justify-nbsp-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/justify-nbsp-expected.png
deleted file mode 100644
index 7d698362..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/justify-nbsp-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/wbr-styled-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/wbr-styled-expected.png
deleted file mode 100644
index a1afecf6..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/wbr-styled-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/word-break-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/word-break-expected.png
deleted file mode 100644
index c0158ce..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/word-break-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/http/tests/cache/cached-main-resource-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/http/tests/cache/cached-main-resource-expected.txt
deleted file mode 100644
index 23985fc9..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/http/tests/cache/cached-main-resource-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-FAIL
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/http/tests/cache/iframe-304-crash-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/http/tests/cache/iframe-304-crash-expected.txt
deleted file mode 100644
index 78d1d6f..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/http/tests/cache/iframe-304-crash-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-http://127.0.0.1:8000/cache/resources/iframe304.php - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/cache/resources/iframe304.php, main document URL http://127.0.0.1:8000/cache/iframe-304-crash.html, http method GET>
-http://127.0.0.1:8000/cache/resources/iframe304.php - didReceiveResponse <NSURLResponse http://127.0.0.1:8000/cache/resources/iframe304.php, http status code 200>
-http://127.0.0.1:8000/cache/resources/iframe304.php - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/cache/resources/iframe304.php, main document URL http://127.0.0.1:8000/cache/iframe-304-crash.html, http method GET>
-http://127.0.0.1:8000/cache/resources/iframe304.php - didReceiveResponse <NSURLResponse http://127.0.0.1:8000/cache/resources/iframe304.php, http status code 200>
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/http/tests/misc/recreate-location-after-detach-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/http/tests/misc/recreate-location-after-detach-expected.txt
deleted file mode 100644
index 295cbe1..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/http/tests/misc/recreate-location-after-detach-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-We pass if we don't crash under ASAN. 
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/crash-bad-cast-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/crash-bad-cast-expected.txt
deleted file mode 100644
index 8d1c8b6..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/crash-bad-cast-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
- 
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-circle-focus-ring-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-circle-focus-ring-expected.png
deleted file mode 100644
index 4fd8b25e..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-circle-focus-ring-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-focus-ring-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-focus-ring-expected.png
deleted file mode 100644
index 033b006..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-focus-ring-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png
deleted file mode 100644
index 3247645f..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-focus-ring-zero-outline-width-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-focus-ring-zero-outline-width-expected.png
deleted file mode 100644
index a589e551..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-focus-ring-zero-outline-width-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-overflowing-circle-focus-ring-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-overflowing-circle-focus-ring-expected.png
deleted file mode 100644
index b6fa040..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-overflowing-circle-focus-ring-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-overflowing-polygon-focus-ring-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-overflowing-polygon-focus-ring-expected.png
deleted file mode 100644
index 5343ba786..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-overflowing-polygon-focus-ring-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-polygon-focus-ring-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-polygon-focus-ring-expected.png
deleted file mode 100644
index 93ff41d6..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/imagemap-polygon-focus-ring-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/W3C-SVG-1.1/text-align-01-b-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/W3C-SVG-1.1/text-align-01-b-expected.png
deleted file mode 100644
index ae0badf..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/W3C-SVG-1.1/text-align-01-b-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/text/text-selection-align-01-b-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/text/text-selection-align-01-b-expected.png
deleted file mode 100644
index fc074b87e..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/text/text-selection-align-01-b-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug17130-1-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug17130-1-expected.png
deleted file mode 100644
index 39d9b91..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug17130-1-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-circle-focus-ring-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-circle-focus-ring-expected.png
deleted file mode 100644
index 8ed8cf43..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-circle-focus-ring-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png
deleted file mode 100644
index fb7f7cb3e..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png
deleted file mode 100644
index 5aa5ea3e..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-focus-ring-zero-outline-width-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-focus-ring-zero-outline-width-expected.png
deleted file mode 100644
index 4f97cd1..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-focus-ring-zero-outline-width-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-overflowing-circle-focus-ring-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-overflowing-circle-focus-ring-expected.png
deleted file mode 100644
index d89962c..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-overflowing-circle-focus-ring-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png
deleted file mode 100644
index f5b85b9e..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png
deleted file mode 100644
index 8bfdb5b..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/mouseevent_fractional/fast/events/js-keyboard-event-creation-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/mouseevent_fractional/fast/events/js-keyboard-event-creation-expected.txt
deleted file mode 100644
index 505f2f7..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/mouseevent_fractional/fast/events/js-keyboard-event-creation-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
- 
-This tests that DOMKeyboardEvents are created correctly in the JavaScript API.
-
-keydown - key: Tab@DOM_KEY_LOCATION_STANDARD (keyCode/charCode: 9/0) modifiers: false,false,false,false
-
-keyup - key: Tab@DOM_KEY_LOCATION_STANDARD (keyCode/charCode: 9/0) modifiers: false,false,true,false
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/5138441-expected.png b/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/5138441-expected.png
deleted file mode 100644
index 5881e87..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/5138441-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/5138441-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/5138441-expected.txt
deleted file mode 100644
index 3ee5d482..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/5138441-expected.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow {P} at (0,0) size 784x60
-        LayoutText {#text} at (0,0) size 774x59
-          text run at (0,0) width 493: "This tests for a bug where indented text would appear quoted in GoogleDocs. "
-          text run at (493,0) width 218: "Google docs uses blockquotes and"
-          text run at (0,20) width 774: "FormatBlock to implement a \"Quote Text\" feature, and style rules for blockquotes appeared on the blockquotes that we use"
-          text run at (0,40) width 149: "to implement indenting."
-      LayoutBlockFlow {DIV} at (0,76) size 784x66
-        LayoutBlockFlow {BLOCKQUOTE} at (40,0) size 744x20
-          LayoutBlockFlow {DIV} at (0,0) size 744x20
-            LayoutText {#text} at (0,0) size 230x19
-              text run at (0,0) width 230: "This should be indented, not quoted."
-        LayoutBlockFlow {BLOCKQUOTE} at (8,28) size 768x38 [border: (1px dashed #AAAAAA)]
-          LayoutText {#text} at (9,9) size 175x19
-            text run at (9,9) width 175: "This text should be Quoted."
-caret: position 0 of child 0 {#text} of child 0 {DIV} of child 1 {BLOCKQUOTE} of child 3 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/5569741-expected.png b/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/5569741-expected.png
deleted file mode 100644
index 3ae430c..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/5569741-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/5569741-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/5569741-expected.txt
deleted file mode 100644
index 2298485..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/5569741-expected.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x576
-      LayoutBlockFlow {P} at (0,0) size 784x20
-        LayoutText {#text} at (0,0) size 681x19
-          text run at (0,0) width 681: "This tests for a bug where hitting return inside an empty paragraph in a non-empty list item would remove it."
-      LayoutBlockFlow {DIV} at (0,36) size 784x60
-        LayoutBlockFlow {UL} at (0,0) size 784x60
-          LayoutListItem {LI} at (40,0) size 744x40
-            LayoutListMarker (anonymous) at (-18,0) size 7x19: bullet
-            LayoutText {#text} at (0,0) size 21x19
-              text run at (0,0) width 21: "foo"
-            LayoutBR {BR} at (21,15) size 0x0
-            LayoutBR {BR} at (0,20) size 0x19
-          LayoutListItem {LI} at (40,40) size 744x20
-            LayoutListMarker (anonymous) at (-18,0) size 7x19: bullet
-            LayoutBR {BR} at (0,0) size 0x19
-caret: position 0 of child 0 {BR} of child 1 {LI} of child 1 {UL} of child 2 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/remove-list-from-range-selection-expected.png b/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/remove-list-from-range-selection-expected.png
deleted file mode 100644
index 27f2342..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/remove-list-from-range-selection-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/remove-list-from-range-selection-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/remove-list-from-range-selection-expected.txt
deleted file mode 100644
index 63e662b5..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/editing/execCommand/remove-list-from-range-selection-expected.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x576
-      LayoutBlockFlow {P} at (0,0) size 784x20
-        LayoutText {#text} at (0,0) size 528x19
-          text run at (0,0) width 528: "This tests Insert{Un}OrderedList on a range selection that is entirely within one list."
-      LayoutBlockFlow {DIV} at (0,36) size 784x116
-        LayoutBlockFlow (anonymous) at (0,0) size 784x80
-          LayoutText {#text} at (0,0) size 75x19
-            text run at (0,0) width 75: "None of the"
-          LayoutBR {BR} at (75,15) size 0x0
-          LayoutText {#text} at (0,20) size 100x19
-            text run at (0,20) width 100: "selected content"
-          LayoutBR {BR} at (100,35) size 0x0
-          LayoutText {#text} at (0,40) size 61x19
-            text run at (0,40) width 61: "should be"
-          LayoutBR {BR} at (61,55) size 0x0
-          LayoutText {#text} at (0,60) size 49x19
-            text run at (0,60) width 49: "in a list."
-          LayoutBR {BR} at (49,75) size 0x0
-        LayoutBlockFlow {OL} at (0,96) size 784x20
-          LayoutListItem {LI} at (40,0) size 744x20
-            LayoutListMarker (anonymous) at (-16,0) size 16x19: "1"
-            LayoutText {#text} at (0,0) size 316x19
-              text run at (0,0) width 316: "This should be in a list and should not be selected."
-selection start: position 2 of child 0 {#text} of child 2 {DIV} of body
-selection end:   position 2 of child 6 {#text} of child 2 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/5138441-expected.png b/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/5138441-expected.png
deleted file mode 100644
index d3b4fe3..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/5138441-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/5138441-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/5138441-expected.txt
deleted file mode 100644
index 91c4e907..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/5138441-expected.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow {P} at (0,0) size 784x54
-        LayoutText {#text} at (0,0) size 763x54
-          text run at (0,0) width 500: "This tests for a bug where indented text would appear quoted in GoogleDocs. "
-          text run at (499,0) width 221: "Google docs uses blockquotes and"
-          text run at (0,18) width 763: "FormatBlock to implement a \"Quote Text\" feature, and style rules for blockquotes appeared on the blockquotes that we"
-          text run at (0,36) width 179: "use to implement indenting."
-      LayoutBlockFlow {DIV} at (0,70) size 784x62
-        LayoutBlockFlow {BLOCKQUOTE} at (40,0) size 744x18
-          LayoutBlockFlow {DIV} at (0,0) size 744x18
-            LayoutText {#text} at (0,0) size 234x18
-              text run at (0,0) width 234: "This should be indented, not quoted."
-        LayoutBlockFlow {BLOCKQUOTE} at (8,26) size 768x36 [border: (1px dashed #AAAAAA)]
-          LayoutText {#text} at (9,9) size 178x18
-            text run at (9,9) width 178: "This text should be Quoted."
-caret: position 0 of child 0 {#text} of child 0 {DIV} of child 1 {BLOCKQUOTE} of child 3 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/5569741-expected.png b/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/5569741-expected.png
deleted file mode 100644
index bd57e3b5..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/5569741-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/5569741-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/5569741-expected.txt
deleted file mode 100644
index 06f76c3c..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/5569741-expected.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x576
-      LayoutBlockFlow {P} at (0,0) size 784x18
-        LayoutText {#text} at (0,0) size 697x18
-          text run at (0,0) width 697: "This tests for a bug where hitting return inside an empty paragraph in a non-empty list item would remove it."
-      LayoutBlockFlow {DIV} at (0,34) size 784x54
-        LayoutBlockFlow {UL} at (0,0) size 784x54
-          LayoutListItem {LI} at (40,0) size 744x36
-            LayoutListMarker (anonymous) at (-17,0) size 7x18: bullet
-            LayoutText {#text} at (0,0) size 22x18
-              text run at (0,0) width 22: "foo"
-            LayoutBR {BR} at (21,14) size 1x0
-            LayoutBR {BR} at (0,18) size 0x18
-          LayoutListItem {LI} at (40,36) size 744x18
-            LayoutListMarker (anonymous) at (-17,0) size 7x18: bullet
-            LayoutBR {BR} at (0,0) size 0x18
-caret: position 0 of child 0 {BR} of child 1 {LI} of child 1 {UL} of child 2 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/remove-list-from-range-selection-expected.png b/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/remove-list-from-range-selection-expected.png
deleted file mode 100644
index fd22425..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/remove-list-from-range-selection-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/remove-list-from-range-selection-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/remove-list-from-range-selection-expected.txt
deleted file mode 100644
index fccfeb4..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/editing/execCommand/remove-list-from-range-selection-expected.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x576
-      LayoutBlockFlow {P} at (0,0) size 784x18
-        LayoutText {#text} at (0,0) size 541x18
-          text run at (0,0) width 541: "This tests Insert{Un}OrderedList on a range selection that is entirely within one list."
-      LayoutBlockFlow {DIV} at (0,34) size 784x106
-        LayoutBlockFlow (anonymous) at (0,0) size 784x72
-          LayoutText {#text} at (0,0) size 76x18
-            text run at (0,0) width 76: "None of the"
-          LayoutBR {BR} at (75,14) size 1x0
-          LayoutText {#text} at (0,18) size 103x18
-            text run at (0,18) width 103: "selected content"
-          LayoutBR {BR} at (102,32) size 1x0
-          LayoutText {#text} at (0,36) size 62x18
-            text run at (0,36) width 62: "should be"
-          LayoutBR {BR} at (61,50) size 1x0
-          LayoutText {#text} at (0,54) size 52x18
-            text run at (0,54) width 52: "in a list."
-          LayoutBR {BR} at (51,68) size 1x0
-        LayoutBlockFlow {OL} at (0,88) size 784x18
-          LayoutListItem {LI} at (40,0) size 744x18
-            LayoutListMarker (anonymous) at (-16,0) size 16x18: "1"
-            LayoutText {#text} at (0,0) size 323x18
-              text run at (0,0) width 323: "This should be in a list and should not be selected."
-selection start: position 2 of child 0 {#text} of child 2 {DIV} of body
-selection end:   position 2 of child 6 {#text} of child 2 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/5138441-expected.png b/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/5138441-expected.png
deleted file mode 100644
index 52506f6..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/5138441-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/5138441-expected.txt b/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/5138441-expected.txt
deleted file mode 100644
index 3e4744d..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/5138441-expected.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow {P} at (0,0) size 784x60
-        LayoutText {#text} at (0,0) size 782x59
-          text run at (0,0) width 471: "This tests for a bug where indented text would appear quoted in GoogleDocs. "
-          text run at (471,0) width 311: "Google docs uses blockquotes and FormatBlock to"
-          text run at (0,20) width 724: "implement a \"Quote Text\" feature, and style rules for blockquotes appeared on the blockquotes that we use to implement"
-          text run at (0,40) width 57: "indenting."
-      LayoutBlockFlow {DIV} at (0,76) size 784x66
-        LayoutBlockFlow {BLOCKQUOTE} at (40,0) size 744x20
-          LayoutBlockFlow {DIV} at (0,0) size 744x20
-            LayoutText {#text} at (0,0) size 219x19
-              text run at (0,0) width 219: "This should be indented, not quoted."
-        LayoutBlockFlow {BLOCKQUOTE} at (8,28) size 768x38 [border: (1px dashed #AAAAAA)]
-          LayoutText {#text} at (9,9) size 167x19
-            text run at (9,9) width 167: "This text should be Quoted."
-caret: position 0 of child 0 {#text} of child 0 {DIV} of child 1 {BLOCKQUOTE} of child 3 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/5569741-expected.png b/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/5569741-expected.png
deleted file mode 100644
index c17cd31..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/5569741-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/5569741-expected.txt b/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/5569741-expected.txt
deleted file mode 100644
index 669fe38..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/5569741-expected.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x576
-      LayoutBlockFlow {P} at (0,0) size 784x20
-        LayoutText {#text} at (0,0) size 643x19
-          text run at (0,0) width 643: "This tests for a bug where hitting return inside an empty paragraph in a non-empty list item would remove it."
-      LayoutBlockFlow {DIV} at (0,36) size 784x60
-        LayoutBlockFlow {UL} at (0,0) size 784x60
-          LayoutListItem {LI} at (40,0) size 744x40
-            LayoutListMarker (anonymous) at (-18,0) size 7x19: bullet
-            LayoutText {#text} at (0,0) size 20x19
-              text run at (0,0) width 20: "foo"
-            LayoutBR {BR} at (20,15) size 0x0
-            LayoutBR {BR} at (0,20) size 0x19
-          LayoutListItem {LI} at (40,40) size 744x20
-            LayoutListMarker (anonymous) at (-18,0) size 7x19: bullet
-            LayoutBR {BR} at (0,0) size 0x19
-caret: position 0 of child 0 {BR} of child 1 {LI} of child 1 {UL} of child 2 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/remove-list-from-range-selection-expected.png b/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/remove-list-from-range-selection-expected.png
deleted file mode 100644
index b3e7eca..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/remove-list-from-range-selection-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/remove-list-from-range-selection-expected.txt b/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/remove-list-from-range-selection-expected.txt
deleted file mode 100644
index 76f1f734..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/editing/execCommand/remove-list-from-range-selection-expected.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x576
-      LayoutBlockFlow {P} at (0,0) size 784x20
-        LayoutText {#text} at (0,0) size 499x19
-          text run at (0,0) width 499: "This tests Insert{Un}OrderedList on a range selection that is entirely within one list."
-      LayoutBlockFlow {DIV} at (0,36) size 784x116
-        LayoutBlockFlow (anonymous) at (0,0) size 784x80
-          LayoutText {#text} at (0,0) size 72x19
-            text run at (0,0) width 72: "None of the"
-          LayoutBR {BR} at (72,15) size 0x0
-          LayoutText {#text} at (0,20) size 97x19
-            text run at (0,20) width 97: "selected content"
-          LayoutBR {BR} at (97,35) size 0x0
-          LayoutText {#text} at (0,40) size 58x19
-            text run at (0,40) width 58: "should be"
-          LayoutBR {BR} at (58,55) size 0x0
-          LayoutText {#text} at (0,60) size 45x19
-            text run at (0,60) width 45: "in a list."
-          LayoutBR {BR} at (45,75) size 0x0
-        LayoutBlockFlow {OL} at (0,96) size 784x20
-          LayoutListItem {LI} at (40,0) size 744x20
-            LayoutListMarker (anonymous) at (-16,0) size 16x19: "1"
-            LayoutText {#text} at (0,0) size 300x19
-              text run at (0,0) width 300: "This should be in a list and should not be selected."
-selection start: position 2 of child 0 {#text} of child 2 {DIV} of body
-selection end:   position 2 of child 6 {#text} of child 2 {DIV} of body
diff --git a/third_party/WebKit/Source/build/scripts/templates/make_names.cc.tmpl b/third_party/WebKit/Source/build/scripts/templates/make_names.cc.tmpl
index ac274edcdcd..3e8cde9 100644
--- a/third_party/WebKit/Source/build/scripts/templates/make_names.cc.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/make_names.cc.tmpl
@@ -10,8 +10,6 @@
 namespace blink {
 namespace {{namespace}}Names {
 
-using namespace WTF;
-
 void* {{suffix}}NamesStorage[{{namespace}}{{suffix}}NamesCount * ((sizeof(AtomicString) + sizeof(void *) - 1) / sizeof(void *))];
 
 {% for entry in entries|sort(attribute='name', case_sensitive=True) %}
diff --git a/third_party/WebKit/Source/core/animation/OWNERS b/third_party/WebKit/Source/core/animation/OWNERS
index 5e43ed4..b763135 100644
--- a/third_party/WebKit/Source/core/animation/OWNERS
+++ b/third_party/WebKit/Source/core/animation/OWNERS
@@ -5,6 +5,8 @@
 alancutter@chromium.org
 ericwilligers@chromium.org
 
+per-file compositor_*=loyso@chromium.org
+# TODO(tkent): Remove a per-file line for a CamelCase pattern.
 per-file Compositor*=loyso@chromium.org
 
 # TEAM: animations-dev@chromium.org
diff --git a/third_party/WebKit/Source/core/css/MediaList.cpp b/third_party/WebKit/Source/core/css/MediaList.cpp
index 78c6963..dc5e2f3 100644
--- a/third_party/WebKit/Source/core/css/MediaList.cpp
+++ b/third_party/WebKit/Source/core/css/MediaList.cpp
@@ -82,7 +82,7 @@
 
   // Only continue if exactly one media query is found, as described above.
   if (result->queries_.size() != 1)
-    return true;
+    return false;
 
   std::unique_ptr<MediaQuery> new_query = std::move(result->queries_[0]);
   // TODO(keishi) Changed DCHECK to CHECK for crbug.com/699269 diagnosis
@@ -93,7 +93,7 @@
   for (size_t i = 0; i < queries_.size(); ++i) {
     MediaQuery& query = *queries_[i];
     if (query == *new_query)
-      return true;
+      return false;
   }
 
   queries_.push_back(std::move(new_query));
@@ -192,17 +192,12 @@
     parent_style_sheet_->DidMutate();
 }
 
-void MediaList::appendMedium(const String& medium,
-                             ExceptionState& exception_state) {
+void MediaList::appendMedium(const String& medium) {
   CSSStyleSheet::RuleMutationScope mutation_scope(parent_rule_);
 
-  bool success = media_queries_->Add(medium);
-  if (!success) {
-    exception_state.ThrowDOMException(
-        kInvalidCharacterError,
-        "The value provided ('" + medium + "') is not a valid medium.");
+  bool added = media_queries_->Add(medium);
+  if (!added)
     return;
-  }
 
   if (parent_style_sheet_)
     parent_style_sheet_->DidMutate();
diff --git a/third_party/WebKit/Source/core/css/MediaList.h b/third_party/WebKit/Source/core/css/MediaList.h
index 953b61f..c574dae 100644
--- a/third_party/WebKit/Source/core/css/MediaList.h
+++ b/third_party/WebKit/Source/core/css/MediaList.h
@@ -86,7 +86,7 @@
   unsigned length() const { return media_queries_->QueryVector().size(); }
   String item(unsigned index) const;
   void deleteMedium(const String& old_medium, ExceptionState&);
-  void appendMedium(const String& new_medium, ExceptionState&);
+  void appendMedium(const String& new_medium);
 
   String mediaText() const { return media_queries_->MediaText(); }
   void setMediaText(const String&);
diff --git a/third_party/WebKit/Source/core/css/MediaList.idl b/third_party/WebKit/Source/core/css/MediaList.idl
index 1c20b6a..1980425 100644
--- a/third_party/WebKit/Source/core/css/MediaList.idl
+++ b/third_party/WebKit/Source/core/css/MediaList.idl
@@ -32,7 +32,6 @@
     stringifier attribute [TreatNullAs=EmptyString] DOMString mediaText;
     readonly attribute unsigned long length;
     [Measure] getter DOMString? item(unsigned long index);
-    // TODO(foolip): appendMedium() and deleteMedium() should never throw.
-    [RaisesException] void appendMedium(DOMString medium);
+    void appendMedium(DOMString medium);
     [RaisesException] void deleteMedium(DOMString medium);
 };
diff --git a/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp b/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp
index cf74fef..e09af07 100644
--- a/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp
+++ b/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp
@@ -376,10 +376,13 @@
       }
     }
     if (success) {
-      if (longhands[0]->IsPendingSubstitutionValue())
-        return ToCSSPendingSubstitutionValue(longhands[0])
-            ->ShorthandValue()
-            ->CssText();
+      if (longhands[0]->IsPendingSubstitutionValue()) {
+        const CSSPendingSubstitutionValue* substitution_value =
+            ToCSSPendingSubstitutionValue(longhands[0]);
+        if (substitution_value->ShorthandPropertyId() != shorthand.id())
+          return g_empty_string;
+        return substitution_value->ShorthandValue()->CssText();
+      }
       return longhands[0]->CssText();
     }
   }
diff --git a/third_party/WebKit/Source/core/dom/FirstLetterPseudoElement.cpp b/third_party/WebKit/Source/core/dom/FirstLetterPseudoElement.cpp
index 60aa2a36..79d4f80 100644
--- a/third_party/WebKit/Source/core/dom/FirstLetterPseudoElement.cpp
+++ b/third_party/WebKit/Source/core/dom/FirstLetterPseudoElement.cpp
@@ -37,24 +37,21 @@
 
 namespace blink {
 
-using namespace WTF;
-using namespace Unicode;
-
 // CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter "Punctuation
 // (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close"
 // (Pe), "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes),
 // that precedes or follows the first letter should be included"
 static inline bool IsPunctuationForFirstLetter(UChar32 c) {
-  CharCategory char_category = Category(c);
-  return char_category == kPunctuation_Open ||
-         char_category == kPunctuation_Close ||
-         char_category == kPunctuation_InitialQuote ||
-         char_category == kPunctuation_FinalQuote ||
-         char_category == kPunctuation_Other;
+  WTF::Unicode::CharCategory char_category = WTF::Unicode::Category(c);
+  return char_category == WTF::Unicode::kPunctuation_Open ||
+         char_category == WTF::Unicode::kPunctuation_Close ||
+         char_category == WTF::Unicode::kPunctuation_InitialQuote ||
+         char_category == WTF::Unicode::kPunctuation_FinalQuote ||
+         char_category == WTF::Unicode::kPunctuation_Other;
 }
 
 static inline bool IsSpaceForFirstLetter(UChar c) {
-  return IsSpaceOrNewline(c) || c == kNoBreakSpaceCharacter;
+  return IsSpaceOrNewline(c) || c == WTF::Unicode::kNoBreakSpaceCharacter;
 }
 
 unsigned FirstLetterPseudoElement::FirstLetterLength(const String& text) {
diff --git a/third_party/WebKit/Source/core/dom/OWNERS b/third_party/WebKit/Source/core/dom/OWNERS
index b65c13b..b31578c 100644
--- a/third_party/WebKit/Source/core/dom/OWNERS
+++ b/third_party/WebKit/Source/core/dom/OWNERS
@@ -1,6 +1,9 @@
 hayato@chromium.org
 tkent@chromium.org
 
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+# TODO(tkent): Remove per-file lines for CamelCase patterns.
 per-file *StructTraits*.*=set noparent
 per-file *StructTraits*.*=file://ipc/SECURITY_OWNERS
 per-file *.typemap=set noparent
diff --git a/third_party/WebKit/Source/core/dom/SlotAssignment.cpp b/third_party/WebKit/Source/core/dom/SlotAssignment.cpp
index 6479459f..e193ebf8 100644
--- a/third_party/WebKit/Source/core/dom/SlotAssignment.cpp
+++ b/third_party/WebKit/Source/core/dom/SlotAssignment.cpp
@@ -213,7 +213,7 @@
   }
 }
 
-void SlotAssignment::RecalcAssignmentNg() {
+void SlotAssignment::RecalcAssignment() {
   DCHECK(RuntimeEnabledFeatures::IncrementalShadowDOMEnabled());
 
   if (!needs_assignment_recalc_)
@@ -265,7 +265,7 @@
     slot->RecalcFlatTreeChildren();
 }
 
-void SlotAssignment::RecalcAssignment() {
+void SlotAssignment::RecalcAssignmentForDistribution() {
   DCHECK(!RuntimeEnabledFeatures::IncrementalShadowDOMEnabled());
 
   for (Member<HTMLSlotElement> slot : Slots())
@@ -309,7 +309,7 @@
 void SlotAssignment::RecalcDistribution() {
   DCHECK(!RuntimeEnabledFeatures::IncrementalShadowDOMEnabled());
 
-  RecalcAssignment();
+  RecalcAssignmentForDistribution();
   const HeapVector<Member<HTMLSlotElement>>& slots = Slots();
 
   for (auto slot : slots)
diff --git a/third_party/WebKit/Source/core/dom/SlotAssignment.h b/third_party/WebKit/Source/core/dom/SlotAssignment.h
index 9178451..d71c0b9 100644
--- a/third_party/WebKit/Source/core/dom/SlotAssignment.h
+++ b/third_party/WebKit/Source/core/dom/SlotAssignment.h
@@ -37,7 +37,6 @@
   // Instead, provide alternative, HTMLSlotElement::hasAssignedNodesSlow()
   // so that slotchange can be detected.
 
-  void RecalcDistribution();
   const HeapVector<Member<HTMLSlotElement>>& Slots();
 
   void DidAddSlot(HTMLSlotElement&);
@@ -48,14 +47,15 @@
 
   bool FindHostChildBySlotName(const AtomicString& slot_name) const;
 
-  void SetNeedsAssignmentRecalc();
-
-  // For Incremental Shadow DOM
-  void RecalcAssignmentNg();
-
   void Trace(blink::Visitor*);
 
+  // For Incremental Shadow DOM
   bool NeedsAssignmentRecalc() const { return needs_assignment_recalc_; }
+  void SetNeedsAssignmentRecalc();
+  void RecalcAssignment();
+
+  // For Non-Incremental Shadow DOM
+  void RecalcDistribution();
 
  private:
   explicit SlotAssignment(ShadowRoot& owner);
@@ -71,13 +71,14 @@
   HTMLSlotElement* GetCachedFirstSlotWithoutAccessingNodeTree(
       const AtomicString& slot_name);
 
-  void RecalcAssignment();
-
   void DidAddSlotInternal(HTMLSlotElement&);
   void DidRemoveSlotInternal(HTMLSlotElement&,
                              const AtomicString& slot_name,
                              SlotMutationType);
 
+  // For Non-Incremental Shadow DOM
+  void RecalcAssignmentForDistribution();
+
   HeapVector<Member<HTMLSlotElement>> slots_;
   Member<TreeOrderedMap> slot_map_;
   WeakMember<ShadowRoot> owner_;
diff --git a/third_party/WebKit/Source/core/dom/ng/slot_assignment_engine.cc b/third_party/WebKit/Source/core/dom/ng/slot_assignment_engine.cc
index a2cd2f13..98e886d 100644
--- a/third_party/WebKit/Source/core/dom/ng/slot_assignment_engine.cc
+++ b/third_party/WebKit/Source/core/dom/ng/slot_assignment_engine.cc
@@ -44,9 +44,9 @@
        HeapHashSet<WeakMember<ShadowRoot>>(shadow_roots_needing_recalc_)) {
     DCHECK(shadow_root->isConnected());
     DCHECK(shadow_root->NeedsSlotAssignmentRecalc());
-    // SlotAssignment::RecalcAssignmentNg() will remove its shadow root from
+    // SlotAssignment::RecalcAssignment() will remove its shadow root from
     // shadow_roots_needing_recalc_.
-    shadow_root->GetSlotAssignment().RecalcAssignmentNg();
+    shadow_root->GetSlotAssignment().RecalcAssignment();
   }
   DCHECK(shadow_roots_needing_recalc_.IsEmpty());
 }
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp
index ed92af8..0fe6b46c 100644
--- a/third_party/WebKit/Source/core/editing/Editor.cpp
+++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -94,8 +94,6 @@
 namespace blink {
 
 using namespace HTMLNames;
-using namespace WTF;
-using namespace Unicode;
 
 namespace {
 
diff --git a/third_party/WebKit/Source/core/editing/InlineBoxPosition.cpp b/third_party/WebKit/Source/core/editing/InlineBoxPosition.cpp
index 2813755b..43b82b02 100644
--- a/third_party/WebKit/Source/core/editing/InlineBoxPosition.cpp
+++ b/third_party/WebKit/Source/core/editing/InlineBoxPosition.cpp
@@ -162,6 +162,9 @@
   if (inline_box->Direction() == primary_direction)
     return AdjustInlineBoxPositionForPrimaryDirection(inline_box, caret_offset);
 
+  if (unicode_bidi == UnicodeBidi::kPlaintext)
+    return InlineBoxPosition(inline_box, caret_offset);
+
   const unsigned char level = inline_box->BidiLevel();
   if (caret_offset == inline_box->CaretLeftmostOffset()) {
     InlineBox* const prev_box = inline_box->PrevLeafChildIgnoringLineBreak();
@@ -183,9 +186,6 @@
     return InlineBoxPosition(result_box, result_box->CaretLeftmostOffset());
   }
 
-  if (unicode_bidi == UnicodeBidi::kPlaintext)
-    return InlineBoxPosition(inline_box, inline_box->CaretRightmostOffset());
-
   InlineBox* const next_box = inline_box->NextLeafChildIgnoringLineBreak();
   if (!next_box || next_box->BidiLevel() < level) {
     // Right edge of a secondary run. Set to the left edge of the entire
diff --git a/third_party/WebKit/Source/core/editing/LocalCaretRectTest.cpp b/third_party/WebKit/Source/core/editing/LocalCaretRectTest.cpp
index afb0936..80cb117 100644
--- a/third_party/WebKit/Source/core/editing/LocalCaretRectTest.cpp
+++ b/third_party/WebKit/Source/core/editing/LocalCaretRectTest.cpp
@@ -915,4 +915,15 @@
             position_rect);
   EXPECT_EQ(LayoutRect(299, 10, 1, 10), visible_position_rect);
 };
+
+TEST_P(ParameterizedLocalCaretRectTest,
+       UnicodeBidiPlaintextWithDifferentBlockDirection) {
+  LoadAhem();
+  InsertStyleElement("div { font: 10px/10px Ahem; unicode-bidi: plaintext }");
+  const Position position = SetCaretTextToBody("<div dir='rtl'>|abc</div>");
+  const LayoutRect caret_rect =
+      LocalCaretRectOfPosition(PositionWithAffinity(position)).rect;
+  EXPECT_EQ(LayoutRect(0, 0, 1, 10), caret_rect);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/exported/WebFrameContentDumper.cpp b/third_party/WebKit/Source/core/exported/WebFrameContentDumper.cpp
index 5545e17..d717be19 100644
--- a/third_party/WebKit/Source/core/exported/WebFrameContentDumper.cpp
+++ b/third_party/WebKit/Source/core/exported/WebFrameContentDumper.cpp
@@ -59,11 +59,11 @@
 // whitespace characters are left as-is, without any collapsing or conversion.
 // For example, from HTML <p>\na\n\nb\n</p>, we get text dump "a\n\nb".
 // [*] https://developer.mozilla.org/en-US/docs/Web/API/Node/innerText
-class InnerTextDumper final {
+class TextDumper final {
   STACK_ALLOCATED();
 
  public:
-  InnerTextDumper(StringBuilder& builder, size_t max_length)
+  TextDumper(StringBuilder& builder, size_t max_length)
       : builder_(builder), max_length_(max_length) {}
 
   void DumpTextFrom(const Node& node) {
@@ -155,85 +155,11 @@
   StringBuilder& builder_;
   const size_t max_length_;
 
-  DISALLOW_COPY_AND_ASSIGN(InnerTextDumper);
+  DISALLOW_COPY_AND_ASSIGN(TextDumper);
 };
 
-bool TextContentDumperIgnoresElement(const Element& element) {
-  return IsHTMLStyleElement(element) || IsHTMLScriptElement(element) ||
-         IsHTMLNoScriptElement(element);
-}
-
-bool IsWhiteSpace(UChar ch) {
-  return ch == ' ' || ch == '\n' || ch == '\t';
-}
-
-// This class dumps textContent of a node into a StringBuilder, with the minor
-// exception that text nodes in certain elements are ignored (See
-// TextContentDumperIgnoresElement()), and consucetive whitespace characters are
-// collapsed regardless of style.
-// Note: This dumper is for TranslateHelper only. Do not use for other purposes!
-class TextContentDumper {
-  STACK_ALLOCATED();
-
- public:
-  TextContentDumper(StringBuilder& builder, size_t max_length)
-      : builder_(builder), max_length_(max_length) {}
-
-  void DumpTextFrom(const Element& element) { HandleElement(element, 0); }
-
- private:
-  void HandleElement(const Element& element, unsigned depth) {
-    if (depth == text_dumper_max_depth)
-      return;
-    if (TextContentDumperIgnoresElement(element))
-      return;
-
-    for (const Node& child : NodeTraversal::ChildrenOf(element)) {
-      if (child.IsElementNode()) {
-        HandleElement(ToElement(child), depth + 1);
-        continue;
-      }
-
-      if (!child.IsTextNode())
-        continue;
-
-      HandleTextNode(ToText(child));
-      if (builder_.length() >= max_length_)
-        return;
-    }
-  }
-
-  void HandleTextNode(const Text& node) {
-    for (unsigned i = 0;
-         i < node.data().length() && builder_.length() < max_length_; ++i) {
-      UChar ch = node.data()[i];
-      if (ShouldAppendCharacter(ch))
-        builder_.Append(ch);
-    }
-  }
-
-  bool ShouldAppendCharacter(UChar ch) const {
-    if (!IsWhiteSpace(ch))
-      return true;
-    if (builder_.IsEmpty())
-      return true;
-    if (!IsWhiteSpace(builder_[builder_.length() - 1]))
-      return true;
-    return false;
-  }
-
-  StringBuilder& builder_;
-  const size_t max_length_;
-
-  DISALLOW_COPY_AND_ASSIGN(TextContentDumper);
-};
-
-// Controls which text dumper to use: TextContentDumper or InnerTextDumper.
-enum TextDumpOption { kDumpTextContent, kDumpInnerText };
-
 void FrameContentAsPlainText(size_t max_chars,
                              LocalFrame* frame,
-                             TextDumpOption option,
                              StringBuilder& output) {
   Document* document = frame->GetDocument();
   if (!document)
@@ -242,21 +168,11 @@
   if (!frame->View() || frame->View()->ShouldThrottleRendering())
     return;
 
-  if (option == TextDumpOption::kDumpInnerText) {
-    // Dumping inner text requires clean layout
-    DCHECK(!frame->View()->NeedsLayout());
-    DCHECK(!document->NeedsLayoutTreeUpdate());
-  }
+  DCHECK(!frame->View()->NeedsLayout());
+  DCHECK(!document->NeedsLayoutTreeUpdate());
 
-  if (document->documentElement()) {
-    if (option == TextDumpOption::kDumpInnerText) {
-      InnerTextDumper(output, max_chars)
-          .DumpTextFrom(*document->documentElement());
-    } else {
-      TextContentDumper(output, max_chars)
-          .DumpTextFrom(*document->documentElement());
-    }
-  }
+  if (document->documentElement())
+    TextDumper(output, max_chars).DumpTextFrom(*document->documentElement());
 
   // The separator between frames when the frames are converted to plain text.
   const LChar kFrameSeparator[] = {'\n', '\n'};
@@ -269,19 +185,16 @@
     if (!cur_child->IsLocalFrame())
       continue;
     LocalFrame* cur_local_child = ToLocalFrame(cur_child);
-    // When dumping inner text, ignore the text of non-visible frames.
-    if (option == TextDumpOption::kDumpInnerText) {
-      LayoutView* layout_view = cur_local_child->ContentLayoutObject();
-      LayoutObject* owner_layout_object = cur_local_child->OwnerLayoutObject();
-      if (!layout_view || !layout_view->Size().Width() ||
-          !layout_view->Size().Height() ||
-          (layout_view->Location().X() + layout_view->Size().Width() <= 0) ||
-          (layout_view->Location().Y() + layout_view->Size().Height() <= 0) ||
-          (owner_layout_object && owner_layout_object->Style() &&
-           owner_layout_object->Style()->Visibility() !=
-               EVisibility::kVisible)) {
-        continue;
-      }
+    // Ignore the text of non-visible frames.
+    LayoutView* layout_view = cur_local_child->ContentLayoutObject();
+    LayoutObject* owner_layout_object = cur_local_child->OwnerLayoutObject();
+    if (!layout_view || !layout_view->Size().Width() ||
+        !layout_view->Size().Height() ||
+        (layout_view->Location().X() + layout_view->Size().Width() <= 0) ||
+        (layout_view->Location().Y() + layout_view->Size().Height() <= 0) ||
+        (owner_layout_object && owner_layout_object->Style() &&
+         owner_layout_object->Style()->Visibility() != EVisibility::kVisible)) {
+      continue;
     }
 
     // Make sure the frame separator won't fill up the buffer, and give up if
@@ -293,7 +206,7 @@
       return;
 
     output.Append(kFrameSeparator, frame_separator_length);
-    FrameContentAsPlainText(max_chars, cur_local_child, option, output);
+    FrameContentAsPlainText(max_chars, cur_local_child, output);
     if (output.length() >= max_chars)
       return;  // Filled up the buffer.
   }
@@ -308,7 +221,7 @@
     return WebString();
   StringBuilder text;
   FrameContentAsPlainText(max_chars, ToWebLocalFrameImpl(frame)->GetFrame(),
-                          TextDumpOption::kDumpTextContent, text);
+                          text);
   return text.ToString();
 }
 
@@ -323,7 +236,7 @@
 
   StringBuilder text;
   FrameContentAsPlainText(max_chars, ToWebLocalFrameImpl(frame)->GetFrame(),
-                          TextDumpOption::kDumpInnerText, text);
+                          text);
   return text.ToString();
 }
 
diff --git a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
index 608f8fae..fc812d04 100644
--- a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
@@ -4986,29 +4986,6 @@
   EXPECT_EQ("Hello world", text.Utf8());
 }
 
-// Verifies that ChromeRenderFrameObserver::CapturePageText can get page text
-// with WebFrameContentDumper::DeprecatedDumpFrameTreeAsText() in dirty layout.
-TEST_P(ParameterizedWebFrameTest, CapturePageTextWithDirtyLayout) {
-  FrameTestHelpers::WebViewHelper web_view_helper;
-  web_view_helper.InitializeAndLoad("about:blank");
-
-  WebLocalFrame* frame = web_view_helper.LocalMainFrame();
-  Document* document = frame->GetDocument();
-  Element* body = document->body();
-
-  // Change the document innerHTML, which dirties layout.
-  const char* new_html = "<div>Foo bar</div><div></div>baz";
-  body->SetInnerHTMLFromString(new_html);
-
-  // Verifies that text capturing works on dirty layout.
-  // Note that we must call the deprecated function here to simulate the
-  // behavior of ChromeRenderFrameObserver::CapturePageText().
-  EXPECT_TRUE(document->NeedsLayoutTreeUpdate());
-  EXPECT_EQ(
-      "Foo barbaz",
-      WebFrameContentDumper::DeprecatedDumpFrameTreeAsText(frame, 12).Utf8());
-}
-
 TEST_P(ParameterizedWebFrameTest, GetFullHtmlOfPage) {
   FrameTestHelpers::WebViewHelper web_view_helper;
   web_view_helper.InitializeAndLoad("about:blank");
diff --git a/third_party/WebKit/Source/core/html/HTMLElement.cpp b/third_party/WebKit/Source/core/html/HTMLElement.cpp
index b498d61..e3345bf 100644
--- a/third_party/WebKit/Source/core/html/HTMLElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLElement.cpp
@@ -76,7 +76,6 @@
 
 using namespace cssvalue;
 using namespace HTMLNames;
-using namespace WTF;
 
 using namespace std;
 
diff --git a/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp b/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
index cca6437..7d5ca49e 100644
--- a/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
@@ -103,7 +103,7 @@
     return assigned_nodes_;
   }
   if (RuntimeEnabledFeatures::IncrementalShadowDOMEnabled()) {
-    ContainingShadowRoot()->GetSlotAssignment().RecalcAssignmentNg();
+    ContainingShadowRoot()->GetSlotAssignment().RecalcAssignment();
     return assigned_nodes_;
   }
 
@@ -272,7 +272,7 @@
 Node* HTMLSlotElement::AssignedNodeNextTo(const Node& node) const {
   DCHECK(SupportsAssignment());
   if (RuntimeEnabledFeatures::IncrementalShadowDOMEnabled())
-    ContainingShadowRoot()->GetSlotAssignment().RecalcAssignmentNg();
+    ContainingShadowRoot()->GetSlotAssignment().RecalcAssignment();
   else
     DCHECK(!NeedsDistributionRecalc());
   // TODO(crbug.com/776656): Use {node -> index} map to avoid O(N) lookup
@@ -286,7 +286,7 @@
 Node* HTMLSlotElement::AssignedNodePreviousTo(const Node& node) const {
   DCHECK(SupportsAssignment());
   if (RuntimeEnabledFeatures::IncrementalShadowDOMEnabled())
-    ContainingShadowRoot()->GetSlotAssignment().RecalcAssignmentNg();
+    ContainingShadowRoot()->GetSlotAssignment().RecalcAssignment();
   else
     DCHECK(!NeedsDistributionRecalc());
   // TODO(crbug.com/776656): Use {node -> index} map to avoid O(N) lookup
diff --git a/third_party/WebKit/Source/core/html/forms/DateTimeEditElement.cpp b/third_party/WebKit/Source/core/html/forms/DateTimeEditElement.cpp
index 8c162ab..5db49e4 100644
--- a/third_party/WebKit/Source/core/html/forms/DateTimeEditElement.cpp
+++ b/third_party/WebKit/Source/core/html/forms/DateTimeEditElement.cpp
@@ -43,7 +43,6 @@
 namespace blink {
 
 using namespace HTMLNames;
-using namespace WTF::Unicode;
 
 class DateTimeEditBuilder : private DateTimeFormat::TokenHandler {
  public:
@@ -468,9 +467,10 @@
   HTMLDivElement* element = HTMLDivElement::Create(EditElement().GetDocument());
   element->SetShadowPseudoId(text_pseudo_id);
   if (parameters_.locale.IsRTL() && text.length()) {
-    CharDirection dir = Direction(text[0]);
-    if (dir == kSegmentSeparator || dir == kWhiteSpaceNeutral ||
-        dir == kOtherNeutral)
+    WTF::Unicode::CharDirection dir = WTF::Unicode::Direction(text[0]);
+    if (dir == WTF::Unicode::kSegmentSeparator ||
+        dir == WTF::Unicode::kWhiteSpaceNeutral ||
+        dir == WTF::Unicode::kOtherNeutral)
       element->AppendChild(Text::Create(EditElement().GetDocument(),
                                         String(&kRightToLeftMarkCharacter, 1)));
   }
diff --git a/third_party/WebKit/Source/core/html/parser/TextDocumentParser.cpp b/third_party/WebKit/Source/core/html/parser/TextDocumentParser.cpp
index 12fc3f33..5d50260 100644
--- a/third_party/WebKit/Source/core/html/parser/TextDocumentParser.cpp
+++ b/third_party/WebKit/Source/core/html/parser/TextDocumentParser.cpp
@@ -40,6 +40,9 @@
 TextDocumentParser::~TextDocumentParser() = default;
 
 void TextDocumentParser::AppendBytes(const char* data, size_t length) {
+  if (!length || IsStopped())
+    return;
+
   if (!have_inserted_fake_pre_element_)
     InsertFakePreElement();
   HTMLDocumentParser::AppendBytes(data, length);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
index 92fc088..bb6143cb 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
@@ -1658,6 +1658,12 @@
 InspectorDOMAgent::BuildDistributedNodesForSlot(HTMLSlotElement* slot_element) {
   std::unique_ptr<protocol::Array<protocol::DOM::BackendNode>>
       distributed_nodes = protocol::Array<protocol::DOM::BackendNode>::create();
+  if (RuntimeEnabledFeatures::IncrementalShadowDOMEnabled()) {
+    // TODO(hayato): Support distributed_nodes for IncrementalShadowDOM.
+    // We might use HTMLSlotElement::flat_tree_children here, however, we don't
+    // want to expose it, as of now.
+    return distributed_nodes;
+  }
   for (Node* node = slot_element->FirstDistributedNode(); node;
        node = slot_element->DistributedNodeNextTo(*node)) {
     if (IsWhitespace(node))
diff --git a/third_party/WebKit/Source/core/layout/BidiRunForLine.cpp b/third_party/WebKit/Source/core/layout/BidiRunForLine.cpp
index 7eb1945e..30da3a4c 100644
--- a/third_party/WebKit/Source/core/layout/BidiRunForLine.cpp
+++ b/third_party/WebKit/Source/core/layout/BidiRunForLine.cpp
@@ -27,8 +27,6 @@
 
 namespace blink {
 
-using namespace WTF::Unicode;
-
 static LineLayoutItem FirstLayoutObjectForDirectionalityDetermination(
     LineLayoutItem root,
     LineLayoutItem current = nullptr) {
diff --git a/third_party/WebKit/Source/core/layout/line/InlineIterator.h b/third_party/WebKit/Source/core/layout/line/InlineIterator.h
index 48e0bcc..7a13793 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineIterator.h
+++ b/third_party/WebKit/Source/core/layout/line/InlineIterator.h
@@ -148,13 +148,12 @@
 static inline WTF::Unicode::CharDirection EmbedCharFromDirection(
     TextDirection dir,
     UnicodeBidi unicode_bidi) {
-  using namespace WTF::Unicode;
   if (unicode_bidi == UnicodeBidi::kEmbed) {
-    return dir == TextDirection::kRtl ? kRightToLeftEmbedding
-                                      : kLeftToRightEmbedding;
+    return dir == TextDirection::kRtl ? WTF::Unicode::kRightToLeftEmbedding
+                                      : WTF::Unicode::kLeftToRightEmbedding;
   }
-  return dir == TextDirection::kRtl ? kRightToLeftOverride
-                                    : kLeftToRightOverride;
+  return dir == TextDirection::kRtl ? WTF::Unicode::kRightToLeftOverride
+                                    : WTF::Unicode::kLeftToRightOverride;
 }
 
 static inline bool TreatAsIsolated(const ComputedStyle& style) {
diff --git a/third_party/WebKit/Source/core/messaging/OWNERS b/third_party/WebKit/Source/core/messaging/OWNERS
index 8a792b5..9c7ae1ec 100644
--- a/third_party/WebKit/Source/core/messaging/OWNERS
+++ b/third_party/WebKit/Source/core/messaging/OWNERS
@@ -1,6 +1,9 @@
 mek@chromium.org
 jbroman@chromium.org
 
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+# TODO(tkent): Remove per-file lines for CamelCase patterns.
 per-file *StructTraits*.*=set noparent
 per-file *StructTraits*.*=file://ipc/SECURITY_OWNERS
 per-file *.typemap=set noparent
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index fe175ae..384dc62 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -402,6 +402,27 @@
   return AncestorScrollingLayer() != other->AncestorScrollingLayer();
 }
 
+bool PaintLayer::IsAffectedByScrollOf(const PaintLayer* ancestor) const {
+  if (this == ancestor)
+    return false;
+
+  const PaintLayer* current_layer = this;
+  while (current_layer && current_layer != ancestor) {
+    bool ancestor_escaped = false;
+    const PaintLayer* container =
+        current_layer->ContainingLayer(ancestor, &ancestor_escaped);
+    if (ancestor_escaped)
+      return false;
+    // Workaround the bug that LayoutView is mistakenly considered
+    // a fixed-pos container.
+    if (current_layer->GetLayoutObject().IsFixedPositioned() &&
+        container->IsRootLayer())
+      return false;
+    current_layer = container;
+  }
+  return current_layer == ancestor;
+}
+
 void PaintLayer::UpdateLayerPositionsAfterOverflowScroll() {
   if (IsRootLayer()) {
     // The root PaintLayer (i.e. the LayoutView) is special, in that scroll
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.h b/third_party/WebKit/Source/core/paint/PaintLayer.h
index e746292..7b6e710 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.h
@@ -667,6 +667,8 @@
   bool FixedToViewport() const;
   bool ScrollsWithRespectTo(const PaintLayer*) const;
 
+  bool IsAffectedByScrollOf(const PaintLayer* ancestor) const;
+
   void AddLayerHitTestRects(LayerHitTestRects&, TouchAction) const;
 
   // Compute rects only for this layer
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
index 8b7aaeb4..02163d3 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
@@ -458,7 +458,7 @@
         FloatPoint(), &context.root_layer->GetLayoutObject()));
     if (context.respect_overflow_clip == kIgnoreOverflowClipAndScroll &&
         context.root_layer->ScrollsOverflow() &&
-        layer_.ScrollsWithRespectTo(context.root_layer)) {
+        layer_.IsAffectedByScrollOf(context.root_layer)) {
       offset.Move(LayoutSize(
           context.root_layer->GetScrollableArea()->GetScrollOffset()));
     }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp
index 679c72a..8cd4028 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp
@@ -890,19 +890,12 @@
   PaintLayer* target_layer =
       ToLayoutBoxModelObject(target->GetLayoutObject())->Layer();
 
-  {
-    ClipRect clip_rect;
-    target_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
-        .CalculateBackgroundClipRect(
-            ClipRectsContext(GetDocument().GetLayoutView()->Layer(),
-                             kAbsoluteClipRectsIgnoringViewportClip,
-                             kIgnorePlatformOverlayScrollbarSize,
-                             kIgnoreOverflowClipAndScroll),
-            clip_rect);
-    EXPECT_EQ(LayoutRect(100, 200, 300, 400), clip_rect.Rect());
-  }
-
   GetDocument().domWindow()->scrollTo(0, 50);
+  GetDocument()
+      .GetLayoutView()
+      ->Layer()
+      ->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+      .ClearClipRectsIncludingDescendants();
 
   {
     ClipRect clip_rect;
@@ -915,6 +908,70 @@
             clip_rect);
     EXPECT_EQ(LayoutRect(100, 250, 300, 400), clip_rect.Rect());
   }
+
+  GetDocument().domWindow()->scrollTo(0, 100);
+
+  {
+    ClipRect clip_rect;
+    target_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+        .CalculateBackgroundClipRect(
+            ClipRectsContext(GetDocument().GetLayoutView()->Layer(),
+                             kAbsoluteClipRectsIgnoringViewportClip,
+                             kIgnorePlatformOverlayScrollbarSize,
+                             kIgnoreOverflowClipAndScroll),
+            clip_rect);
+    EXPECT_EQ(LayoutRect(100, 300, 300, 400), clip_rect.Rect());
+  }
+}
+
+TEST_P(PaintLayerClipperTestParameterized,
+       FixedLayerClipRectInDocumentSpaceWithNestedScroller) {
+  SetBodyInnerHTML(R"HTML(
+    <div style="position:fixed; left:100px; top:200px; width:300px; height:400px; overflow:scroll;">
+      <div style="width:200px; height:300px; overflow:hidden;">
+        <div id="target" style="position:relative;"></div>
+      </div>
+      <div style="height:3000px;"></div>
+    </div>
+    <div style="height:3000px;"></div>
+  )HTML");
+
+  Element* target = GetDocument().getElementById("target");
+  PaintLayer* target_layer =
+      ToLayoutBoxModelObject(target->GetLayoutObject())->Layer();
+
+  GetDocument().domWindow()->scrollTo(0, 50);
+  GetDocument()
+      .GetLayoutView()
+      ->Layer()
+      ->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+      .ClearClipRectsIncludingDescendants();
+
+  {
+    ClipRect clip_rect;
+    target_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+        .CalculateBackgroundClipRect(
+            ClipRectsContext(GetDocument().GetLayoutView()->Layer(),
+                             kAbsoluteClipRectsIgnoringViewportClip,
+                             kIgnorePlatformOverlayScrollbarSize,
+                             kIgnoreOverflowClipAndScroll),
+            clip_rect);
+    EXPECT_EQ(LayoutRect(100, 250, 200, 300), clip_rect.Rect());
+  }
+
+  GetDocument().domWindow()->scrollTo(0, 100);
+
+  {
+    ClipRect clip_rect;
+    target_layer->Clipper(PaintLayer::kDoNotUseGeometryMapper)
+        .CalculateBackgroundClipRect(
+            ClipRectsContext(GetDocument().GetLayoutView()->Layer(),
+                             kAbsoluteClipRectsIgnoringViewportClip,
+                             kIgnorePlatformOverlayScrollbarSize,
+                             kIgnoreOverflowClipAndScroll),
+            clip_rect);
+    EXPECT_EQ(LayoutRect(100, 300, 200, 300), clip_rect.Rect());
+  }
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/xml/XPathParser.cpp b/third_party/WebKit/Source/core/xml/XPathParser.cpp
index c50e872..e48c251 100644
--- a/third_party/WebKit/Source/core/xml/XPathParser.cpp
+++ b/third_party/WebKit/Source/core/xml/XPathParser.cpp
@@ -39,8 +39,6 @@
 
 namespace blink {
 
-using namespace WTF;
-using namespace Unicode;
 using namespace XPath;
 
 Parser* Parser::current_parser_ = nullptr;
@@ -57,12 +55,16 @@
 
   if (a_char == '.' || a_char == '-')
     return kNameCont;
-  CharCategory category = Unicode::Category(a_char);
-  if (category & (kLetter_Uppercase | kLetter_Lowercase | kLetter_Other |
-                  kLetter_Titlecase | kNumber_Letter))
+  WTF::Unicode::CharCategory category = WTF::Unicode::Category(a_char);
+  if (category &
+      (WTF::Unicode::kLetter_Uppercase | WTF::Unicode::kLetter_Lowercase |
+       WTF::Unicode::kLetter_Other | WTF::Unicode::kLetter_Titlecase |
+       WTF::Unicode::kNumber_Letter))
     return kNameStart;
-  if (category & (kMark_NonSpacing | kMark_SpacingCombining | kMark_Enclosing |
-                  kLetter_Modifier | kNumber_DecimalDigit))
+  if (category &
+      (WTF::Unicode::kMark_NonSpacing | WTF::Unicode::kMark_SpacingCombining |
+       WTF::Unicode::kMark_Enclosing | WTF::Unicode::kLetter_Modifier |
+       WTF::Unicode::kNumber_DecimalDigit))
     return kNameCont;
   return kNotPartOfName;
 }
diff --git a/third_party/WebKit/Source/modules/background_fetch/OWNERS b/third_party/WebKit/Source/modules/background_fetch/OWNERS
index 8bea39e..686fc57 100644
--- a/third_party/WebKit/Source/modules/background_fetch/OWNERS
+++ b/third_party/WebKit/Source/modules/background_fetch/OWNERS
@@ -1,5 +1,8 @@
 peter@chromium.org
 
+per-file *_type_converter*.*=set noparent
+per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
+# TODO(tkent): Remove per-file lines for CamelCase patterns.
 per-file *TypeConverter*.*=set noparent
 per-file *TypeConverter*.*=file://ipc/SECURITY_OWNERS
 
diff --git a/third_party/WebKit/Source/modules/credentialmanager/OWNERS b/third_party/WebKit/Source/modules/credentialmanager/OWNERS
index 16269f1..7fe6f7a 100644
--- a/third_party/WebKit/Source/modules/credentialmanager/OWNERS
+++ b/third_party/WebKit/Source/modules/credentialmanager/OWNERS
@@ -2,6 +2,9 @@
 mkwst@chromium.org
 vasilii@chromium.org
 
+per-file *_type_converter*.*=set noparent
+per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
+# TODO(tkent): Remove per-file lines for CamelCase patterns.
 per-file *TypeConverter*.*=set noparent
 per-file *TypeConverter*.*=file://ipc/SECURITY_OWNERS
 
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBKeyPath.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBKeyPath.cpp
index 62d1959..75184d6 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBKeyPath.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBKeyPath.cpp
@@ -36,24 +36,26 @@
 
 namespace {
 
-using namespace WTF::Unicode;
-
 // The following correspond to grammar in ECMA-262.
-const uint32_t kUnicodeLetter = kLetter_Uppercase | kLetter_Lowercase |
-                                kLetter_Titlecase | kLetter_Modifier |
-                                kLetter_Other | kNumber_Letter;
+const uint32_t kUnicodeLetter =
+    WTF::Unicode::kLetter_Uppercase | WTF::Unicode::kLetter_Lowercase |
+    WTF::Unicode::kLetter_Titlecase | WTF::Unicode::kLetter_Modifier |
+    WTF::Unicode::kLetter_Other | WTF::Unicode::kNumber_Letter;
 const uint32_t kUnicodeCombiningMark =
-    kMark_NonSpacing | kMark_SpacingCombining;
-const uint32_t kUnicodeDigit = kNumber_DecimalDigit;
-const uint32_t kUnicodeConnectorPunctuation = kPunctuation_Connector;
+    WTF::Unicode::kMark_NonSpacing | WTF::Unicode::kMark_SpacingCombining;
+const uint32_t kUnicodeDigit = WTF::Unicode::kNumber_DecimalDigit;
+const uint32_t kUnicodeConnectorPunctuation =
+    WTF::Unicode::kPunctuation_Connector;
 
 static inline bool IsIdentifierStartCharacter(UChar c) {
-  return (Category(c) & kUnicodeLetter) || (c == '$') || (c == '_');
+  return (WTF::Unicode::Category(c) & kUnicodeLetter) || (c == '$') ||
+         (c == '_');
 }
 
 static inline bool IsIdentifierCharacter(UChar c) {
-  return (Category(c) & (kUnicodeLetter | kUnicodeCombiningMark |
-                         kUnicodeDigit | kUnicodeConnectorPunctuation)) ||
+  return (WTF::Unicode::Category(c) &
+          (kUnicodeLetter | kUnicodeCombiningMark | kUnicodeDigit |
+           kUnicodeConnectorPunctuation)) ||
          (c == '$') || (c == '_') || (c == kZeroWidthNonJoinerCharacter) ||
          (c == kZeroWidthJoinerCharacter);
 }
diff --git a/third_party/WebKit/Source/modules/mediasession/OWNERS b/third_party/WebKit/Source/modules/mediasession/OWNERS
index ed4533e..9fea355 100644
--- a/third_party/WebKit/Source/modules/mediasession/OWNERS
+++ b/third_party/WebKit/Source/modules/mediasession/OWNERS
@@ -1,6 +1,9 @@
 foolip@chromium.org
 mlamouri@chromium.org
 
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+# TODO(tkent): Remove per-file lines for CamelCase patterns.
 per-file *StructTraits*.*=set noparent
 per-file *StructTraits*.*=file://ipc/SECURITY_OWNERS
 
diff --git a/third_party/WebKit/Source/platform/PartitionAllocMemoryDumpProvider.cpp b/third_party/WebKit/Source/platform/PartitionAllocMemoryDumpProvider.cpp
index e382ff2..81a9d6a 100644
--- a/third_party/WebKit/Source/platform/PartitionAllocMemoryDumpProvider.cpp
+++ b/third_party/WebKit/Source/platform/PartitionAllocMemoryDumpProvider.cpp
@@ -18,8 +18,6 @@
 
 namespace {
 
-using namespace WTF;
-
 void ReportAllocation(void* address, size_t size, const char* type_name) {
   PartitionAllocMemoryDumpProvider::Instance()->insert(address, size,
                                                        type_name);
@@ -161,7 +159,8 @@
       &partition_stats_dumper);
 
   base::trace_event::MemoryAllocatorDump* allocated_objects_dump =
-      memory_dump->CreateAllocatorDump(Partitions::kAllocatedObjectPoolName);
+      memory_dump->CreateAllocatorDump(
+          WTF::Partitions::kAllocatedObjectPoolName);
   allocated_objects_dump->AddScalar("size", "bytes",
                                     partition_stats_dumper.TotalActiveBytes());
   memory_dump->AddOwnershipEdge(allocated_objects_dump->guid(),
diff --git a/third_party/WebKit/Source/platform/blob/OWNERS b/third_party/WebKit/Source/platform/blob/OWNERS
index e8cd7eaf..3323d97 100644
--- a/third_party/WebKit/Source/platform/blob/OWNERS
+++ b/third_party/WebKit/Source/platform/blob/OWNERS
@@ -1,6 +1,9 @@
 dmurph@chromium.org
 mek@chromium.org
 
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+# TODO(tkent): Remove per-file lines for CamelCase patterns.
 per-file *StructTraits*.*=set noparent
 per-file *StructTraits*.*=file://ipc/SECURITY_OWNERS
 per-file *.typemap=set noparent
diff --git a/third_party/WebKit/Source/platform/exported/Platform.cpp b/third_party/WebKit/Source/platform/exported/Platform.cpp
index 6df4554..399e584 100644
--- a/third_party/WebKit/Source/platform/exported/Platform.cpp
+++ b/third_party/WebKit/Source/platform/exported/Platform.cpp
@@ -164,11 +164,6 @@
         base::ThreadTaskRunnerHandle::Get());
   }
 
-  // Pre-create the File thread so multiple threads can call FileTaskRunner() in
-  // a non racy way later.
-  g_platform->file_thread_ = g_platform->CreateThread(
-      WebThreadCreationParams(WebThreadType::kFileThread));
-
   if (BlinkResourceCoordinatorBase::IsEnabled())
     RendererResourceCoordinator::Initialize();
 }
@@ -187,15 +182,6 @@
   return main_thread_;
 }
 
-base::SingleThreadTaskRunner* Platform::FileTaskRunner() const {
-  return file_thread_ ? file_thread_->GetTaskRunner().get() : nullptr;
-}
-
-scoped_refptr<base::SingleThreadTaskRunner> Platform::BaseFileTaskRunner()
-    const {
-  return file_thread_ ? file_thread_->GetTaskRunner() : nullptr;
-}
-
 service_manager::Connector* Platform::GetConnector() {
   DEFINE_STATIC_LOCAL(DefaultConnector, connector, ());
   return connector.Get();
diff --git a/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.h b/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.h
index 0b9e7b19..a28843d7 100644
--- a/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.h
+++ b/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.h
@@ -15,8 +15,6 @@
 
 namespace blink {
 
-using namespace WTF;
-
 class FontDescription;
 class FontFallbackList;
 class SimpleFontData;
diff --git a/third_party/WebKit/Source/platform/fonts/SymbolsIterator.cpp b/third_party/WebKit/Source/platform/fonts/SymbolsIterator.cpp
index 62e1c4e..12616d4 100644
--- a/third_party/WebKit/Source/platform/fonts/SymbolsIterator.cpp
+++ b/third_party/WebKit/Source/platform/fonts/SymbolsIterator.cpp
@@ -10,8 +10,6 @@
 
 namespace blink {
 
-using namespace WTF::Unicode;
-
 SymbolsIterator::SymbolsIterator(const UChar* buffer, unsigned buffer_size)
     : utf16_iterator_(std::make_unique<UTF16TextIterator>(buffer, buffer_size)),
       buffer_size_(buffer_size),
diff --git a/third_party/WebKit/Source/platform/heap/BUILD.gn b/third_party/WebKit/Source/platform/heap/BUILD.gn
index 68731a7..b4e1601 100644
--- a/third_party/WebKit/Source/platform/heap/BUILD.gn
+++ b/third_party/WebKit/Source/platform/heap/BUILD.gn
@@ -9,10 +9,15 @@
 
 declare_args() {
   # Enables incremental marking in Oilpan.
+  #
+  # Note: Incremental marking is currently considered experimental and also
+  # enables 'enable_blink_heap_incremental_marking'. See default value below.
   enable_blink_heap_incremental_marking = false
+}
 
+declare_args() {
   # Enables heap verification.
-  enable_blink_heap_verification = false
+  enable_blink_heap_verification = enable_blink_heap_incremental_marking
 }
 
 buildflag_header("blink_heap_flags") {
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.cpp b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
index 6e15e37..612f822 100644
--- a/third_party/WebKit/Source/platform/heap/HeapPage.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
@@ -609,6 +609,10 @@
 
 void NormalPageArena::VerifyMarking() {
 #if DCHECK_IS_ON()
+  // We cannot rely on other marking phases to clear the allocation area as
+  // for incremental marking the application is running between steps and
+  // might set up a new area.
+  SetAllocationPoint(nullptr, 0);
   for (NormalPage* page = static_cast<NormalPage*>(first_page_); page;
        page = static_cast<NormalPage*>(page->Next()))
     page->VerifyMarking();
diff --git a/third_party/WebKit/Source/platform/mojo/OWNERS b/third_party/WebKit/Source/platform/mojo/OWNERS
index 3e025c8..a36c1b3 100644
--- a/third_party/WebKit/Source/platform/mojo/OWNERS
+++ b/third_party/WebKit/Source/platform/mojo/OWNERS
@@ -1,3 +1,8 @@
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+# TODO(tkent): Remove per-file lines for CamelCase patterns.
 per-file *MojomTraits*.*=set noparent
 per-file *MojomTraits*.*=file://ipc/SECURITY_OWNERS
 per-file *StructTraits*.*=set noparent
diff --git a/third_party/WebKit/Source/platform/wtf/text/AtomicStringTable.cpp b/third_party/WebKit/Source/platform/wtf/text/AtomicStringTable.cpp
index 082ece5..9a77388 100644
--- a/third_party/WebKit/Source/platform/wtf/text/AtomicStringTable.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/AtomicStringTable.cpp
@@ -9,8 +9,6 @@
 
 namespace WTF {
 
-using namespace Unicode;
-
 AtomicStringTable::AtomicStringTable() {
   for (StringImpl* string : StringImpl::AllStaticStrings().Values())
     Add(string);
@@ -90,14 +88,14 @@
     if (buffer.utf16_length != buffer.length) {
       if (string->Is8Bit()) {
         const LChar* characters8 = string->Characters8();
-        return EqualLatin1WithUTF8(characters8, characters8 + string->length(),
-                                   buffer.characters,
-                                   buffer.characters + buffer.length);
+        return Unicode::EqualLatin1WithUTF8(
+            characters8, characters8 + string->length(), buffer.characters,
+            buffer.characters + buffer.length);
       }
       const UChar* characters16 = string->Characters16();
-      return EqualUTF16WithUTF8(characters16, characters16 + string->length(),
-                                buffer.characters,
-                                buffer.characters + buffer.length);
+      return Unicode::EqualUTF16WithUTF8(
+          characters16, characters16 + string->length(), buffer.characters,
+          buffer.characters + buffer.length);
     }
 
     if (string->Is8Bit()) {
@@ -132,9 +130,9 @@
 
     bool is_all_ascii;
     const char* source = buffer.characters;
-    if (ConvertUTF8ToUTF16(&source, source + buffer.length, &target,
-                           target + buffer.utf16_length,
-                           &is_all_ascii) != kConversionOK)
+    if (Unicode::ConvertUTF8ToUTF16(&source, source + buffer.length, &target,
+                                    target + buffer.utf16_length,
+                                    &is_all_ascii) != Unicode::kConversionOK)
       NOTREACHED();
 
     if (is_all_ascii)
@@ -210,7 +208,7 @@
     const char* characters_end) {
   HashAndUTF8Characters buffer;
   buffer.characters = characters_start;
-  buffer.hash = CalculateStringHashAndLengthFromUTF8MaskingTop8Bits(
+  buffer.hash = Unicode::CalculateStringHashAndLengthFromUTF8MaskingTop8Bits(
       characters_start, characters_end, buffer.length, buffer.utf16_length);
 
   if (!buffer.hash)
diff --git a/third_party/WebKit/Source/platform/wtf/text/OWNERS b/third_party/WebKit/Source/platform/wtf/text/OWNERS
index 01fd8ce..1dc6240 100644
--- a/third_party/WebKit/Source/platform/wtf/text/OWNERS
+++ b/third_party/WebKit/Source/platform/wtf/text/OWNERS
@@ -1,3 +1,9 @@
+per-file character_names.h=drott@chromium.org
+per-file text_codec*.*=jsbell@chromium.org
+per-file text_codec*.*=jshin@chromium.org
+per-file text_encoding*.*=jshin@chromium.org
+per-file text_encoding*.*=jshin@chromium.org
+# TODO(tkent): Remove per-file lines for CamelCase patterns.
 per-file CharacterNames.h=drott@chromium.org
 per-file TextCodec*.*=jsbell@chromium.org
 per-file TextCodec*.*=jshin@chromium.org
diff --git a/third_party/WebKit/Source/platform/wtf/text/StringImpl.cpp b/third_party/WebKit/Source/platform/wtf/text/StringImpl.cpp
index ac4098d..8542d6f 100644
--- a/third_party/WebKit/Source/platform/wtf/text/StringImpl.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/StringImpl.cpp
@@ -44,8 +44,6 @@
 
 namespace WTF {
 
-using namespace Unicode;
-
 // As of Jan 2017, StringImpl needs 2 * sizeof(int) + 29 bits of data, and
 // sizeof(ThreadRestrictionVerifier) is 16 bytes. Thus, in DCHECK mode the
 // class may be padded to 32 bytes.
@@ -1058,7 +1056,7 @@
                                  const LChar* b,
                                  unsigned length) {
   while (length--) {
-    if (FoldCase(*a++) != StringImpl::kLatin1CaseFoldTable[*b++])
+    if (Unicode::FoldCase(*a++) != StringImpl::kLatin1CaseFoldTable[*b++])
       return false;
   }
   return true;
@@ -2001,7 +1999,7 @@
     }
   }
 
-  return ToUpper(c);
+  return Unicode::ToUpper(c);
 }
 
 }  // namespace WTF
diff --git a/third_party/WebKit/Source/platform/wtf/text/TextCodecUTF8.cpp b/third_party/WebKit/Source/platform/wtf/text/TextCodecUTF8.cpp
index 7d4bfe2..8a035bc2b 100644
--- a/third_party/WebKit/Source/platform/wtf/text/TextCodecUTF8.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/TextCodecUTF8.cpp
@@ -34,8 +34,6 @@
 
 namespace WTF {
 
-using namespace WTF::Unicode;
-
 // We'll use nonCharacter* constants to signal invalid utf-8.
 // The number in the name signals how many input bytes were invalid.
 const int kNonCharacter1 = -1;
diff --git a/third_party/WebKit/Source/platform/wtf/text/WTFString.cpp b/third_party/WebKit/Source/platform/wtf/text/WTFString.cpp
index 9a07e9f..74ad7a3a 100644
--- a/third_party/WebKit/Source/platform/wtf/text/WTFString.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/WTFString.cpp
@@ -37,8 +37,6 @@
 
 namespace WTF {
 
-using namespace Unicode;
-
 // Construct a string with UTF-16 data.
 String::String(const UChar* characters, unsigned length)
     : impl_(characters ? StringImpl::Create(characters, length) : nullptr) {}
@@ -658,11 +656,11 @@
   if (Is8Bit()) {
     const LChar* characters = this->Characters8();
 
-    ConversionResult result =
-        ConvertLatin1ToUTF8(&characters, characters + length, &buffer,
-                            buffer + buffer_vector.size());
+    Unicode::ConversionResult result =
+        Unicode::ConvertLatin1ToUTF8(&characters, characters + length, &buffer,
+                                     buffer + buffer_vector.size());
     // (length * 3) should be sufficient for any conversion
-    DCHECK_NE(result, kTargetExhausted);
+    DCHECK_NE(result, Unicode::kTargetExhausted);
   } else {
     const UChar* characters = this->Characters16();
 
@@ -671,13 +669,13 @@
       char* buffer_end = buffer + buffer_vector.size();
       while (characters < characters_end) {
         // Use strict conversion to detect unpaired surrogates.
-        ConversionResult result = ConvertUTF16ToUTF8(
+        Unicode::ConversionResult result = Unicode::ConvertUTF16ToUTF8(
             &characters, characters_end, &buffer, buffer_end, true);
-        DCHECK_NE(result, kTargetExhausted);
+        DCHECK_NE(result, Unicode::kTargetExhausted);
         // Conversion fails when there is an unpaired surrogate.  Put
         // replacement character (U+FFFD) instead of the unpaired
         // surrogate.
-        if (result != kConversionOK) {
+        if (result != Unicode::kConversionOK) {
           DCHECK_LE(0xD800, *characters);
           DCHECK_LE(*characters, 0xDFFF);
           // There should be room left, since one UChar hasn't been
@@ -689,20 +687,20 @@
       }
     } else {
       bool strict = mode == kStrictUTF8Conversion;
-      ConversionResult result =
-          ConvertUTF16ToUTF8(&characters, characters + length, &buffer,
-                             buffer + buffer_vector.size(), strict);
+      Unicode::ConversionResult result =
+          Unicode::ConvertUTF16ToUTF8(&characters, characters + length, &buffer,
+                                      buffer + buffer_vector.size(), strict);
       // (length * 3) should be sufficient for any conversion
-      DCHECK_NE(result, kTargetExhausted);
+      DCHECK_NE(result, Unicode::kTargetExhausted);
 
       // Only produced from strict conversion.
-      if (result == kSourceIllegal) {
+      if (result == Unicode::kSourceIllegal) {
         DCHECK(strict);
         return CString();
       }
 
       // Check for an unconverted high surrogate.
-      if (result == kSourceExhausted) {
+      if (result == Unicode::kSourceExhausted) {
         if (strict)
           return CString();
         // This should be one unpaired high surrogate. Treat it the same
@@ -764,9 +762,10 @@
 
   UChar* buffer_current = buffer_start;
   const char* string_current = reinterpret_cast<const char*>(string_start);
-  if (ConvertUTF8ToUTF16(
+  if (Unicode::ConvertUTF8ToUTF16(
           &string_current, reinterpret_cast<const char*>(string_start + length),
-          &buffer_current, buffer_current + buffer.size()) != kConversionOK)
+          &buffer_current,
+          buffer_current + buffer.size()) != Unicode::kConversionOK)
     return String();
 
   unsigned utf16_length = buffer_current - buffer_start;
diff --git a/third_party/WebKit/public/platform/OWNERS b/third_party/WebKit/public/platform/OWNERS
index e2d3754..e54d41834 100644
--- a/third_party/WebKit/public/platform/OWNERS
+++ b/third_party/WebKit/public/platform/OWNERS
@@ -5,10 +5,18 @@
 # review, but you should add a security team OWNER if you are changing others.
 per-file web_feature.mojom=file://third_party/WebKit/Source/core/OWNERS
 
+per-file *_enum_traits*.*=set noparent
+per-file *_enum_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+# TODO(tkent): Remove per-file lines for CamelCase patterns.
 per-file *EnumTraits*.*=set noparent
 per-file *EnumTraits*.*=file://ipc/SECURITY_OWNERS
 per-file *StructTraits*.*=set noparent
 per-file *StructTraits*.*=file://ipc/SECURITY_OWNERS
 per-file *.typemap=set noparent
 per-file *.typemap=file://ipc/SECURITY_OWNERS
+
+per-file web_rtc_*=hbos@chromium.org
+# TODO(tkent): Remove a per-file line for a CamelCase pattern.
 per-file WebRTC*=hbos@chromium.org
diff --git a/third_party/WebKit/public/platform/Platform.h b/third_party/WebKit/public/platform/Platform.h
index dfc266d..966dd54 100644
--- a/third_party/WebKit/public/platform/Platform.h
+++ b/third_party/WebKit/public/platform/Platform.h
@@ -474,9 +474,6 @@
   // renderer was created with threaded rendering desabled.
   virtual WebThread* CompositorThread() const { return 0; }
 
-  // Returns an interface to the file task runner.
-  base::SingleThreadTaskRunner* FileTaskRunner() const;
-  scoped_refptr<base::SingleThreadTaskRunner> BaseFileTaskRunner() const;
 
   // Returns an interface to the IO task runner.
   virtual scoped_refptr<base::SingleThreadTaskRunner> GetIOTaskRunner() const {
@@ -494,7 +491,6 @@
   CreateNestedMessageLoopRunner() const {
     return nullptr;
   }
-
   // Testing -------------------------------------------------------------
 
   // Gets a pointer to URLLoaderMockFactory for testing. Will not be available
@@ -763,7 +759,6 @@
   virtual ~Platform();
 
   WebThread* main_thread_;
-  std::unique_ptr<WebThread> file_thread_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/platform/WebRuntimeFeatures.h b/third_party/WebKit/public/platform/WebRuntimeFeatures.h
index 96cd4fe..fd4cea2 100644
--- a/third_party/WebKit/public/platform/WebRuntimeFeatures.h
+++ b/third_party/WebKit/public/platform/WebRuntimeFeatures.h
@@ -129,7 +129,6 @@
   BLINK_PLATFORM_EXPORT static void EnableScriptedSpeech(bool);
   BLINK_PLATFORM_EXPORT static void EnableScrollAnchoring(bool);
   BLINK_PLATFORM_EXPORT static void EnableScrollAnchorSerialization(bool);
-  BLINK_PLATFORM_EXPORT static void EnableServiceWorkerNavigationPreload(bool);
   BLINK_PLATFORM_EXPORT static void EnableServiceWorkerScriptFullCodeCache(
       bool);
   BLINK_PLATFORM_EXPORT static void EnableSharedArrayBuffer(bool);
diff --git a/third_party/WebKit/public/web/OWNERS b/third_party/WebKit/public/web/OWNERS
index 1ebeb4c..0b04b827 100644
--- a/third_party/WebKit/public/web/OWNERS
+++ b/third_party/WebKit/public/web/OWNERS
@@ -1,13 +1,24 @@
+per-file web_ax_enums.h=dmazzoni@chromium.org
+per-file web_ax_enums.h=aboxhall@chromium.org
+per-file web_ax_enums.h=dtseng@chromium.org
+per-file web_ax_enums.h=nektar@chromium.org
+# TODO(tkent): Remove per-file lines for CamelCase patterns.
 per-file WebAXEnums.h=dmazzoni@chromium.org
 per-file WebAXEnums.h=aboxhall@chromium.org
 per-file WebAXEnums.h=dtseng@chromium.org
 per-file WebAXEnums.h=nektar@chromium.org
 
 # Page load metrics
+per-file web_performance.h=bmcquade@chromium.org
+per-file web_performance.h=csharrison@chromium.org
+# TODO(tkent): Remove per-file lines for CamelCase patterns.
 per-file WebPerformance.h=bmcquade@chromium.org
 per-file WebPerformance.h=csharrison@chromium.org
 
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+# TODO(tkent): Remove per-file lines for CamelCase patterns.
 per-file *StructTraits*.*=set noparent
 per-file *StructTraits*.*=file://ipc/SECURITY_OWNERS
diff --git a/third_party/blink/tools/move_blink_source.py b/third_party/blink/tools/move_blink_source.py
index 15f71cb9..bffa5b2 100755
--- a/third_party/blink/tools/move_blink_source.py
+++ b/third_party/blink/tools/move_blink_source.py
@@ -68,8 +68,19 @@
                 return FileType.NONE
             return FileType.BUILD
         if basename.endswith('.html') and re.search(
-                r'third_party/WebKit/LayoutTests/(geolocation-api|installedapp|' +
-                r'media/mediasession|payments|presentation|webshare)', slash_dir):
+                r'third_party/WebKit/LayoutTests/('
+                r'fast/dom/shadow|'
+                r'fast/forms/color|'
+                r'geolocation-api|'
+                r'http/tests/budget|'
+                r'http/tests/credentialmanager|'
+                r'http/tests/security/powerfulFeatureRestrictions|'
+                r'installedapp|'
+                r'media/mediasession|'
+                r'payments|'
+                r'presentation|'
+                r'reporting-observer|'
+                r'webshare)', slash_dir):
             return FileType.LAYOUT_TESTS_WITH_MOJOM
         return FileType.NONE
 
@@ -102,7 +113,6 @@
         """
         _log.info('Planning renaming ...')
         file_pairs = plan_blink_move(self._fs, [])
-        _log.info('Will move %d files', len(file_pairs))
 
         self._create_basename_maps(file_pairs)
         dirs = self._update_file_content(apply_only)
@@ -182,9 +192,13 @@
              [('third_party/WebKit/Source', 'third_party/blink/renderer')]),
             ('tools/android/loading/request_track.py',
              [('third_party/WebKit/Source', 'third_party/blink/renderer')]),
+            ('tools/cfi/blacklist.txt',
+             [('third_party/WebKit/Source', 'third_party/blink/renderer')]),
             ('tools/gritsettings/resource_ids',
              [('third_party/WebKit/public', 'third_party/blink/public'),
               ('third_party/WebKit/Source', 'third_party/blink/renderer')]),
+            ('tools/include_tracer.py',
+             [('third_party/WebKit/Source', 'third_party/blink/renderer')]),
             ('tools/metrics/actions/extract_actions.py',
              [('third_party/WebKit/Source', 'third_party/blink/renderer')]),
             ('tools/metrics/histograms/update_editor_commands.py',
@@ -237,7 +251,6 @@
         if apply_only:
             file_pairs = [(src, dest) for (src, dest) in file_pairs
                           if 'third_party/WebKit/' + src.replace('\\', '/') in apply_only]
-            print 'Update file_pairs = ', file_pairs
         _log.info('Will move %d files', len(file_pairs))
 
         git = Git(cwd=self._repo_root)
@@ -359,7 +372,7 @@
                 source_header = source_base.replace('.proto', '.pb.h')
                 basename_map[source_header] = dest_base.replace('.proto', '.pb.h')
                 pattern += re.escape(source_header) + '|'
-        _log.info('Rename %d files for snake_case', len(basename_map))
+        _log.debug('Rename %d files for snake_case', len(basename_map))
         self._basename_map = basename_map
         self._basename_re = re.compile(pattern[0:len(pattern) - 1] + ')(?=["\']|$)')
         self._idl_generated_impl_headers = idl_headers
@@ -449,7 +462,8 @@
         return self._update_basename(content)
 
     def _update_layout_tests(self, content):
-        return content.replace('file:///gen/third_party/WebKit/', 'file:///gen/third_party/blink/renderer/')
+        return content.replace('file:///gen/third_party/WebKit/public/',
+                               'file:///gen/third_party/blink/public/')
 
     def _update_basename(self, content):
         return self._basename_re.sub(lambda match: self._basename_map[match.group(1)], content)
@@ -482,7 +496,7 @@
                 content = self._update_owners(content)
             elif file_type == FileType.DEPS:
                 if self._fs.dirname(file_path) == self._repo_root:
-                    _log.info("Skip //DEPS")
+                    _log.debug("Skip //DEPS")
                     continue
                 content = self._update_deps(content)
             elif file_type == FileType.BLINK_DEPS:
@@ -501,9 +515,9 @@
             if self._options.run and (not apply_only or file_path.replace('\\', '/') in apply_only):
                 self._fs.write_text_file(file_path, content)
                 self._updated_files.append(file_path)
+                _log.info('Updated %s', self._shorten_path(file_path))
             if file_type == FileType.DEPS:
                 self._append_unless_upper_dir_exists(updated_deps_dirs, self._fs.dirname(file_path))
-            _log.info('Updated %s', self._shorten_path(file_path))
         return updated_deps_dirs
 
     def _update_cpp_includes_in_directories(self, dirs, apply_only):
@@ -515,6 +529,8 @@
                      '.h.tmpl', 'xpath_grammar.y', '.gperf')))
             for file_path in files:
                 posix_file_path = file_path.replace('\\', '/')
+                if '/third_party/WebKit/Source/bindings/tests/results/' in posix_file_path:
+                    continue
                 original_content = self._fs.read_text_file(file_path)
 
                 content = self._update_cpp_includes(original_content)
@@ -528,7 +544,7 @@
                 if self._options.run and (not apply_only or posix_file_path in apply_only):
                     self._fs.write_text_file(file_path, content)
                     self._updated_files.append(file_path)
-                _log.info('Updated %s', self._shorten_path(file_path))
+                    _log.info('Updated %s', self._shorten_path(file_path))
 
     def _replace_include_path(self, match):
         include_or_import = match.group(1)
@@ -624,13 +640,13 @@
             if should_write:
                 self._fs.write_text_file(full_path, content)
                 self._updated_files.append(full_path)
-            _log.info('Updated %s', file_path)
+                _log.info('Updated %s', file_path)
         else:
             _log.warning('%s does not contain specified source strings.', file_path)
 
 
 def main():
-    logging.basicConfig(level=logging.DEBUG,
+    logging.basicConfig(level=logging.INFO,
                         format='[%(asctime)s %(levelname)s %(name)s] %(message)s',
                         datefmt='%H:%M:%S')
     parser = argparse.ArgumentParser(description='Blink source mover')
diff --git a/third_party/closure_compiler/compiled_resources2.gyp b/third_party/closure_compiler/compiled_resources2.gyp
index 403718f1..16765e9 100644
--- a/third_party/closure_compiler/compiled_resources2.gyp
+++ b/third_party/closure_compiler/compiled_resources2.gyp
@@ -26,7 +26,6 @@
         '<(DEPTH)/chrome/browser/resources/cryptotoken/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/download_internals/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/extensions/compiled_resources2.gyp:*',
-        '<(DEPTH)/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/md_downloads/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/md_extensions/compiled_resources2.gyp:*',
         '<(DEPTH)/chrome/browser/resources/md_history/compiled_resources2.gyp:*',
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index cf607e5..1301648 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -85,7 +85,7 @@
     },
 
     'chromium.chromedriver': {
-      'Win7': 'release_bot_x86_minimal_symbols',
+      'Win7': 'release_bot_x86',
       'Mac 10.6': 'release_bot',
       'Linux': 'release_bot',
       'Linux32': 'release_bot_x86',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 5653ffa3..cdd57918 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -4766,6 +4766,15 @@
   <int value="4" label="FAILED_INCLUSION_PROOF_MALFORMED"/>
 </enum>
 
+<enum name="CertVerifierTrialComparisonResult">
+  <int value="0" label="Invalid"/>
+  <int value="1" label="Equal"/>
+  <int value="2" label="Primary Valid, Secondary Error"/>
+  <int value="3" label="Primary Error, Secondary Valid"/>
+  <int value="4" label="Both Valid, Different Details"/>
+  <int value="5" label="Both Error, Different Details"/>
+</enum>
+
 <enum name="ChannelLayout">
   <int value="0" label="CHANNEL_LAYOUT_NONE"/>
   <int value="1" label="CHANNEL_LAYOUT_UNSUPPORTED"/>
@@ -9986,6 +9995,30 @@
   <int value="2" label="No action or opened via extension"/>
 </enum>
 
+<enum name="DownloadFileInBackground">
+  <int value="0" label="FailedWithoutBackgrounding">
+    The download failed. This task was running when the app was active.
+  </int>
+  <int value="1" label="FailedWithBackgrounding">
+    The download failed. This task was fully or partially running when the app
+    was not active.
+  </int>
+  <int value="2" label="SucceededWithoutBackgrounding">
+    The download successfully completed. This task was running when the app was
+    active.
+  </int>
+  <int value="3" label="SucceededWithBackgrounding">
+    The download successfully completed. This task was fully or partially
+    running when the app was not active.
+  </int>
+  <int value="4" label="CanceledAfterAppQuit">
+    The download was cancelled, because the app was quit by the user. Some of
+    these downloads can be salvaged by supporting
+    application:handleEventsForBackgroundURLSession:completionHandler:
+    AppDelegate callback.
+  </int>
+</enum>
+
 <enum name="DownloadFilePickerResult">
   <int value="0" label="SAME"/>
   <int value="1" label="DIFFERENT_DIR"/>
@@ -10788,6 +10821,28 @@
   <int value="6" label="Lock screen enabled, trust agent enabled"/>
 </enum>
 
+<enum name="EasyUnlockSetupProgress">
+  <int value="0" label="Showed promo"/>
+  <int value="1" label="Clicked promo"/>
+  <int value="2" label="Dismissed promo"/>
+  <int value="3" label="Launched setup app"/>
+  <int value="4" label="Clicked find phone"/>
+  <int value="5" label="Find phone error"/>
+  <int value="6" label="Server returned eligible devices"/>
+  <int value="7" label="Remote device connected"/>
+  <int value="8" label="Missing secure lock screen"/>
+  <int value="9" label="Clicked check again after missing secure lock screen"/>
+  <int value="10" label="Clicked pair phone"/>
+  <int value="11" label="Pairing error"/>
+  <int value="12" label="Clicked restart setup after paring error"/>
+  <int value="13" label="Pairing complete"/>
+  <int value="14" label="Showed SmartLock for Android promo"/>
+  <int value="15" label="Acknowledged SmartLock for Android promo"/>
+  <int value="16" label="Showed pairing complete"/>
+  <int value="17" label="Clicked try it out"/>
+  <int value="18" label="Clicked done"/>
+</enum>
+
 <enum name="EasyUnlockSetupState">
   <int value="0" label="Success"/>
   <int value="1" label="Scan (initial)"/>
@@ -26286,6 +26341,7 @@
   <int value="-879031960" label="FetchKeepaliveTimeoutSetting:disabled"/>
   <int value="-876773752" label="enable-tablet-splitview"/>
   <int value="-876148583" label="ArcBootCompletedBroadcast:disabled"/>
+  <int value="-874602599" label="HorizontalTabSwitcherAndroid:enabled"/>
   <int value="-872764392" label="ContextualSuggestionsBottomSheet:disabled"/>
   <int value="-867087281" label="enable-virtual-keyboard"/>
   <int value="-866993841" label="OfflinePagesCTV2:disabled"/>
@@ -27046,6 +27102,7 @@
       label="ContentSuggestionsThumbnailDominantColor:disabled"/>
   <int value="1005684777" label="PictureInPicture:disabled"/>
   <int value="1007444341" label="enable-prefixed-encrypted-media"/>
+  <int value="1012942422" label="HorizontalTabSwitcherAndroid:disabled"/>
   <int value="1015895665" label="drop-sync-credential:enabled"/>
   <int value="1017364362" label="VrIconInDaydreamHome:enabled"/>
   <int value="1018998019" label="memlog"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 61fc5bd..4c5bbbd 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -18592,6 +18592,17 @@
   </summary>
 </histogram>
 
+<histogram name="Download.IOSDownloadFileInBackground"
+    enum="DownloadFileInBackground">
+  <owner>eugenebut@chromium.org</owner>
+  <summary>
+    Logged when the download is completed (successfully or not) or in-progress
+    download was cancelled because of the app termination. This histogram
+    includes information whether the download was successful and whether or not
+    the download task was running while the app was active.
+  </summary>
+</histogram>
+
 <histogram name="Download.IOSDownloadFileResult" enum="DownloadFileResult">
   <owner>bdibello@chromium.org</owner>
   <summary>Result when a user attempts to download a file on iOS.</summary>
@@ -19831,6 +19842,24 @@
   </details>
 </histogram>
 
+<histogram name="EasyUnlock.Setup.Progress.SansPromo"
+    enum="EasyUnlockSetupProgress">
+  <owner>jhawkins@chromium.org</owner>
+  <summary>
+    Records events at each step of the Setup process, when the Setup flow is
+    initiated without the promotion notification.
+  </summary>
+</histogram>
+
+<histogram name="EasyUnlock.Setup.Progress.ViaPromo"
+    enum="EasyUnlockSetupProgress">
+  <owner>jhawkins@chromium.org</owner>
+  <summary>
+    Records events at each step of the Setup process, when the Setup flow is
+    initiated via the promotion notification.
+  </summary>
+</histogram>
+
 <histogram name="EasyUnlock.Setup.PromoNotificationEvent"
     enum="EasyUnlockPromoNotificationEvent">
   <owner>isherman@chromium.org</owner>
@@ -43813,6 +43842,17 @@
   </summary>
 </histogram>
 
+<histogram name="Net.CertVerifier_TrialComparisonResult"
+    enum="CertVerifierTrialComparisonResult">
+  <owner>mattm@chromium.org</owner>
+  <summary>
+    If the CertDualVerificationTrial is enabled, each certificate verification
+    associated with a (non-incognito) profile which is opted-in to SBER2(Scout)
+    will record the outcome of comparing the primary verifier and secondary
+    verifier results.
+  </summary>
+</histogram>
+
 <histogram name="Net.CoalescePotential" enum="CoalescePotentialPackets">
   <obsolete>
     Deprecated 04/2016 as doesn't have data nor owner.
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv
index 9218d8f..b03c748 100644
--- a/tools/perf/benchmark.csv
+++ b/tools/perf/benchmark.csv
@@ -44,6 +44,8 @@
 power.typical_10_mobile,perezju@chromium.org,
 rasterize_and_record_micro.partial_invalidation,"vmpstr@chromium.org, wkorman@chromium.org",Internals>Compositing>Rasterization
 rasterize_and_record_micro.top_25,"vmpstr@chromium.org, wkorman@chromium.org",Internals>Compositing>Rasterization
+rendering.desktop,"sadrul@chromium.org, vmiura@chromium.org",
+rendering.mobile,"sadrul@chromium.org, vmiura@chromium.org",
 resource_sizes,"agrieve@chromium.org, rnephew@chromium.org, perezju@chromium.org",
 scheduler.tough_scheduling_cases,"skyostil@chromium.org, brianderson@chromium.org",
 sizes (linux),thestig@chromium.org,
diff --git a/tools/perf/contrib/vr_benchmarks/BUILD.gn b/tools/perf/contrib/vr_benchmarks/BUILD.gn
index f3c86fc2..848d6e4 100644
--- a/tools/perf/contrib/vr_benchmarks/BUILD.gn
+++ b/tools/perf/contrib/vr_benchmarks/BUILD.gn
@@ -15,6 +15,7 @@
     "./vr_benchmarks.py",
     "./vr_browsing_mode_pages.py",
     "./vr_sample_page.py",
+    "./vr_story_set.py",
     "./webvr_sample_pages.py",
     "./webvr_wpr_pages.py",
     "//chrome/android/shared_preference_files/test/",
diff --git a/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py b/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py
index c62a525b..2816d42d 100644
--- a/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py
+++ b/tools/perf/contrib/vr_benchmarks/shared_android_vr_page_state.py
@@ -4,6 +4,7 @@
 
 import os
 from core import path_util
+from devil.android.sdk import intent  # pylint: disable=import-error
 path_util.AddAndroidPylibToPath()
 from pylib.utils import shared_preference_utils
 from telemetry.core import android_platform
@@ -15,6 +16,22 @@
 
 CARDBOARD_PATH = os.path.join('chrome', 'android', 'shared_preference_files',
                               'test', 'vr_cardboard_skipdon_setupcomplete.json')
+FAKE_TRACKER_COMPONENT = ('com.google.vr.vrcore/'
+                          '.tracking.HeadTrackingService')
+SUPPORTED_POSE_TRACKER_MODES = [
+    'frozen',          # Static pose looking straight forward.
+    'sweep',           # Moves head back and forth horizontally.
+    'rotate',          # Moves head continuously in a circle.
+    'circle_strafe',   # Moves head continuously in a circle (also changes
+                       # position if 6DoF supported?).
+    'motion_sickness', # Moves head in a sort of figure-eight pattern.
+]
+SUPPORTED_POSE_TRACKER_TYPES = [
+    'sensor',    # Standard sensor-fusion-based pose tracker.
+    'tango',     # Tango-based pose tracker.
+    'platform',  # ?
+    'fake',      # Fake pose tracker that can provide pre-defined pose sets.
+]
 
 
 class SharedAndroidVrPageState(shared_page_state.SharedPageState):
@@ -42,6 +59,10 @@
 
     super(SharedAndroidVrPageState, self).__init__(test, finder_options,
                                                    story_set)
+    self._story_set = story_set
+    # Optimization so we're not doing redundant service starts before every
+    # story.
+    self._did_set_tracker = False
     self._PerformAndroidVrSetup()
 
   def _PerformAndroidVrSetup(self):
@@ -64,8 +85,9 @@
     """Configures VrCore using the provided settings file."""
     settings = shared_preference_utils.ExtractSettingsFromJson(filepath)
     for setting in settings:
-      shared_pref = self._platform.GetSharedPrefs(setting['package'],
-                                                  setting['filename'])
+      shared_pref = self._platform.GetSharedPrefs(
+          setting['package'], setting['filename'],
+          use_encrypted_path=setting.get('supports_encrypted_path', False))
       shared_preference_utils.ApplySharedPreferenceSetting(
           shared_pref, setting)
 
@@ -94,13 +116,64 @@
                      'gvr-android-sdk', 'test-apks', 'vr_keyboard',
                      'vr_keyboard_current.apk'))
 
+  def _SetFakePoseTrackerIfNotSet(self):
+    if self._story_set.use_fake_pose_tracker and not self._did_set_tracker:
+      self.SetPoseTrackerType('fake')
+      self.SetPoseTrackerMode('sweep')
+      self._did_set_tracker = True
+
+  def SetPoseTrackerType(self, tracker_type):
+    """Sets the VrCore pose tracker to the given type.
+
+    Only works if VrCore has been configured to use the VrCore-side tracker
+    by setting EnableVrCoreHeadTracking to true. This setting persists between
+    VR sessions and Chrome restarts.
+
+    Args:
+      tracker_type: A string corresponding to the tracker type to set.
+
+    Raises:
+      RuntimeError if the given |tracker_type| is not in the supported list.
+    """
+    if tracker_type not in SUPPORTED_POSE_TRACKER_TYPES:
+      raise RuntimeError('Given tracker %s is not supported.' % tracker_type)
+    self.platform.StartAndroidService(start_intent=intent.Intent(
+        action='com.google.vr.vrcore.SET_TRACKER_TYPE',
+        component=FAKE_TRACKER_COMPONENT,
+        extras={'com.google.vr.vrcore.TRACKER_TYPE': tracker_type}))
+
+  def SetPoseTrackerMode(self, tracker_mode):
+    """Sets the fake VrCore pose tracker to provide poses in the given mode.
+
+    Only works after SetPoseTrackerType has been set to 'fake'. This setting
+    persists between VR sessions and Chrome restarts.
+
+    Args:
+      tracker_mode: A string corresponding to the tracker mode to set.
+
+    Raises:
+      RuntimeError if the given |tracker_mode| is not in the supported list.
+    """
+    if tracker_mode not in SUPPORTED_POSE_TRACKER_MODES:
+      raise RuntimeError('Given mode %s is not supported.' % tracker_mode)
+    self.platform.StartAndroidService(start_intent=intent.Intent(
+        action='com.google.vr.vrcore.SET_FAKE_TRACKER_MODE',
+        component=FAKE_TRACKER_COMPONENT,
+        extras={'com.google.vr.vrcore.FAKE_TRACKER_MODE': tracker_mode}))
+
   def WillRunStory(self, page):
     super(SharedAndroidVrPageState, self).WillRunStory(page)
     if not self._finder_options.disable_screen_reset:
       self._CycleScreen()
+    self._SetFakePoseTrackerIfNotSet()
 
   def TearDownState(self):
     super(SharedAndroidVrPageState, self).TearDownState()
+    # Reset the tracker type to use the actual sensor if it's been changed. When
+    # run on the bots, this shouldn't matter since the service will be killed
+    # during the automatic restart, but this could persist when run locally.
+    if self._did_set_tracker:
+      self.SetPoseTrackerType('sensor')
     # Re-apply Cardboard as the viewer to leave the device in a consistent
     # state after a benchmark run
     # TODO(bsheedy): Remove this after crbug.com/772969 is fixed
diff --git a/tools/perf/contrib/vr_benchmarks/vr_browsing_mode_pages.py b/tools/perf/contrib/vr_benchmarks/vr_browsing_mode_pages.py
index 28d9488..9e70b40 100644
--- a/tools/perf/contrib/vr_benchmarks/vr_browsing_mode_pages.py
+++ b/tools/perf/contrib/vr_benchmarks/vr_browsing_mode_pages.py
@@ -9,6 +9,7 @@
 from devil.android.sdk import intent  # pylint: disable=import-error
 from contrib.vr_benchmarks import shared_android_vr_page_state as vr_state
 from contrib.vr_benchmarks.vr_sample_page import VrSamplePage
+from contrib.vr_benchmarks.vr_story_set import VrStorySet
 from page_sets import top_10_mobile
 
 
@@ -80,24 +81,26 @@
     return self._shared_page_state.platform
 
 
-class VrBrowsingModePageSet(story.StorySet):
+class VrBrowsingModePageSet(VrStorySet):
   """Pageset for VR Browsing Mode tests on sample pages."""
 
-  def __init__(self):
-    super(VrBrowsingModePageSet, self).__init__()
+  def __init__(self, use_fake_pose_tracker=True):
+    super(VrBrowsingModePageSet, self).__init__(
+        use_fake_pose_tracker=use_fake_pose_tracker)
     self.AddStory(Simple2dStillPage(self))
 
 
-class VrBrowsingModeWprPageSet(story.StorySet):
+class VrBrowsingModeWprPageSet(VrStorySet):
   """Pageset for VR browsing mode on WPR recordings of live sites.
 
   Re-uses the URL list and WPR archive from the memory.top_10_mobile benchmark.
   """
 
-  def __init__(self):
+  def __init__(self, use_fake_pose_tracker=True):
     super(VrBrowsingModeWprPageSet, self).__init__(
         archive_data_file='../../page_sets/data/memory_top_10_mobile.json',
-        cloud_storage_bucket=story.PARTNER_BUCKET)
+        cloud_storage_bucket=story.PARTNER_BUCKET,
+        use_fake_pose_tracker=use_fake_pose_tracker)
 
     for url in top_10_mobile.URL_LIST:
       name = re.sub(r'\W+', '_', url)
diff --git a/tools/perf/contrib/vr_benchmarks/vr_story_set.py b/tools/perf/contrib/vr_benchmarks/vr_story_set.py
new file mode 100644
index 0000000..8d8adb3
--- /dev/null
+++ b/tools/perf/contrib/vr_benchmarks/vr_story_set.py
@@ -0,0 +1,16 @@
+# Copyright 2018 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.
+
+
+from telemetry import story
+
+
+class VrStorySet(story.StorySet):
+  def __init__(self, use_fake_pose_tracker=True, **kwargs):
+    self._use_fake_pose_tracker = use_fake_pose_tracker
+    super(VrStorySet, self).__init__(**kwargs)
+
+  @property
+  def use_fake_pose_tracker(self):
+    return self._use_fake_pose_tracker
diff --git a/tools/perf/contrib/vr_benchmarks/webvr_sample_pages.py b/tools/perf/contrib/vr_benchmarks/webvr_sample_pages.py
index a6950389..634fa144 100644
--- a/tools/perf/contrib/vr_benchmarks/webvr_sample_pages.py
+++ b/tools/perf/contrib/vr_benchmarks/webvr_sample_pages.py
@@ -2,8 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from telemetry import story
 from contrib.vr_benchmarks.vr_sample_page import VrSamplePage
+from contrib.vr_benchmarks.vr_story_set import VrStorySet
 
 
 class WebVrSamplePage(VrSamplePage):
@@ -25,11 +25,12 @@
     action_runner.Navigate("about:blank")
 
 
-class WebVrSamplePageSet(story.StorySet):
+class WebVrSamplePageSet(VrStorySet):
   """A page set using the official WebVR sample with settings tweaked."""
 
-  def __init__(self):
-    super(WebVrSamplePageSet, self).__init__()
+  def __init__(self, use_fake_pose_tracker=True):
+    super(WebVrSamplePageSet, self).__init__(
+        use_fake_pose_tracker=use_fake_pose_tracker)
 
     # Test cases that use the synthetic cube field page
     cube_test_cases = [
diff --git a/tools/perf/contrib/vr_benchmarks/webvr_wpr_pages.py b/tools/perf/contrib/vr_benchmarks/webvr_wpr_pages.py
index 1322a53f..965ff811 100644
--- a/tools/perf/contrib/vr_benchmarks/webvr_wpr_pages.py
+++ b/tools/perf/contrib/vr_benchmarks/webvr_wpr_pages.py
@@ -5,6 +5,7 @@
 from telemetry import story
 from telemetry import page
 from contrib.vr_benchmarks import (shared_android_vr_page_state as vr_state)
+from contrib.vr_benchmarks.vr_story_set import VrStorySet
 
 class WebVrWprPage(page.Page):
   """Class for running a story on a WebVR WPR page."""
@@ -50,13 +51,14 @@
     return self._shared_page_state.recording_wpr
 
 
-class WebVrWprPageSet(story.StorySet):
+class WebVrWprPageSet(VrStorySet):
   """A page set using live WebVR sites recorded using WPR."""
 
-  def __init__(self):
+  def __init__(self, use_fake_pose_tracker=True):
     super(WebVrWprPageSet, self).__init__(
         archive_data_file='data/webvr_wpr.json',
-        cloud_storage_bucket=story.PARTNER_BUCKET)
+        cloud_storage_bucket=story.PARTNER_BUCKET,
+        use_fake_pose_tracker=use_fake_pose_tracker)
 
     # View the Pirates: Dock model on Sketchfab
     def SketchfabInteraction(action_runner, _):
@@ -112,8 +114,9 @@
   Also contains sites that we would like to run with WPR, but that interact
   badly when replayed. So, access the live version instead.
   """
-  def __init__(self):
-    super(WebVrLivePageSet, self).__init__()
+  def __init__(self, use_fake_pose_tracker=True):
+    super(WebVrLivePageSet, self).__init__(
+        use_fake_pose_tracker=use_fake_pose_tracker)
 
     # Look at "randomly" generated (constant seed) geometry in Mass Migrations
     # Not usable via WPR due to it often not submitting frames while using WPR
diff --git a/tools/perf/core/benchmark_android_bot_map.json b/tools/perf/core/benchmark_android_bot_map.json
index eb61882b..9f20ba9 100644
--- a/tools/perf/core/benchmark_android_bot_map.json
+++ b/tools/perf/core/benchmark_android_bot_map.json
@@ -55,12 +55,14 @@
   },
   "16": {
     "benchmarks": [
-      "smoothness.top_25_smooth"
+      "smoothness.top_25_smooth",
+      "rendering.mobile"
     ]
   },
   "17": {
     "benchmarks": [
-      "smoothness.tough_ad_cases"
+      "smoothness.tough_ad_cases",
+      "rendering.desktop"
     ]
   },
   "18": {
diff --git a/tools/perf/core/benchmark_desktop_bot_map.json b/tools/perf/core/benchmark_desktop_bot_map.json
index 08e29b5..a86ff5f 100644
--- a/tools/perf/core/benchmark_desktop_bot_map.json
+++ b/tools/perf/core/benchmark_desktop_bot_map.json
@@ -64,11 +64,13 @@
   "16": {
     "benchmarks": [
       "smoothness.gpu_rasterization.tough_filters_cases",
-      "speedometer-future"
+      "speedometer-future",
+       "rendering.mobile"
     ]
   },
   "17": {
     "benchmarks": [
+      "rendering.desktop",
       "smoothness.gpu_rasterization.tough_path_rendering_cases",
       "speedometer2"
     ]
diff --git a/tools/perf/core/benchmark_sharding_map.json b/tools/perf/core/benchmark_sharding_map.json
index e971c62..18a61604 100644
--- a/tools/perf/core/benchmark_sharding_map.json
+++ b/tools/perf/core/benchmark_sharding_map.json
@@ -22,7 +22,8 @@
       "benchmarks": [
         "blink_perf.image_decoder",
         "blink_perf.owp_storage",
-        "wasm"
+        "wasm",
+	"rendering.desktop"
       ]
     },
     "build13-b1--device4": {
@@ -168,6 +169,7 @@
       "benchmarks": [
         "blink_perf.paint",
         "kraken",
+        "rendering.mobile",
         "smoothness.key_mobile_sites_smooth",
         "tracing.tracing_with_background_memory_infra"
       ]
@@ -199,7 +201,8 @@
       "benchmarks": [
         "blink_perf.image_decoder",
         "blink_perf.owp_storage",
-        "wasm"
+        "wasm",
+	"rendering.desktop"
       ]
     },
     "build73-b1--device4": {
@@ -345,6 +348,7 @@
       "benchmarks": [
         "blink_perf.paint",
         "kraken",
+        "rendering.mobile",
         "smoothness.key_mobile_sites_smooth",
         "tracing.tracing_with_background_memory_infra"
       ]
@@ -379,7 +383,8 @@
         "blink_perf.image_decoder",
         "blink_perf.owp_storage",
         "system_health.common_desktop",
-        "wasm"
+        "wasm",
+	"rendering.desktop"
       ]
     },
     "build164-b1--device4": {
@@ -478,6 +483,7 @@
     "build166-b1--device1": {
       "benchmarks": [
         "kraken",
+        "rendering.mobile",
         "loading.mobile",
         "media.mobile",
         "smoothness.tough_filters_cases"
@@ -553,7 +559,8 @@
       "benchmarks": [
         "blink_perf.image_decoder",
         "blink_perf.owp_storage",
-        "wasm"
+        "wasm",
+	"rendering.desktop"
       ]
     },
     "build15-b1--device4": {
@@ -699,6 +706,7 @@
       "benchmarks": [
         "blink_perf.paint",
         "kraken",
+        "rendering.mobile",
         "smoothness.key_mobile_sites_smooth",
         "tracing.tracing_with_background_memory_infra"
       ]
@@ -731,7 +739,8 @@
         "blink_perf.image_decoder",
         "blink_perf.owp_storage",
         "system_health.common_desktop",
-        "wasm"
+        "wasm",
+	"rendering.desktop"
       ]
     },
     "build112-b1--device4": {
@@ -832,6 +841,7 @@
     "build114-b1--device1": {
       "benchmarks": [
         "kraken",
+        "rendering.mobile",
         "loading.mobile",
         "media.mobile",
         "smoothness.tough_filters_cases"
@@ -919,7 +929,8 @@
         "smoothness.image_decoding_cases",
         "smoothness.pathological_mobile_sites",
         "smoothness.tough_pinch_zoom_cases",
-        "wasm"
+        "wasm",
+	"rendering.desktop"
       ]
     },
     "build10-b1--device4": {
@@ -1007,6 +1018,7 @@
       "benchmarks": [
         "blink_perf.paint",
         "kraken",
+        "rendering.mobile",
         "smoothness.key_mobile_sites_smooth",
         "tracing.tracing_with_background_memory_infra"
       ]
@@ -1084,7 +1096,8 @@
       "benchmarks": [
         "blink_perf.image_decoder",
         "blink_perf.owp_storage",
-        "wasm"
+        "wasm",
+	"rendering.desktop"
       ]
     },
     "build17-b1--device4": {
@@ -1113,6 +1126,7 @@
     "build17-b1--device7": {
       "benchmarks": [
         "kraken",
+        "rendering.mobile",
         "power.idle_platform"
       ]
     },
@@ -1262,7 +1276,8 @@
         "blink_perf.owp_storage",
         "speedometer-future",
         "speedometer2-future",
-        "wasm"
+        "wasm",
+	"rendering.desktop"
       ]
     },
     "build245-m4--device4": {
@@ -1406,6 +1421,7 @@
       "benchmarks": [
         "blink_perf.paint",
         "kraken",
+        "rendering.mobile",
         "smoothness.key_mobile_sites_smooth",
         "tracing.tracing_with_background_memory_infra"
       ]
@@ -1485,7 +1501,8 @@
         "thread_times.tough_compositor_cases",
         "v8.browsing_desktop-future",
         "v8.browsing_mobile-future",
-        "wasm"
+        "wasm",
+	"rendering.desktop"
       ]
     },
     "build30-a9": {
@@ -1516,6 +1533,7 @@
         "media.desktop",
         "memory.long_running_idle_gmail_tbmv2",
         "rasterize_and_record_micro.partial_invalidation",
+        "rendering.mobile",
         "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -1598,7 +1616,8 @@
         "thread_times.tough_compositor_cases",
         "v8.browsing_desktop-future",
         "v8.browsing_mobile-future",
-        "wasm"
+        "wasm",
+	"rendering.desktop"
       ]
     },
     "build105-b1": {
@@ -1630,6 +1649,7 @@
         "media.desktop",
         "memory.long_running_idle_gmail_tbmv2",
         "rasterize_and_record_micro.partial_invalidation",
+        "rendering.mobile",
         "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -1698,6 +1718,7 @@
         "dromaeo",
         "memory.long_running_idle_gmail_background_tbmv2",
         "rasterize_and_record_micro.top_25",
+	"rendering.desktop",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
         "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
@@ -1744,6 +1765,7 @@
         "media.desktop",
         "memory.long_running_idle_gmail_tbmv2",
         "rasterize_and_record_micro.partial_invalidation",
+        "rendering.mobile",
         "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -1811,6 +1833,7 @@
         "dromaeo",
         "memory.long_running_idle_gmail_background_tbmv2",
         "rasterize_and_record_micro.top_25",
+	"rendering.desktop",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
         "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
@@ -1858,6 +1881,7 @@
         "media.desktop",
         "memory.long_running_idle_gmail_tbmv2",
         "rasterize_and_record_micro.partial_invalidation",
+        "rendering.mobile",
         "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -1927,6 +1951,7 @@
         "dromaeo",
         "memory.long_running_idle_gmail_background_tbmv2",
         "rasterize_and_record_micro.top_25",
+	"rendering.desktop",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
         "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
@@ -1972,6 +1997,7 @@
         "media.desktop",
         "memory.long_running_idle_gmail_tbmv2",
         "rasterize_and_record_micro.partial_invalidation",
+        "rendering.mobile",
         "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -2001,6 +2027,7 @@
         "media.desktop",
         "memory.long_running_idle_gmail_tbmv2",
         "rasterize_and_record_micro.partial_invalidation",
+        "rendering.mobile",
         "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -2047,6 +2074,7 @@
         "octane",
         "oortonline_tbmv2",
         "power.idle_platform",
+	"rendering.desktop",
         "smoothness.key_silk_cases",
         "smoothness.pathological_mobile_sites",
         "smoothness.top_25_smooth",
@@ -2162,6 +2190,7 @@
         "dromaeo",
         "memory.long_running_idle_gmail_background_tbmv2",
         "rasterize_and_record_micro.top_25",
+	"rendering.desktop",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
         "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
@@ -2208,6 +2237,7 @@
         "media.desktop",
         "memory.long_running_idle_gmail_tbmv2",
         "rasterize_and_record_micro.partial_invalidation",
+        "rendering.mobile",
         "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -2277,6 +2307,7 @@
         "dromaeo",
         "memory.long_running_idle_gmail_background_tbmv2",
         "rasterize_and_record_micro.top_25",
+        "rendering.desktop",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
         "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
@@ -2323,6 +2354,7 @@
         "media.desktop",
         "memory.long_running_idle_gmail_tbmv2",
         "rasterize_and_record_micro.partial_invalidation",
+        "rendering.mobile",
         "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -2389,6 +2421,7 @@
         "dromaeo",
         "memory.long_running_idle_gmail_background_tbmv2",
         "rasterize_and_record_micro.top_25",
+	"rendering.desktop",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
         "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
@@ -2436,6 +2469,7 @@
         "media.desktop",
         "memory.long_running_idle_gmail_tbmv2",
         "rasterize_and_record_micro.partial_invalidation",
+        "rendering.mobile",
         "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -2504,6 +2538,7 @@
         "dromaeo",
         "memory.long_running_idle_gmail_background_tbmv2",
         "rasterize_and_record_micro.top_25",
+	"rendering.desktop",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
         "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
@@ -2550,6 +2585,7 @@
         "media.desktop",
         "memory.long_running_idle_gmail_tbmv2",
         "rasterize_and_record_micro.partial_invalidation",
+        "rendering.mobile",
         "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -2618,6 +2654,7 @@
         "dromaeo",
         "memory.long_running_idle_gmail_background_tbmv2",
         "rasterize_and_record_micro.top_25",
+	"rendering.desktop",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
         "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
@@ -2664,6 +2701,7 @@
         "media.desktop",
         "memory.long_running_idle_gmail_tbmv2",
         "rasterize_and_record_micro.partial_invalidation",
+        "rendering.mobile",
         "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -2732,6 +2770,7 @@
         "dromaeo",
         "memory.long_running_idle_gmail_background_tbmv2",
         "rasterize_and_record_micro.top_25",
+	"rendering.desktop",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
         "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
@@ -2778,6 +2817,7 @@
         "media.desktop",
         "memory.long_running_idle_gmail_tbmv2",
         "rasterize_and_record_micro.partial_invalidation",
+        "rendering.mobile",
         "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -2846,6 +2886,7 @@
         "dromaeo",
         "memory.long_running_idle_gmail_background_tbmv2",
         "rasterize_and_record_micro.top_25",
+	"rendering.desktop",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
         "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
@@ -2892,6 +2933,7 @@
         "media.desktop",
         "memory.long_running_idle_gmail_tbmv2",
         "rasterize_and_record_micro.partial_invalidation",
+        "rendering.mobile",
         "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -2960,6 +3002,7 @@
         "dromaeo",
         "memory.long_running_idle_gmail_background_tbmv2",
         "rasterize_and_record_micro.top_25",
+	"rendering.desktop",
         "smoothness.gpu_rasterization.polymer",
         "smoothness.gpu_rasterization.top_25_smooth",
         "smoothness.gpu_rasterization_and_decoding.image_decoding_cases",
@@ -3006,6 +3049,7 @@
         "media.desktop",
         "memory.long_running_idle_gmail_tbmv2",
         "rasterize_and_record_micro.partial_invalidation",
+        "rendering.mobile",
         "smoothness.desktop_tough_pinch_zoom_cases",
         "smoothness.gpu_rasterization.tough_path_rendering_cases",
         "smoothness.gpu_rasterization.tough_scrolling_cases",
@@ -3058,6 +3102,8 @@
     "power.typical_10_mobile",
     "rasterize_and_record_micro.partial_invalidation",
     "rasterize_and_record_micro.top_25",
+    "rendering.desktop",
+    "rendering.mobile",
     "scheduler.tough_scheduling_cases",
     "smoothness.desktop_tough_pinch_zoom_cases",
     "smoothness.gpu_rasterization.polymer",
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 334274f..529f4ad 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -35,9 +35,7 @@
 
 
 _UNSCHEDULED_TELEMETRY_BENCHMARKS = set([
-  'experimental.startup.android.coldish',
-  'rendering.desktop',
-  'rendering.mobile'
+  'experimental.startup.android.coldish'
   ])
 
 
diff --git a/ui/app_list/views/app_list_item_view.cc b/ui/app_list/views/app_list_item_view.cc
index c878539d..a5cdde4 100644
--- a/ui/app_list/views/app_list_item_view.cc
+++ b/ui/app_list/views/app_list_item_view.cc
@@ -299,12 +299,15 @@
   context_menu_items_ = std::move(menu);
 
   UMA_HISTOGRAM_ENUMERATION("Apps.ContextMenuShowSource.AppGrid", source_type,
-                            ui::MenuSourceType::MENU_SOURCE_TYPE_LAST);
+                            ui::MENU_SOURCE_TYPE_LAST);
 
   if (!apps_grid_view_->IsSelectedView(this))
     apps_grid_view_->ClearAnySelectedView();
-  int run_types = views::MenuRunner::HAS_MNEMONICS |
-                  views::MenuRunner::SEND_GESTURE_EVENTS_TO_OWNER;
+  int run_types = views::MenuRunner::HAS_MNEMONICS;
+
+  if (source_type == ui::MENU_SOURCE_TOUCH)
+    run_types |= views::MenuRunner::SEND_GESTURE_EVENTS_TO_OWNER;
+
   views::MenuAnchorPosition anchor_position = views::MENU_ANCHOR_TOPLEFT;
   gfx::Rect anchor_rect = gfx::Rect(point, gfx::Size());
 
@@ -313,7 +316,7 @@
                  views::MenuRunner::FIXED_ANCHOR |
                  views::MenuRunner::CONTEXT_MENU;
     anchor_position = views::MENU_ANCHOR_BUBBLE_TOUCHABLE_LEFT;
-    if (source_type == ui::MenuSourceType::MENU_SOURCE_TOUCH) {
+    if (source_type == ui::MENU_SOURCE_TOUCH) {
       // When a context menu is shown by touch, the app icon is temporarily
       // enlarged, so use the ideal bounds instead of the current bounds for the
       // anchor rect.
@@ -340,8 +343,6 @@
       item_weak_->id(),
       base::BindOnce(&AppListItemView::OnContextMenuModelReceived,
                      weak_ptr_factory_.GetWeakPtr(), point, source_type));
-
-  source->RequestFocus();
 }
 
 bool AppListItemView::IsCommandIdChecked(int command_id) const {
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc
index 87ae87e..36c2f321 100644
--- a/ui/app_list/views/search_box_view.cc
+++ b/ui/app_list/views/search_box_view.cc
@@ -88,6 +88,28 @@
   view_delegate_->RemoveObserver(this);
 }
 
+void SearchBoxView::ClearSearch() {
+  search_box::SearchBoxViewBase::ClearSearch();
+  app_list_view_->SetStateFromSearchBoxView(true);
+}
+
+views::View* SearchBoxView::GetSelectedViewInContentsView() {
+  if (!contents_view())
+    return nullptr;
+  return static_cast<ContentsView*>(contents_view())->GetSelectedView();
+}
+
+void SearchBoxView::HandleSearchBoxEvent(ui::LocatedEvent* located_event) {
+  if (located_event->type() == ui::ET_MOUSEWHEEL) {
+    if (!app_list_view_->HandleScroll(
+            located_event->AsMouseWheelEvent()->offset().y(),
+            ui::ET_MOUSEWHEEL)) {
+      return;
+    }
+  }
+  search_box::SearchBoxViewBase::HandleSearchBoxEvent(located_event);
+}
+
 void SearchBoxView::ModelChanged() {
   if (search_model_)
     search_model_->search_box()->RemoveObserver(this);
@@ -101,11 +123,6 @@
   OnWallpaperColorsChanged();
 }
 
-void SearchBoxView::ClearSearch() {
-  search_box::SearchBoxViewBase::ClearSearch();
-  app_list_view_->SetStateFromSearchBoxView(true);
-}
-
 void SearchBoxView::UpdateKeyboardVisibility() {
   if (!is_tablet_mode())
     return;
@@ -126,15 +143,65 @@
       keyboard::KeyboardController::HIDE_REASON_MANUAL);
 }
 
-void SearchBoxView::HandleSearchBoxEvent(ui::LocatedEvent* located_event) {
-  if (located_event->type() == ui::ET_MOUSEWHEEL) {
-    if (!app_list_view_->HandleScroll(
-            located_event->AsMouseWheelEvent()->offset().y(),
-            ui::ET_MOUSEWHEEL)) {
-      return;
-    }
+void SearchBoxView::UpdateModel(bool initiated_by_user) {
+  // Temporarily remove from observer to ignore notifications caused by us.
+  search_model_->search_box()->RemoveObserver(this);
+  search_model_->search_box()->Update(search_box()->text(), initiated_by_user);
+  search_model_->search_box()->SetSelectionModel(
+      search_box()->GetSelectionModel());
+  search_model_->search_box()->AddObserver(this);
+}
+
+void SearchBoxView::UpdateSearchIcon() {
+  const gfx::VectorIcon& google_icon =
+      is_search_box_active() ? kIcGoogleColorIcon : kIcGoogleBlackIcon;
+  const gfx::VectorIcon& icon = search_model_->search_engine_is_google()
+                                    ? google_icon
+                                    : kIcSearchEngineNotGoogleIcon;
+  SetSearchIconImage(gfx::CreateVectorIcon(icon, search_box::kSearchIconSize,
+                                           search_box_color()));
+}
+
+void SearchBoxView::UpdateSearchBoxBorder() {
+  if (search_box()->HasFocus() && !is_search_box_active()) {
+    // Show a gray ring around search box to indicate that the search box is
+    // selected. Do not show it when search box is active, because blinking
+    // cursor already indicates that.
+    SetBorder(views::CreateRoundedRectBorder(kSearchBoxBorderWidth,
+                                             kSearchBoxFocusBorderCornerRadius,
+                                             kSearchBoxBorderColor));
+    return;
   }
-  search_box::SearchBoxViewBase::HandleSearchBoxEvent(located_event);
+
+  // Creates an empty border as a placeholder for colored border so that
+  // re-layout won't move views below the search box.
+  SetBorder(
+      views::CreateEmptyBorder(kSearchBoxBorderWidth, kSearchBoxBorderWidth,
+                               kSearchBoxBorderWidth, kSearchBoxBorderWidth));
+}
+
+void SearchBoxView::SetupCloseButton() {
+  views::ImageButton* close = close_button();
+  close->SetImage(views::ImageButton::STATE_NORMAL,
+                  gfx::CreateVectorIcon(views::kIcCloseIcon, kCloseIconSize,
+                                        search_box_color()));
+  close->SetVisible(false);
+  close->SetAccessibleName(
+      l10n_util::GetStringUTF16(IDS_APP_LIST_CLEAR_SEARCHBOX));
+}
+
+void SearchBoxView::SetupBackButton() {
+  views::ImageButton* back = back_button();
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  back->SetImage(views::ImageButton::STATE_NORMAL,
+                 rb.GetImageSkiaNamed(IDR_APP_LIST_FOLDER_BACK_NORMAL));
+  back->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
+                          views::ImageButton::ALIGN_MIDDLE);
+  back->SetVisible(false);
+  base::string16 back_button_label(
+      l10n_util::GetStringUTF16(IDS_APP_LIST_BACK));
+  back->SetAccessibleName(back_button_label);
+  back->SetTooltipText(back_button_label);
 }
 
 void SearchBoxView::OnKeyEvent(ui::KeyEvent* event) {
@@ -227,36 +294,32 @@
       should_restore_opacity ? 1.0f : opacity);
 }
 
-views::View* SearchBoxView::GetSelectedViewInContentsView() {
-  if (!contents_view())
-    return nullptr;
-  return static_cast<ContentsView*>(contents_view())->GetSelectedView();
-}
-
-void SearchBoxView::UpdateModel(bool initiated_by_user) {
-  // Temporarily remove from observer to ignore notifications caused by us.
-  search_model_->search_box()->RemoveObserver(this);
-  search_model_->search_box()->Update(search_box()->text(), initiated_by_user);
-  search_model_->search_box()->SetSelectionModel(
-      search_box()->GetSelectionModel());
-  search_model_->search_box()->AddObserver(this);
-}
-
-void SearchBoxView::UpdateSearchIcon() {
-  const gfx::VectorIcon& google_icon =
-      is_search_box_active() ? kIcGoogleColorIcon : kIcGoogleBlackIcon;
-  const gfx::VectorIcon& icon = search_model_->search_engine_is_google()
-                                    ? google_icon
-                                    : kIcSearchEngineNotGoogleIcon;
-  SetSearchIconImage(gfx::CreateVectorIcon(icon, search_box::kSearchIconSize,
-                                           search_box_color()));
-}
-
 void SearchBoxView::GetWallpaperProminentColors(
     AppListViewDelegate::GetWallpaperProminentColorsCallback callback) {
   view_delegate_->GetWallpaperProminentColors(std::move(callback));
 }
 
+void SearchBoxView::OnWallpaperProminentColorsReceived(
+    const std::vector<SkColor>& prominent_colors) {
+  if (prominent_colors.empty())
+    return;
+  DCHECK_EQ(static_cast<size_t>(ColorProfileType::NUM_OF_COLOR_PROFILES),
+            prominent_colors.size());
+
+  SetSearchBoxColor(
+      prominent_colors[static_cast<int>(ColorProfileType::DARK_MUTED)]);
+  SetBackgroundColor(
+      prominent_colors[static_cast<int>(ColorProfileType::LIGHT_VIBRANT)]);
+  UpdateSearchIcon();
+  close_button()->SetImage(
+      views::Button::STATE_NORMAL,
+      gfx::CreateVectorIcon(views::kIcCloseIcon, kCloseIconSize,
+                            search_box_color()));
+  search_box()->set_placeholder_text_color(search_box_color());
+  UpdateBackgroundColor(background_color());
+  SchedulePaint();
+}
+
 void SearchBoxView::ContentsChanged(views::Textfield* sender,
                                     const base::string16& new_contents) {
   search_box::SearchBoxViewBase::ContentsChanged(sender, new_contents);
@@ -323,73 +386,10 @@
   UpdateSearchIcon();
 }
 
-void SearchBoxView::OnWallpaperProminentColorsReceived(
-    const std::vector<SkColor>& prominent_colors) {
-  if (prominent_colors.empty())
-    return;
-  DCHECK_EQ(static_cast<size_t>(ColorProfileType::NUM_OF_COLOR_PROFILES),
-            prominent_colors.size());
-
-  SetSearchBoxColor(
-      prominent_colors[static_cast<int>(ColorProfileType::DARK_MUTED)]);
-  SetBackgroundColor(
-      prominent_colors[static_cast<int>(ColorProfileType::LIGHT_VIBRANT)]);
-  UpdateSearchIcon();
-  close_button()->SetImage(
-      views::Button::STATE_NORMAL,
-      gfx::CreateVectorIcon(views::kIcCloseIcon, kCloseIconSize,
-                            search_box_color()));
-  search_box()->set_placeholder_text_color(search_box_color());
-  UpdateBackgroundColor(background_color());
-  SchedulePaint();
-}
-
 void SearchBoxView::OnWallpaperColorsChanged() {
   GetWallpaperProminentColors(
       base::BindOnce(&SearchBoxView::OnWallpaperProminentColorsReceived,
                      weak_ptr_factory_.GetWeakPtr()));
 }
 
-void SearchBoxView::UpdateSearchBoxBorder() {
-  if (search_box()->HasFocus() && !is_search_box_active()) {
-    // Show a gray ring around search box to indicate that the search box is
-    // selected. Do not show it when search box is active, because blinking
-    // cursor already indicates that.
-    SetBorder(views::CreateRoundedRectBorder(kSearchBoxBorderWidth,
-                                             kSearchBoxFocusBorderCornerRadius,
-                                             kSearchBoxBorderColor));
-    return;
-  }
-
-  // Creates an empty border as a placeholder for colored border so that
-  // re-layout won't move views below the search box.
-  SetBorder(
-      views::CreateEmptyBorder(kSearchBoxBorderWidth, kSearchBoxBorderWidth,
-                               kSearchBoxBorderWidth, kSearchBoxBorderWidth));
-}
-
-void SearchBoxView::SetupBackButton() {
-  views::ImageButton* back = back_button();
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  back->SetImage(views::ImageButton::STATE_NORMAL,
-                 rb.GetImageSkiaNamed(IDR_APP_LIST_FOLDER_BACK_NORMAL));
-  back->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                          views::ImageButton::ALIGN_MIDDLE);
-  back->SetVisible(false);
-  base::string16 back_button_label(
-      l10n_util::GetStringUTF16(IDS_APP_LIST_BACK));
-  back->SetAccessibleName(back_button_label);
-  back->SetTooltipText(back_button_label);
-}
-
-void SearchBoxView::SetupCloseButton() {
-  views::ImageButton* close = close_button();
-  close->SetImage(views::ImageButton::STATE_NORMAL,
-                  gfx::CreateVectorIcon(views::kIcCloseIcon, kCloseIconSize,
-                                        search_box_color()));
-  close->SetVisible(false);
-  close->SetAccessibleName(
-      l10n_util::GetStringUTF16(IDS_APP_LIST_CLEAR_SEARCHBOX));
-}
-
 }  // namespace app_list
diff --git a/ui/app_list/views/search_box_view.h b/ui/app_list/views/search_box_view.h
index 51aee46d..7b066cf 100644
--- a/ui/app_list/views/search_box_view.h
+++ b/ui/app_list/views/search_box_view.h
@@ -38,10 +38,16 @@
   ~SearchBoxView() override;
 
   // Overridden from search_box::SearchBoxViewBase:
-  void ModelChanged() override;
   void ClearSearch() override;
-  void UpdateKeyboardVisibility() override;
+  views::View* GetSelectedViewInContentsView() override;
   void HandleSearchBoxEvent(ui::LocatedEvent* located_event) override;
+  void ModelChanged() override;
+  void UpdateKeyboardVisibility() override;
+  void UpdateModel(bool initiated_by_user) override;
+  void UpdateSearchIcon() override;
+  void UpdateSearchBoxBorder() override;
+  void SetupCloseButton() override;
+  void SetupBackButton() override;
 
   // Overridden from views::View:
   void OnKeyEvent(ui::KeyEvent* evetn) override;
@@ -66,14 +72,7 @@
   // Updates the opacity of the searchbox.
   void UpdateOpacity();
 
-  // Overridden from search_box::SearchBoxViewBase:
-  views::View* GetSelectedViewInContentsView() override;
-
  private:
-  // Overridden from search_box::SearchBoxViewBase:
-  void UpdateModel(bool initiated_by_user) override;
-  void UpdateSearchIcon() override;
-
   // Gets the wallpaper prominent colors.
   void GetWallpaperProminentColors(
       AppListViewDelegate::GetWallpaperProminentColorsCallback callback);
@@ -100,11 +99,6 @@
   // Overridden from AppListViewDelegateObserver:
   void OnWallpaperColorsChanged() override;
 
-  // Overridden from search_box::SearchBoxViewBase:
-  void UpdateSearchBoxBorder() override;
-  void SetupBackButton() override;
-  void SetupCloseButton() override;
-
   AppListViewDelegate* view_delegate_;  // Not owned.
   SearchModel* search_model_ = nullptr;  // Owned by the profile-keyed service.
 
diff --git a/ui/chromeos/search_box/search_box_view_base.cc b/ui/chromeos/search_box/search_box_view_base.cc
index 71e4f70..b538133 100644
--- a/ui/chromeos/search_box/search_box_view_base.cc
+++ b/ui/chromeos/search_box/search_box_view_base.cc
@@ -227,15 +227,6 @@
   return !search_box_->text().empty();
 }
 
-void SearchBoxViewBase::ClearSearch() {
-  search_box_->SetText(base::string16());
-  UpdateCloseButtonVisisbility();
-  // Updates model and fires query changed manually because SetText() above
-  // does not generate ContentsChanged() notification.
-  UpdateModel(false);
-  NotifyQueryChanged();
-}
-
 gfx::Rect SearchBoxViewBase::GetViewBoundsForSearchBoxContentsBounds(
     const gfx::Rect& rect) const {
   gfx::Rect view_bounds = rect;
@@ -286,22 +277,6 @@
   SchedulePaint();
 }
 
-void SearchBoxViewBase::HandleSearchBoxEvent(ui::LocatedEvent* located_event) {
-  if (located_event->type() == ui::ET_MOUSE_PRESSED ||
-      located_event->type() == ui::ET_GESTURE_TAP) {
-    bool event_is_in_searchbox_bounds =
-        GetWidget()->GetWindowBoundsInScreen().Contains(
-            located_event->root_location());
-    if (is_search_box_active_ || !event_is_in_searchbox_bounds ||
-        !search_box_->text().empty())
-      return;
-    // If the event was within the searchbox bounds and in an inactive empty
-    // search box, enable the search box.
-    SetSearchBoxActive(true);
-  }
-  located_event->SetHandled();
-}
-
 bool SearchBoxViewBase::OnTextfieldEvent() {
   if (is_search_box_active_)
     return false;
@@ -366,10 +341,6 @@
   UpdateKeyboardVisibility();
 }
 
-views::View* SearchBoxViewBase::GetSelectedViewInContentsView() {
-  return nullptr;
-}
-
 void SearchBoxViewBase::OnOnSearchBoxFocusedChanged() {
   UpdateSearchBoxBorder();
   Layout();
@@ -383,6 +354,19 @@
   return trimmed_query.empty();
 }
 
+void SearchBoxViewBase::ClearSearch() {
+  search_box_->SetText(base::string16());
+  UpdateCloseButtonVisisbility();
+  // Updates model and fires query changed manually because SetText() above
+  // does not generate ContentsChanged() notification.
+  UpdateModel(false);
+  NotifyQueryChanged();
+}
+
+views::View* SearchBoxViewBase::GetSelectedViewInContentsView() {
+  return nullptr;
+}
+
 void SearchBoxViewBase::NotifyQueryChanged() {
   DCHECK(delegate_);
   delegate_->QueryChanged(this);
@@ -407,14 +391,6 @@
       SK_ColorTRANSPARENT == color ? kDefaultSearchboxColor : color;
 }
 
-// TODO(crbug.com/755219): Unify this with SetBackgroundColor.
-void SearchBoxViewBase::UpdateBackgroundColor(SkColor color) {
-  if (is_search_box_active_)
-    color = kSearchBoxBackgroundDefault;
-  GetSearchBoxBackground()->set_color(color);
-  search_box_->SetBackgroundColor(color);
-}
-
 void SearchBoxViewBase::UpdateCloseButtonVisisbility() {
   if (!close_button_)
     return;
@@ -458,6 +434,30 @@
   search_icon_->SetImage(image);
 }
 
+void SearchBoxViewBase::HandleSearchBoxEvent(ui::LocatedEvent* located_event) {
+  if (located_event->type() == ui::ET_MOUSE_PRESSED ||
+      located_event->type() == ui::ET_GESTURE_TAP) {
+    bool event_is_in_searchbox_bounds =
+        GetWidget()->GetWindowBoundsInScreen().Contains(
+            located_event->root_location());
+    if (is_search_box_active_ || !event_is_in_searchbox_bounds ||
+        !search_box_->text().empty())
+      return;
+    // If the event was within the searchbox bounds and in an inactive empty
+    // search box, enable the search box.
+    SetSearchBoxActive(true);
+  }
+  located_event->SetHandled();
+}
+
+// TODO(crbug.com/755219): Unify this with SetBackgroundColor.
+void SearchBoxViewBase::UpdateBackgroundColor(SkColor color) {
+  if (is_search_box_active_)
+    color = kSearchBoxBackgroundDefault;
+  GetSearchBoxBackground()->set_color(color);
+  search_box_->SetBackgroundColor(color);
+}
+
 SearchBoxBackground* SearchBoxViewBase::GetSearchBoxBackground() const {
   return static_cast<SearchBoxBackground*>(content_container_->background());
 }
diff --git a/ui/chromeos/search_box/search_box_view_base.h b/ui/chromeos/search_box/search_box_view_base.h
index 971cb20..20395bc 100644
--- a/ui/chromeos/search_box/search_box_view_base.h
+++ b/ui/chromeos/search_box/search_box_view_base.h
@@ -48,9 +48,7 @@
 
   void Init();
 
-  virtual void ModelChanged() = 0;
   bool HasSearch() const;
-  virtual void ClearSearch();
 
   // Returns the bounds to use for the view (including the shadow) given the
   // desired bounds of the search box contents.
@@ -74,13 +72,6 @@
   // disables cursor blink.
   void SetSearchBoxActive(bool active);
 
-  // Shows/hides the virtual keyboard if the search box is active.
-  virtual void UpdateKeyboardVisibility() = 0;
-
-  // Detects |ET_MOUSE_PRESSED| and |ET_GESTURE_TAP| events on the white
-  // background of the search box.
-  virtual void HandleSearchBoxEvent(ui::LocatedEvent* located_event);
-
   // Handles Gesture and Mouse Events sent from |search_box_|.
   bool OnTextfieldEvent();
 
@@ -108,14 +99,16 @@
   // Whether the search box is active.
   bool is_search_box_active() const { return is_search_box_active_; }
 
-  // Returns selected view in contents view.
-  virtual views::View* GetSelectedViewInContentsView();
-
   void OnOnSearchBoxFocusedChanged();
 
   // Whether the trimmed query in the search box is empty.
   bool IsSearchBoxTrimmedQueryEmpty() const;
 
+  virtual void ClearSearch();
+
+  // Returns selected view in contents view.
+  virtual views::View* GetSelectedViewInContentsView();
+
  protected:
   // Fires query change notification.
   void NotifyQueryChanged();
@@ -131,9 +124,6 @@
   void SetSearchBoxColor(SkColor color);
   SkColor search_box_color() const { return search_box_color_; }
 
-  // Updates the search box's background color.
-  virtual void UpdateBackgroundColor(SkColor color);
-
   // Updates the visibility of close button.
   void UpdateCloseButtonVisisbility();
 
@@ -159,16 +149,25 @@
 
   void SetSearchIconImage(gfx::ImageSkia image);
 
+  // Detects |ET_MOUSE_PRESSED| and |ET_GESTURE_TAP| events on the white
+  // background of the search box.
+  virtual void HandleSearchBoxEvent(ui::LocatedEvent* located_event);
+
+  // Updates the search box's background color.
+  virtual void UpdateBackgroundColor(SkColor color);
+
  private:
+  virtual void ModelChanged() = 0;
+
+  // Shows/hides the virtual keyboard if the search box is active.
+  virtual void UpdateKeyboardVisibility() = 0;
+
   // Updates model text and selection model with current Textfield info.
   virtual void UpdateModel(bool initiated_by_user) = 0;
 
   // Updates the search icon.
   virtual void UpdateSearchIcon() = 0;
 
-  // Gets the search box background.
-  SearchBoxBackground* GetSearchBoxBackground() const;
-
   // Update search box border based on whether the search box is activated.
   virtual void UpdateSearchBoxBorder() = 0;
 
@@ -176,6 +175,9 @@
   virtual void SetupCloseButton() = 0;
   virtual void SetupBackButton() = 0;
 
+  // Gets the search box background.
+  SearchBoxBackground* GetSearchBoxBackground() const;
+
   SearchBoxViewDelegate* delegate_;  // Not owned.
 
   // Owned by views hierarchy.
diff --git a/ui/keyboard/container_behavior.h b/ui/keyboard/container_behavior.h
index d641d88..615fb93 100644
--- a/ui/keyboard/container_behavior.h
+++ b/ui/keyboard/container_behavior.h
@@ -39,10 +39,11 @@
 
   // Used by the layout manager to intercept any bounds setting request to
   // adjust the request to different bounds, if necessary. This method gets
-  // called at any time during the keyboard's life cycle.
+  // called at any time during the keyboard's life cycle. The bounds are in
+  // global screen coordinates.
   virtual const gfx::Rect AdjustSetBoundsRequest(
       const gfx::Rect& display_bounds,
-      const gfx::Rect& requested_bounds) = 0;
+      const gfx::Rect& requested_bounds_in_screen_coords) = 0;
 
   // Used to set the bounds to the default location. This is generally called
   // during initialization, but may also be have identical behavior to
diff --git a/ui/keyboard/container_floating_behavior.cc b/ui/keyboard/container_floating_behavior.cc
index d929cb8..17cf9b8 100644
--- a/ui/keyboard/container_floating_behavior.cc
+++ b/ui/keyboard/container_floating_behavior.cc
@@ -115,20 +115,20 @@
   int bottom = keyboard_bounds.bottom();
 
   // Prevent keyboard from appearing off screen or overlapping with the edge.
-  if (left < 0) {
-    left = 0;
-    right = keyboard_bounds.width();
+  if (left < display_bounds.x()) {
+    left = display_bounds.x();
+    right = left + keyboard_bounds.width();
   }
-  if (right >= display_bounds.width()) {
-    right = display_bounds.width();
+  if (right >= display_bounds.right()) {
+    right = display_bounds.right();
     left = right - keyboard_bounds.width();
   }
-  if (top < 0) {
-    top = 0;
-    bottom = keyboard_bounds.height();
+  if (top < display_bounds.y()) {
+    top = display_bounds.y();
+    bottom = top + keyboard_bounds.height();
   }
-  if (bottom >= display_bounds.height()) {
-    bottom = display_bounds.height();
+  if (bottom >= display_bounds.bottom()) {
+    bottom = display_bounds.bottom();
     top = bottom - keyboard_bounds.height();
   }
 
@@ -162,7 +162,11 @@
 
   // Make sure that this location is valid according to the current size of the
   // screen.
-  gfx::Rect keyboard_bounds = gfx::Rect(top_left_offset, keyboard_size);
+  gfx::Rect keyboard_bounds =
+      gfx::Rect(top_left_offset.x() + display_bounds.x(),
+                top_left_offset.y() + display_bounds.y(), keyboard_size.width(),
+                keyboard_size.height());
+
   gfx::Rect valid_keyboard_bounds =
       ContainKeyboardToScreenBounds(keyboard_bounds, display_bounds);
 
diff --git a/ui/keyboard/container_floating_behavior.h b/ui/keyboard/container_floating_behavior.h
index c8cb9e6ffc..ccc5c47 100644
--- a/ui/keyboard/container_floating_behavior.h
+++ b/ui/keyboard/container_floating_behavior.h
@@ -43,7 +43,7 @@
   void InitializeShowAnimationStartingState(aura::Window* container) override;
   const gfx::Rect AdjustSetBoundsRequest(
       const gfx::Rect& display_bounds,
-      const gfx::Rect& requested_bounds) override;
+      const gfx::Rect& requested_bounds_in_screen_coords) override;
   bool IsOverscrollAllowed() const override;
   bool IsDragHandle(const gfx::Vector2d& offset,
                     const gfx::Size& keyboard_size) const override;
diff --git a/ui/keyboard/container_floating_behavior_unittest.cc b/ui/keyboard/container_floating_behavior_unittest.cc
index 6db3b40..cc13bd6 100644
--- a/ui/keyboard/container_floating_behavior_unittest.cc
+++ b/ui/keyboard/container_floating_behavior_unittest.cc
@@ -48,6 +48,13 @@
                       workspace.height() - keyboard_height, keyboard_width,
                       keyboard_height),
             result);
+
+  // Try to move the keyboard to the center of the primary display while it's
+  // in a secondary display.
+  gfx::Rect secondary_display(1000, -200, 1200, 800);
+  result = floating_behavior.AdjustSetBoundsRequest(secondary_display, center);
+  // It gets clipped to the far left of this display
+  ASSERT_EQ(gfx::Rect(1000, 100, keyboard_width, keyboard_height), result);
 }
 
 TEST(ContainerFloatingBehaviorTest, AdjustSetBoundsRequestVariousSides) {
diff --git a/ui/keyboard/container_full_width_behavior.cc b/ui/keyboard/container_full_width_behavior.cc
index 2dca9c0..62fbd43a 100644
--- a/ui/keyboard/container_full_width_behavior.cc
+++ b/ui/keyboard/container_full_width_behavior.cc
@@ -58,19 +58,19 @@
 
 const gfx::Rect ContainerFullWidthBehavior::AdjustSetBoundsRequest(
     const gfx::Rect& display_bounds,
-    const gfx::Rect& requested_bounds) {
+    const gfx::Rect& requested_bounds_in_screen_coords) {
   gfx::Rect new_bounds;
 
   // Honors only the height of the request bounds
-  const int keyboard_height = requested_bounds.height();
+  const int keyboard_height = requested_bounds_in_screen_coords.height();
 
-  new_bounds.set_y(display_bounds.height() - keyboard_height);
+  new_bounds.set_y(display_bounds.bottom() - keyboard_height);
   new_bounds.set_height(keyboard_height);
 
   // If shelf is positioned on the left side of screen, x is not 0. In
   // FULL_WIDTH mode, the virtual keyboard should always align with the left
-  // edge of the screen. So manually set x to 0 here.
-  new_bounds.set_x(0);
+  // edge of the screen. So manually set x to the left side of the screen.
+  new_bounds.set_x(display_bounds.x());
   new_bounds.set_width(display_bounds.width());
 
   return new_bounds;
diff --git a/ui/keyboard/container_full_width_behavior.h b/ui/keyboard/container_full_width_behavior.h
index 077d3b9..f21c46c1 100644
--- a/ui/keyboard/container_full_width_behavior.h
+++ b/ui/keyboard/container_full_width_behavior.h
@@ -35,7 +35,7 @@
   void InitializeShowAnimationStartingState(aura::Window* container) override;
   const gfx::Rect AdjustSetBoundsRequest(
       const gfx::Rect& display_bounds,
-      const gfx::Rect& requested_bounds) override;
+      const gfx::Rect& requested_bounds_in_screen_coords) override;
   bool IsOverscrollAllowed() const override;
   bool IsDragHandle(const gfx::Vector2d& offset,
                     const gfx::Size& keyboard_size) const override;
diff --git a/ui/keyboard/container_full_width_behavior_unittest.cc b/ui/keyboard/container_full_width_behavior_unittest.cc
index 76e9384..eaceffb 100644
--- a/ui/keyboard/container_full_width_behavior_unittest.cc
+++ b/ui/keyboard/container_full_width_behavior_unittest.cc
@@ -18,20 +18,22 @@
 TEST(ContainerFullWidthBehaviorTest, AdjustSetBoundsRequest) {
   ContainerFullWidthBehavior full_width_behavior(nullptr);
 
-  gfx::Rect workspace(0, 0, 300, 200);
+  // workspace is not always necessarily positioned at the origin (e.g.
+  // secondary display).
+  gfx::Rect workspace(20, -30, 300, 200);
   gfx::Rect requested_bounds(0, 0, 10, 10);
   gfx::Rect result;
 
   // Ignore width. Stretch the bounds across the bottom of the screen.
   result =
       full_width_behavior.AdjustSetBoundsRequest(workspace, requested_bounds);
-  ASSERT_EQ(gfx::Rect(0, 190, 300, 10), result);
+  ASSERT_EQ(gfx::Rect(20, 160, 300, 10), result);
 
   // Even if the coordinates are non-zero, ignore them. Only use height.
   requested_bounds = gfx::Rect(30, 80, 20, 100);
   result =
       full_width_behavior.AdjustSetBoundsRequest(workspace, requested_bounds);
-  ASSERT_EQ(gfx::Rect(0, 100, 300, 100), result);
+  ASSERT_EQ(gfx::Rect(20, 70, 300, 100), result);
 }
 
 }  // namespace keyboard
diff --git a/ui/keyboard/display_util.cc b/ui/keyboard/display_util.cc
index 22abc6b..2e6a08a7 100644
--- a/ui/keyboard/display_util.cc
+++ b/ui/keyboard/display_util.cc
@@ -14,7 +14,12 @@
 DisplayUtil::DisplayUtil() {}
 
 int64_t DisplayUtil::GetNearestDisplayIdToWindow(aura::Window* window) const {
-  return display::Screen::GetScreen()->GetDisplayNearestWindow(window).id();
+  return GetNearestDisplayToWindow(window).id();
+}
+
+display::Display DisplayUtil::GetNearestDisplayToWindow(
+    aura::Window* window) const {
+  return display::Screen::GetScreen()->GetDisplayNearestWindow(window);
 }
 
 }  // namespace keyboard
diff --git a/ui/keyboard/display_util.h b/ui/keyboard/display_util.h
index be85562..5a683dd 100644
--- a/ui/keyboard/display_util.h
+++ b/ui/keyboard/display_util.h
@@ -6,6 +6,7 @@
 #define UI_KEYBOARD_DISPLAY_UTIL_H_
 
 #include "ui/aura/window.h"
+#include "ui/display/display.h"
 
 namespace keyboard {
 
@@ -15,6 +16,7 @@
   DisplayUtil();
 
   int64_t GetNearestDisplayIdToWindow(aura::Window* window) const;
+  display::Display GetNearestDisplayToWindow(aura::Window* window) const;
 };
 
 }  // namespace keyboard
diff --git a/ui/keyboard/keyboard_controller_unittest.cc b/ui/keyboard/keyboard_controller_unittest.cc
index c0d9d05..e449422 100644
--- a/ui/keyboard/keyboard_controller_unittest.cc
+++ b/ui/keyboard/keyboard_controller_unittest.cc
@@ -385,45 +385,6 @@
   VerifyKeyboardWindowSize(container, keyboard);
 }
 
-// Flaky on Windows. See http://crbug.com/757044
-#if defined(OS_WIN)
-#define MAYBE_KeyboardSizeMultiRootWindow DISABLED_KeyboardSizeMultiRootWindow
-#else
-#define MAYBE_KeyboardSizeMultiRootWindow KeyboardSizeMultiRootWindow
-#endif
-
-TEST_F(KeyboardControllerTest, MAYBE_KeyboardSizeMultiRootWindow) {
-  aura::Window* container(controller()->GetContainerWindow());
-  aura::Window* keyboard(ui()->GetContentsWindow());
-  gfx::Rect screen_bounds = root_window()->bounds();
-  root_window()->AddChild(container);
-  container->AddChild(keyboard);
-  const gfx::Rect& initial_bounds = container->bounds();
-  // The container should be positioned at the bottom of screen and has 0
-  // height.
-  ASSERT_EQ(0, initial_bounds.height());
-  ASSERT_EQ(screen_bounds.height(), initial_bounds.y());
-  VerifyKeyboardWindowSize(container, keyboard);
-
-  // Adding new root window.
-  std::unique_ptr<aura::WindowTreeHost> secondary_tree_host =
-      base::WrapUnique<aura::WindowTreeHost>(
-          aura::WindowTreeHost::Create(gfx::Rect(0, 0, 1000, 500)));
-  secondary_tree_host->InitHost();
-  EXPECT_EQ(1000, secondary_tree_host->window()->bounds().width());
-  EXPECT_EQ(500, secondary_tree_host->window()->bounds().height());
-
-  // Move the keyboard into the secondary root window.
-  controller()->HideKeyboard(
-      KeyboardController::HideReason::HIDE_REASON_AUTOMATIC);
-  root_window()->RemoveChild(container);
-  secondary_tree_host->window()->AddChild(container);
-
-  const gfx::Rect& new_bounds = container->bounds();
-  EXPECT_EQ(500, new_bounds.y());
-  VerifyKeyboardWindowSize(container, keyboard);
-}
-
 // Tests that tapping/clicking inside the keyboard does not give it focus.
 TEST_F(KeyboardControllerTest, ClickDoesNotFocusKeyboard) {
   ScopedAccessibilityKeyboardEnabler scoped_keyboard_enabler;
diff --git a/ui/keyboard/keyboard_layout_manager.cc b/ui/keyboard/keyboard_layout_manager.cc
index 8323fa1..237291fb 100644
--- a/ui/keyboard/keyboard_layout_manager.cc
+++ b/ui/keyboard/keyboard_layout_manager.cc
@@ -5,6 +5,7 @@
 #include "ui/keyboard/keyboard_layout_manager.h"
 
 #include "ui/compositor/layer_animator.h"
+#include "ui/display/display.h"
 #include "ui/display/screen.h"
 #include "ui/keyboard/keyboard_controller.h"
 #include "ui/keyboard/keyboard_util.h"
@@ -36,20 +37,29 @@
   // resized and covers the container window. Note the contents' bound is only
   // set in OnWindowResized.
 
-  const aura::Window* root_window =
+  aura::Window* root_window =
       controller_->GetContainerWindow()->GetRootWindow();
 
   // If the keyboard has been deactivated, this reference will be null.
   if (!root_window)
     return;
 
-  const gfx::Rect new_bounds = controller_->AdjustSetBoundsRequest(
-      root_window->bounds(), requested_bounds);
+  DisplayUtil display_util;
+  const display::Display& display =
+      display_util.GetNearestDisplayToWindow(root_window);
+  const gfx::Vector2d display_offset =
+      display.bounds().origin().OffsetFromOrigin();
+
+  const gfx::Rect new_bounds =
+      controller_->AdjustSetBoundsRequest(display.bounds(),
+                                          requested_bounds + display_offset) -
+      display_offset;
 
   // Containar bounds should only be reset when the contents window bounds
   // actually change. Otherwise it interrupts the initial animation of showing
   // the keyboard. Described in crbug.com/356753.
   gfx::Rect old_bounds = contents_window_->GetTargetBounds();
+
   aura::Window::ConvertRectToTarget(contents_window_, root_window, &old_bounds);
   if (new_bounds == old_bounds)
     return;
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
index a982faa3..e116f31 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -330,7 +330,7 @@
   if (xrandr_version_ >= 105) {
     void* xrandr_lib = dlopen(NULL, RTLD_NOW);
     if (xrandr_lib) {
-      typedef XRRMonitorInfo* (*XRRGetMonitors_type)(Display*, Window, bool,
+      typedef XRRMonitorInfo* (*XRRGetMonitors_type)(::Display*, Window, bool,
                                                      int*);
       typedef void (*XRRFreeMonitors_type)(XRRMonitorInfo*);
       XRRGetMonitors_type XRRGetMonitors_ptr =