diff --git a/DEPS b/DEPS
index 2b872891..da8f6d6 100644
--- a/DEPS
+++ b/DEPS
@@ -98,7 +98,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '58629a0e49e4ebfb0a0171a4203d2fab4af63165',
+  'pdfium_revision': 'f96dfed065f9c6789811f43b69cd5ab4d85466ac',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -311,7 +311,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c4ccb4b623c91fb2a38e365db5c307523c1ec05c',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4a2cb46cd6011ef96ec553dae8ca50a3583ca266',
 
   # DevTools node modules. Used on Linux buildbots only.
   'src/third_party/devtools-node-modules': {
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index c13222d..00a43e5 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -728,6 +728,10 @@
     "wm/always_on_top_controller.h",
     "wm/ash_focus_rules.cc",
     "wm/ash_focus_rules.h",
+    "wm/base_state.cc",
+    "wm/base_state.h",
+    "wm/client_controlled_state.cc",
+    "wm/client_controlled_state.h",
     "wm/container_finder.cc",
     "wm/container_finder.h",
     "wm/cursor_manager_chromeos.cc",
@@ -1405,6 +1409,7 @@
     "window_user_data_unittest.cc",
     "wm/always_on_top_controller_unittest.cc",
     "wm/ash_focus_rules_unittest.cc",
+    "wm/client_controlled_state_unittest.cc",
     "wm/container_finder_unittest.cc",
     "wm/drag_window_resizer_unittest.cc",
     "wm/gestures/overview_gesture_handler_unittest.cc",
diff --git a/ash/public/cpp/shelf_struct_traits.h b/ash/public/cpp/shelf_struct_traits.h
index 832d2b6..51b7ecc5 100644
--- a/ash/public/cpp/shelf_struct_traits.h
+++ b/ash/public/cpp/shelf_struct_traits.h
@@ -111,8 +111,6 @@
         return ash::mojom::ShelfItemStatus::CLOSED;
       case ash::STATUS_RUNNING:
         return ash::mojom::ShelfItemStatus::RUNNING;
-      case ash::STATUS_ACTIVE:
-        return ash::mojom::ShelfItemStatus::ACTIVE;
       case ash::STATUS_ATTENTION:
         return ash::mojom::ShelfItemStatus::ATTENTION;
     }
@@ -129,9 +127,6 @@
       case ash::mojom::ShelfItemStatus::RUNNING:
         *out = ash::STATUS_RUNNING;
         return true;
-      case ash::mojom::ShelfItemStatus::ACTIVE:
-        *out = ash::STATUS_ACTIVE;
-        return true;
       case ash::mojom::ShelfItemStatus::ATTENTION:
         *out = ash::STATUS_ATTENTION;
         return true;
diff --git a/ash/public/cpp/shelf_types.h b/ash/public/cpp/shelf_types.h
index 5760ca3..27e81c4b 100644
--- a/ash/public/cpp/shelf_types.h
+++ b/ash/public/cpp/shelf_types.h
@@ -129,8 +129,6 @@
   STATUS_CLOSED,
   // A shelf item that has live instance.
   STATUS_RUNNING,
-  // An active shelf item that has focus.
-  STATUS_ACTIVE,
   // A shelf item that needs user's attention.
   STATUS_ATTENTION,
 };
diff --git a/ash/public/interfaces/shelf.mojom b/ash/public/interfaces/shelf.mojom
index e2ecf4f..58d155a 100644
--- a/ash/public/interfaces/shelf.mojom
+++ b/ash/public/interfaces/shelf.mojom
@@ -33,7 +33,6 @@
 enum ShelfItemStatus {
   CLOSED,     // A closed shelf item, i.e. has no live instance.
   RUNNING,    // A shelf item that has live instance.
-  ACTIVE,     // An active shelf item that has focus.
   ATTENTION,  // A shelf item that needs user's attention.
 };
 
diff --git a/ash/public/interfaces/system_tray.mojom b/ash/public/interfaces/system_tray.mojom
index 4c5571e..3f5dffd 100644
--- a/ash/public/interfaces/system_tray.mojom
+++ b/ash/public/interfaces/system_tray.mojom
@@ -122,6 +122,9 @@
   // connection (e.g. Cisco AnyConnect).
   ShowThirdPartyVpnCreate(string extension_id);
 
+  // Launches Arc VPN provider.
+  ShowArcVpnCreate(string app_id);
+
   // Shows settings related to networking. If |network_id| is empty, shows
   // general settings. Otherwise shows settings for the individual network.
   // On devices |network_id| is a GUID, but on Linux desktop and in tests it can
diff --git a/ash/shelf/shelf_button.cc b/ash/shelf/shelf_button.cc
index 704681fb..6d4bddd 100644
--- a/ash/shelf/shelf_button.cc
+++ b/ash/shelf/shelf_button.cc
@@ -468,16 +468,6 @@
   Layout();
 }
 
-void ShelfButton::OnFocus() {
-  AddState(STATE_FOCUSED);
-  Button::OnFocus();
-}
-
-void ShelfButton::OnBlur() {
-  ClearState(STATE_FOCUSED);
-  Button::OnBlur();
-}
-
 void ShelfButton::OnGestureEvent(ui::GestureEvent* event) {
   switch (event->type()) {
     case ui::ET_GESTURE_TAP_DOWN:
@@ -557,8 +547,7 @@
 
 void ShelfButton::UpdateState() {
   indicator_->SetVisible(!(state_ & STATE_HIDDEN) &&
-                         (state_ & STATE_ACTIVE || state_ & STATE_ATTENTION ||
-                          state_ & STATE_RUNNING));
+                         (state_ & STATE_ATTENTION || state_ & STATE_RUNNING));
 
   const bool is_horizontal_shelf =
       shelf_view_->shelf()->IsHorizontalAlignment();
diff --git a/ash/shelf/shelf_button.h b/ash/shelf/shelf_button.h
index d361c45..6701c79a 100644
--- a/ash/shelf/shelf_button.h
+++ b/ash/shelf/shelf_button.h
@@ -33,15 +33,12 @@
     STATE_HOVERED = 1 << 0,
     // Underlying ShelfItem has a running instance.
     STATE_RUNNING = 1 << 1,
-    // Underlying ShelfItem is active (i.e. has focus).
-    STATE_ACTIVE = 1 << 2,
     // Underlying ShelfItem needs user's attention.
-    STATE_ATTENTION = 1 << 3,
-    STATE_FOCUSED = 1 << 4,
+    STATE_ATTENTION = 1 << 2,
     // Hide the status (temporarily for some animations).
-    STATE_HIDDEN = 1 << 5,
+    STATE_HIDDEN = 1 << 3,
     // Button is being dragged.
-    STATE_DRAGGING = 1 << 6,
+    STATE_DRAGGING = 1 << 4,
   };
 
   ShelfButton(InkDropButtonListener* listener, ShelfView* shelf_view);
@@ -82,8 +79,6 @@
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
   void Layout() override;
   void ChildPreferredSizeChanged(views::View* child) override;
-  void OnFocus() override;
-  void OnBlur() override;
 
   // ui::EventHandler overrides:
   void OnGestureEvent(ui::GestureEvent* event) override;
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 69753ae..28544f6e 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -164,22 +164,14 @@
 void ReflectItemStatus(const ShelfItem& item, ShelfButton* button) {
   switch (item.status) {
     case STATUS_CLOSED:
-      button->ClearState(ShelfButton::STATE_ACTIVE);
       button->ClearState(ShelfButton::STATE_RUNNING);
       button->ClearState(ShelfButton::STATE_ATTENTION);
       break;
     case STATUS_RUNNING:
-      button->ClearState(ShelfButton::STATE_ACTIVE);
       button->AddState(ShelfButton::STATE_RUNNING);
       button->ClearState(ShelfButton::STATE_ATTENTION);
       break;
-    case STATUS_ACTIVE:
-      button->AddState(ShelfButton::STATE_ACTIVE);
-      button->ClearState(ShelfButton::STATE_RUNNING);
-      button->ClearState(ShelfButton::STATE_ATTENTION);
-      break;
     case STATUS_ATTENTION:
-      button->ClearState(ShelfButton::STATE_ACTIVE);
       button->ClearState(ShelfButton::STATE_RUNNING);
       button->AddState(ShelfButton::STATE_ATTENTION);
       break;
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index 580336d..cdd65783 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -1212,9 +1212,6 @@
   int index = model_->ItemIndexByID(last_added);
   ShelfButton* button = GetButtonByID(last_added);
   ASSERT_EQ(ShelfButton::STATE_RUNNING, button->state());
-  item.status = STATUS_ACTIVE;
-  model_->Set(index, item);
-  ASSERT_EQ(ShelfButton::STATE_ACTIVE, button->state());
   item.status = STATUS_ATTENTION;
   model_->Set(index, item);
   ASSERT_EQ(ShelfButton::STATE_ATTENTION, button->state());
@@ -1330,9 +1327,6 @@
   int index = model_->ItemIndexByID(last_added);
   ShelfButton* button = GetButtonByID(last_added);
   ASSERT_EQ(ShelfButton::STATE_RUNNING, button->state());
-  item.status = STATUS_ACTIVE;
-  model_->Set(index, item);
-  ASSERT_EQ(ShelfButton::STATE_ACTIVE, button->state());
   item.status = STATUS_ATTENTION;
   model_->Set(index, item);
   ASSERT_EQ(ShelfButton::STATE_ATTENTION, button->state());
diff --git a/ash/shelf/shelf_window_watcher.cc b/ash/shelf/shelf_window_watcher.cc
index bd0c746..6ea71d3 100644
--- a/ash/shelf/shelf_window_watcher.cc
+++ b/ash/shelf/shelf_window_watcher.cc
@@ -61,11 +61,13 @@
   item->type = GetShelfItemType(window);
   item->title = window->GetTitle();
 
-  item->status = STATUS_RUNNING;
-  if (wm::IsActiveWindow(window))
-    item->status = STATUS_ACTIVE;
-  else if (window->GetProperty(aura::client::kDrawAttentionKey))
+  // Active windows don't draw attention because the user is looking at them.
+  if (window->GetProperty(aura::client::kDrawAttentionKey) &&
+      !wm::IsActiveWindow(window)) {
     item->status = STATUS_ATTENTION;
+  } else {
+    item->status = STATUS_RUNNING;
+  }
 
   // Prefer app icons over window icons, they're typically larger.
   gfx::ImageSkia* image = window->GetProperty(aura::client::kAppIconKey);
diff --git a/ash/shelf/shelf_window_watcher_unittest.cc b/ash/shelf/shelf_window_watcher_unittest.cc
index 8f663acd..ca92b90a 100644
--- a/ash/shelf/shelf_window_watcher_unittest.cc
+++ b/ash/shelf/shelf_window_watcher_unittest.cc
@@ -161,7 +161,7 @@
   EXPECT_EQ(3, model_->item_count());
 
   int index_w2 = model_->ItemIndexByID(id_w2);
-  EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status);
+  EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w2].status);
 
   // ShelfItem is removed when the item type window property is cleared.
   widget1->GetNativeWindow()->SetProperty(kShelfItemTypeKey,
@@ -176,40 +176,6 @@
   EXPECT_EQ(1, model_->item_count());
 }
 
-TEST_F(ShelfWindowWatcherTest, ActivateWindow) {
-  // TODO: investigate failure in mash. http://crbug.com/695562.
-  if (Shell::GetAshConfig() == Config::MASH)
-    return;
-
-  std::unique_ptr<views::Widget> widget1 =
-      CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect());
-  std::unique_ptr<views::Widget> widget2 =
-      CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect());
-
-  // Create a ShelfItem for the first window.
-  ShelfID id_w1 = CreateShelfItem(widget1->GetNativeWindow());
-  EXPECT_EQ(2, model_->item_count());
-  int index_w1 = model_->ItemIndexByID(id_w1);
-  EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status);
-
-  // Create a ShelfItem for the second window.
-  ShelfID id_w2 = CreateShelfItem(widget2->GetNativeWindow());
-  EXPECT_EQ(3, model_->item_count());
-  int index_w2 = model_->ItemIndexByID(id_w2);
-  EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status);
-  EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status);
-
-  // The ShelfItem for the first window is active when the window is activated.
-  widget1->Activate();
-  EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w1].status);
-  EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w2].status);
-
-  // The ShelfItem for the second window is active when the window is activated.
-  widget2->Activate();
-  EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status);
-  EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status);
-}
-
 TEST_F(ShelfWindowWatcherTest, UpdateWindowProperty) {
   // Create a ShelfItem for a new window.
   EXPECT_EQ(1, model_->item_count());
@@ -219,7 +185,7 @@
   EXPECT_EQ(2, model_->item_count());
 
   int index = model_->ItemIndexByID(id);
-  EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status);
+  EXPECT_EQ(STATUS_RUNNING, model_->items()[index].status);
 
   // Update the window's ShelfItemType.
   widget->GetNativeWindow()->SetProperty(kShelfItemTypeKey,
@@ -240,7 +206,7 @@
   EXPECT_EQ(2, model_->item_count());
 
   int index = model_->ItemIndexByID(id);
-  EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status);
+  EXPECT_EQ(STATUS_RUNNING, model_->items()[index].status);
 
   // Maximize the window.
   wm::WindowState* window_state = wm::GetWindowState(widget->GetNativeWindow());
@@ -274,7 +240,7 @@
   EXPECT_EQ(2, model_->item_count());
 
   int index = model_->ItemIndexByID(id);
-  EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status);
+  EXPECT_EQ(STATUS_RUNNING, model_->items()[index].status);
 
   // Simulate dragging of the window and check its item is not changed.
   std::unique_ptr<WindowResizer> resizer(
diff --git a/ash/system/network/vpn_list_view.cc b/ash/system/network/vpn_list_view.cc
index 391ce4b..236d8c7 100644
--- a/ash/system/network/vpn_list_view.cc
+++ b/ash/system/network/vpn_list_view.cc
@@ -112,6 +112,10 @@
           UMA_STATUS_AREA_VPN_ADD_THIRD_PARTY_CLICKED);
       Shell::Get()->system_tray_controller()->ShowThirdPartyVpnCreate(
           vpn_provider_.app_id);
+    } else if (vpn_provider_.provider_type == VPNProvider::ARC_VPN) {
+      // TODO(lgcheng@) Add UMA status if needed.
+      Shell::Get()->system_tray_controller()->ShowArcVpnCreate(
+          vpn_provider_.app_id);
     } else {
       Shell::Get()->metrics()->RecordUserMetricsAction(
           UMA_STATUS_AREA_VPN_ADD_BUILT_IN_CLICKED);
diff --git a/ash/system/tray/system_tray_controller.cc b/ash/system/tray/system_tray_controller.cc
index f79b4f9..57f37f64 100644
--- a/ash/system/tray/system_tray_controller.cc
+++ b/ash/system/tray/system_tray_controller.cc
@@ -124,6 +124,11 @@
     system_tray_client_->ShowThirdPartyVpnCreate(extension_id);
 }
 
+void SystemTrayController::ShowArcVpnCreate(const std::string& app_id) {
+  if (system_tray_client_)
+    system_tray_client_->ShowArcVpnCreate(app_id);
+}
+
 void SystemTrayController::ShowNetworkSettings(const std::string& network_id) {
   if (system_tray_client_)
     system_tray_client_->ShowNetworkSettings(network_id);
diff --git a/ash/system/tray/system_tray_controller.h b/ash/system/tray/system_tray_controller.h
index 716962e..a36acf4 100644
--- a/ash/system/tray/system_tray_controller.h
+++ b/ash/system/tray/system_tray_controller.h
@@ -56,6 +56,7 @@
   void ShowNetworkConfigure(const std::string& network_id);
   void ShowNetworkCreate(const std::string& type);
   void ShowThirdPartyVpnCreate(const std::string& extension_id);
+  void ShowArcVpnCreate(const std::string& app_id);
   void ShowNetworkSettings(const std::string& network_id);
   void RequestRestartForUpdate();
 
diff --git a/ash/wm/base_state.cc b/ash/wm/base_state.cc
new file mode 100644
index 0000000..5884fe7
--- /dev/null
+++ b/ash/wm/base_state.cc
@@ -0,0 +1,120 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/wm/base_state.h"
+
+#include "ash/public/cpp/window_state_type.h"
+#include "ash/wm/window_animation_types.h"
+#include "ash/wm/wm_event.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
+
+namespace ash {
+namespace wm {
+namespace {
+
+bool IsMinimizedWindowState(const mojom::WindowStateType state_type) {
+  return state_type == mojom::WindowStateType::MINIMIZED;
+}
+
+}  // namespace
+
+BaseState::BaseState(mojom::WindowStateType initial_state_type)
+    : state_type_(initial_state_type) {}
+BaseState::~BaseState() = default;
+
+void BaseState::OnWMEvent(WindowState* window_state, const WMEvent* event) {
+  if (event->IsWorkspaceEvent()) {
+    HandleWorkspaceEvents(window_state, event);
+    return;
+  }
+  if ((window_state->IsTrustedPinned() || window_state->IsPinned()) &&
+      event->type() != WM_EVENT_NORMAL) {
+    // PIN state can be exited only by normal event.
+    return;
+  }
+
+  if (event->IsCompoundEvent()) {
+    HandleCompoundEvents(window_state, event);
+    return;
+  }
+
+  if (event->IsBoundsEvent()) {
+    HandleBoundsEvents(window_state, event);
+    return;
+  }
+  DCHECK(event->IsTransitionEvent());
+  HandleTransitionEvents(window_state, event);
+}
+
+mojom::WindowStateType BaseState::GetType() const {
+  return state_type_;
+}
+
+// static
+mojom::WindowStateType BaseState::GetStateForTransitionEvent(
+    const WMEvent* event) {
+  switch (event->type()) {
+    case WM_EVENT_NORMAL:
+      return mojom::WindowStateType::NORMAL;
+    case WM_EVENT_MAXIMIZE:
+      return mojom::WindowStateType::MAXIMIZED;
+    case WM_EVENT_MINIMIZE:
+      return mojom::WindowStateType::MINIMIZED;
+    case WM_EVENT_FULLSCREEN:
+      return mojom::WindowStateType::FULLSCREEN;
+    case WM_EVENT_SNAP_LEFT:
+      return mojom::WindowStateType::LEFT_SNAPPED;
+    case WM_EVENT_SNAP_RIGHT:
+      return mojom::WindowStateType::RIGHT_SNAPPED;
+    case WM_EVENT_SHOW_INACTIVE:
+      return mojom::WindowStateType::INACTIVE;
+    case WM_EVENT_PIN:
+      return mojom::WindowStateType::PINNED;
+    case WM_EVENT_TRUSTED_PIN:
+      return mojom::WindowStateType::TRUSTED_PINNED;
+    default:
+      break;
+  }
+#if !defined(NDEBUG)
+  if (event->IsWorkspaceEvent())
+    NOTREACHED() << "Can't get the state for Workspace event" << event->type();
+  if (event->IsCompoundEvent())
+    NOTREACHED() << "Can't get the state for Compound event:" << event->type();
+  if (event->IsBoundsEvent())
+    NOTREACHED() << "Can't get the state for Bounds event:" << event->type();
+#endif
+  return mojom::WindowStateType::NORMAL;
+}
+
+void BaseState::UpdateMinimizedState(
+    WindowState* window_state,
+    mojom::WindowStateType previous_state_type) {
+  aura::Window* window = window_state->window();
+  if (window_state->IsMinimized()) {
+    // Save the previous show state so that we can correctly restore it after
+    // exiting the minimized mode.
+    window->SetProperty(aura::client::kPreMinimizedShowStateKey,
+                        ToWindowShowState(previous_state_type));
+    ::wm::SetWindowVisibilityAnimationType(
+        window, WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE);
+
+    window->Hide();
+    if (window_state->IsActive())
+      window_state->Deactivate();
+  } else if ((window->layer()->GetTargetVisibility() ||
+              IsMinimizedWindowState(previous_state_type)) &&
+             !window->layer()->visible()) {
+    // The layer may be hidden if the window was previously minimized. Make
+    // sure it's visible.
+    window->Show();
+    if (IsMinimizedWindowState(previous_state_type) &&
+        !window_state->IsMaximizedOrFullscreenOrPinned()) {
+      window_state->set_unminimize_to_restore_bounds(false);
+    }
+  }
+}
+
+}  // namespace wm
+}  // namespace ash
diff --git a/ash/wm/base_state.h b/ash/wm/base_state.h
new file mode 100644
index 0000000..56e6060
--- /dev/null
+++ b/ash/wm/base_state.h
@@ -0,0 +1,55 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/wm/window_state.h"
+#include "base/macros.h"
+
+namespace ash {
+namespace wm {
+
+// BaseState implements the common framework for WindowState::State.
+class BaseState : public WindowState::State {
+ public:
+  explicit BaseState(mojom::WindowStateType initial_state_type);
+  ~BaseState() override;
+
+  // WindowState::State:
+  void OnWMEvent(WindowState* window_state, const WMEvent* event) override;
+  mojom::WindowStateType GetType() const override;
+
+ protected:
+  // Returns the WindowStateType corresponds to the WMEvent type.
+  static mojom::WindowStateType GetStateForTransitionEvent(
+      const WMEvent* event);
+
+  // Handle workspace related events, such as DISPLAY_BOUNDS_CHANGED.
+  virtual void HandleWorkspaceEvents(WindowState* window_state,
+                                     const WMEvent* event) = 0;
+
+  // Handle state dependent events, such as TOGGLE_MAXIMIZED,
+  // TOGGLE_FULLSCREEN.
+  virtual void HandleCompoundEvents(WindowState* window_state,
+                                    const WMEvent* event) = 0;
+
+  // Handle bounds change events: SET_BOUNDS and CENTER.
+  virtual void HandleBoundsEvents(WindowState* window_state,
+                                  const WMEvent* event) = 0;
+
+  // Handle state transition events, such as MAXIMZIED, MINIMIZED.
+  virtual void HandleTransitionEvents(WindowState* window_state,
+                                      const WMEvent* event) = 0;
+
+  // Show/Hide window when minimized state changes.
+  void UpdateMinimizedState(WindowState* window_state,
+                            mojom::WindowStateType previous_state_type);
+
+  // The current type of the window.
+  mojom::WindowStateType state_type_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BaseState);
+};
+
+}  // namespace wm
+}  // namespace ash
diff --git a/ash/wm/client_controlled_state.cc b/ash/wm/client_controlled_state.cc
new file mode 100644
index 0000000..da45c5ea
--- /dev/null
+++ b/ash/wm/client_controlled_state.cc
@@ -0,0 +1,198 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/wm/client_controlled_state.h"
+
+#include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/cpp/window_state_type.h"
+#include "ash/root_window_controller.h"
+#include "ash/screen_util.h"
+#include "ash/shell.h"
+#include "ash/wm/screen_pinning_controller.h"
+#include "ash/wm/window_animation_types.h"
+#include "ash/wm/window_parenting_utils.h"
+#include "ash/wm/window_positioning_utils.h"
+#include "ash/wm/window_state.h"
+#include "ash/wm/window_state_delegate.h"
+#include "ash/wm/window_state_util.h"
+#include "ash/wm/wm_event.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_delegate.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/wm/core/window_util.h"
+
+namespace ash {
+namespace wm {
+
+ClientControlledState::ClientControlledState(std::unique_ptr<Delegate> delegate)
+    : BaseState(mojom::WindowStateType::DEFAULT),
+      delegate_(std::move(delegate)) {}
+
+ClientControlledState::~ClientControlledState() {}
+
+void ClientControlledState::HandleTransitionEvents(WindowState* window_state,
+                                                   const WMEvent* event) {
+  bool pin_transition = window_state->IsTrustedPinned() ||
+                        window_state->IsPinned() || event->IsPinEvent();
+  // Pinned State transition is handled on server side.
+  if (pin_transition) {
+    // Only one window can be pinned.
+    if (event->IsPinEvent() &&
+        Shell::Get()->screen_pinning_controller()->IsPinned()) {
+      return;
+    }
+    mojom::WindowStateType next_state_type = GetStateForTransitionEvent(event);
+    delegate_->HandleWindowStateRequest(state_type_, next_state_type);
+    mojom::WindowStateType old_state_type = state_type_;
+
+    bool was_pinned = window_state->IsPinned();
+    bool was_trusted_pinned = window_state->IsTrustedPinned();
+
+    EnterNextState(window_state, next_state_type);
+
+    VLOG(1) << "Processing Pinned Transtion: event=" << event->type()
+            << ", state=" << old_state_type << "=>" << next_state_type
+            << ", pinned=" << was_pinned << "=>" << window_state->IsPinned()
+            << ", trusted pinned=" << was_trusted_pinned << "=>"
+            << window_state->IsTrustedPinned();
+    return;
+  }
+
+  switch (event->type()) {
+    case WM_EVENT_NORMAL:
+    case WM_EVENT_MAXIMIZE:
+    case WM_EVENT_MINIMIZE:
+    case WM_EVENT_FULLSCREEN:
+    case WM_EVENT_SNAP_LEFT:
+    case WM_EVENT_SNAP_RIGHT: {
+      // Reset window state
+      window_state->UpdateWindowPropertiesFromStateType();
+      mojom::WindowStateType next_state = GetStateForTransitionEvent(event);
+      VLOG(1) << "Processing State Transtion: event=" << event->type()
+              << ", state=" << state_type_ << ", next_state=" << next_state;
+      // Then ask delegate to handle the window state change.
+      delegate_->HandleWindowStateRequest(state_type_, next_state);
+      break;
+    }
+    case WM_EVENT_SHOW_INACTIVE:
+      NOTREACHED();
+      break;
+    default:
+      NOTREACHED() << "Unknown event :" << event->type();
+  }
+}
+
+void ClientControlledState::AttachState(
+    WindowState* window_state,
+    WindowState::State* state_in_previous_mode) {}
+
+void ClientControlledState::DetachState(WindowState* window_state) {}
+
+void ClientControlledState::HandleWorkspaceEvents(WindowState* window_state,
+                                                  const WMEvent* event) {
+  // Client is responsible for adjusting bounds after workspace bounds change.
+}
+
+void ClientControlledState::HandleCompoundEvents(WindowState* window_state,
+                                                 const WMEvent* event) {
+  switch (event->type()) {
+    case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION:
+      if (window_state->IsFullscreen()) {
+        const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
+        window_state->OnWMEvent(&event);
+      } else if (window_state->IsMaximized()) {
+        window_state->Restore();
+      } else if (window_state->IsNormalOrSnapped()) {
+        if (window_state->CanMaximize())
+          window_state->Maximize();
+      }
+      break;
+    case WM_EVENT_TOGGLE_MAXIMIZE:
+      if (window_state->IsFullscreen()) {
+        const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
+        window_state->OnWMEvent(&event);
+      } else if (window_state->IsMaximized()) {
+        window_state->Restore();
+      } else if (window_state->CanMaximize()) {
+        window_state->Maximize();
+      }
+      break;
+    case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE:
+      // TODO(oshima): Implement this.
+      break;
+    case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE:
+      // TODO(oshima): Implement this.
+      break;
+    case WM_EVENT_TOGGLE_FULLSCREEN:
+      ToggleFullScreen(window_state, window_state->delegate());
+      break;
+    case WM_EVENT_CYCLE_SNAP_LEFT:
+    case WM_EVENT_CYCLE_SNAP_RIGHT:
+      // TODO(oshima): implement this.
+      break;
+    default:
+      NOTREACHED() << "Invalid event :" << event->type();
+      break;
+  }
+}
+
+void ClientControlledState::HandleBoundsEvents(WindowState* window_state,
+                                               const WMEvent* event) {
+  switch (event->type()) {
+    case WM_EVENT_SET_BOUNDS: {
+      // TODO(oshima): Send the set bounds request to client.
+      const SetBoundsEvent* set_bounds_event =
+          static_cast<const SetBoundsEvent*>(event);
+      if (set_bounds_locally_) {
+        window_state->SetBoundsDirect(set_bounds_event->requested_bounds());
+      } else {
+        delegate_->HandleBoundsRequest(window_state->GetStateType(),
+                                       set_bounds_event->requested_bounds());
+      }
+      break;
+    }
+    case WM_EVENT_CENTER:
+      // TODO(oshima): implement this.
+      break;
+    default:
+      NOTREACHED() << "Unknown event:" << event->type();
+  }
+}
+
+bool ClientControlledState::EnterNextState(
+    WindowState* window_state,
+    mojom::WindowStateType next_state_type) {
+  // Do nothing if  we're already in the same state.
+  if (state_type_ == next_state_type)
+    return false;
+
+  mojom::WindowStateType previous_state_type = state_type_;
+  state_type_ = next_state_type;
+
+  window_state->UpdateWindowPropertiesFromStateType();
+  window_state->NotifyPreStateTypeChange(previous_state_type);
+
+  // Don't update the window if the window is detached from parent.
+  // This can happen during dragging.
+  // TODO(oshima): This was added for DOCKED windows. Investigate if
+  // we still need this.
+  if (window_state->window()->parent())
+    UpdateMinimizedState(window_state, previous_state_type);
+
+  window_state->NotifyPostStateTypeChange(previous_state_type);
+
+  if (next_state_type == mojom::WindowStateType::PINNED ||
+      previous_state_type == mojom::WindowStateType::PINNED ||
+      next_state_type == mojom::WindowStateType::TRUSTED_PINNED ||
+      previous_state_type == mojom::WindowStateType::TRUSTED_PINNED) {
+    Shell::Get()->screen_pinning_controller()->SetPinnedWindow(
+        window_state->window());
+  }
+  return true;
+}
+
+}  // namespace wm
+}  // namespace ash
diff --git a/ash/wm/client_controlled_state.h b/ash/wm/client_controlled_state.h
new file mode 100644
index 0000000..cdfe54c
--- /dev/null
+++ b/ash/wm/client_controlled_state.h
@@ -0,0 +1,86 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_WM_CLIENT_CONTROLLED_STATE_H_
+#define ASH_WM_CLIENT_CONTROLLED_STATE_H_
+
+#include <memory>
+
+#include "ash/ash_export.h"
+#include "ash/wm/base_state.h"
+#include "ash/wm/wm_event.h"
+#include "base/macros.h"
+#include "ui/display/display.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace ash {
+namespace mojom {
+enum class WindowStateType;
+}
+
+namespace wm {
+
+// ClientControlledState delegates the window state transition and
+// bounds control to the client. Its window state and bounds are
+// determined by the delegate. ARC++ window's state is controlled by
+// Android framework, for example.
+class ASH_EXPORT ClientControlledState : public BaseState {
+ public:
+  class Delegate {
+   public:
+    virtual ~Delegate() = default;
+    // Handles the state change from |current_state| to |requested_state|.
+    // Delegate may decide to ignore the state change, proceed with the state
+    // change, or can move to a different state.
+    virtual void HandleWindowStateRequest(
+        mojom::WindowStateType current_state,
+        mojom::WindowStateType requested_state) = 0;
+    // Handles the bounds change request. |current_state| specifies the current
+    // window state. Delegate may choose to ignore the request, set the given
+    // bounds, or set the different bounds.
+    virtual void HandleBoundsRequest(mojom::WindowStateType current_state,
+                                     const gfx::Rect& requested_bounds) = 0;
+  };
+
+  explicit ClientControlledState(std::unique_ptr<Delegate> delegate);
+  ~ClientControlledState() override;
+
+  // A flag used to update the window's bounds directly, instead of
+  // delegating to |Delegate|. The Delegate should use this to
+  // apply the bounds change to the window.
+  void set_bounds_locally(bool set) { set_bounds_locally_ = set; }
+
+  // WindowState::State:
+  void AttachState(WindowState* window_state,
+                   WindowState::State* previous_state) override;
+  void DetachState(WindowState* window_state) override;
+
+  // BaseState:
+  void HandleWorkspaceEvents(WindowState* window_state,
+                             const WMEvent* event) override;
+  void HandleCompoundEvents(WindowState* window_state,
+                            const WMEvent* event) override;
+  void HandleBoundsEvents(WindowState* window_state,
+                          const WMEvent* event) override;
+  void HandleTransitionEvents(WindowState* window_state,
+                              const WMEvent* event) override;
+
+  // Enters next state. This is used when the state moves from one to another
+  // within the same desktop mode. Returns true if the state has changed, or
+  // false otherwise.
+  bool EnterNextState(wm::WindowState* window_state,
+                      mojom::WindowStateType next_state_type);
+
+ private:
+  std::unique_ptr<Delegate> delegate_;
+
+  bool set_bounds_locally_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(ClientControlledState);
+};
+
+}  // namespace wm
+}  // namespace ash
+
+#endif  // ASH_WM_DEFAULT_STATE_H_
diff --git a/ash/wm/client_controlled_state_unittest.cc b/ash/wm/client_controlled_state_unittest.cc
new file mode 100644
index 0000000..fef345b
--- /dev/null
+++ b/ash/wm/client_controlled_state_unittest.cc
@@ -0,0 +1,335 @@
+// Copyright 2013 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/wm/client_controlled_state.h"
+
+#include "ash/public/cpp/shell_window_ids.h"
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/wm/screen_pinning_controller.h"
+#include "ash/wm/window_state.h"
+#include "ash/wm/wm_event.h"
+#include "base/macros.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+namespace wm {
+namespace {
+
+constexpr gfx::Rect kInitialBounds(0, 0, 100, 100);
+
+class TestClientControlledStateDelegate
+    : public ClientControlledState::Delegate {
+ public:
+  TestClientControlledStateDelegate() = default;
+  ~TestClientControlledStateDelegate() override = default;
+
+  void HandleWindowStateRequest(mojom::WindowStateType current_state,
+                                mojom::WindowStateType next_state) override {
+    old_state_ = current_state;
+    new_state_ = next_state;
+  }
+
+  void HandleBoundsRequest(mojom::WindowStateType current_state,
+                           const gfx::Rect& bounds) override {
+    requested_bounds_ = bounds;
+  }
+
+  mojom::WindowStateType old_state() const { return old_state_; }
+
+  mojom::WindowStateType new_state() const { return new_state_; }
+
+  const gfx::Rect& requested_bounds() const { return requested_bounds_; }
+
+  void reset() {
+    old_state_ = mojom::WindowStateType::DEFAULT;
+    new_state_ = mojom::WindowStateType::DEFAULT;
+    requested_bounds_.SetRect(0, 0, 0, 0);
+  }
+
+ private:
+  mojom::WindowStateType old_state_ = mojom::WindowStateType::DEFAULT;
+  mojom::WindowStateType new_state_ = mojom::WindowStateType::DEFAULT;
+  gfx::Rect requested_bounds_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestClientControlledStateDelegate);
+};
+
+}  // namespace
+
+class ClientControlledStateTest : public AshTestBase {
+ public:
+  ClientControlledStateTest() = default;
+  ~ClientControlledStateTest() override = default;
+
+  void SetUp() override {
+    AshTestBase::SetUp();
+
+    widget_ = std::make_unique<views::Widget>();
+    views::Widget::InitParams params;
+    params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+    params.parent = Shell::GetPrimaryRootWindow()->GetChildById(
+        kShellWindowId_DefaultContainer);
+    params.bounds = kInitialBounds;
+    widget_->Init(params);
+    wm::WindowState* window_state = wm::GetWindowState(window());
+    auto delegate = std::make_unique<TestClientControlledStateDelegate>();
+    delegate_ = delegate.get();
+    auto state = std::make_unique<ClientControlledState>(std::move(delegate));
+    state_ = state.get();
+    window_state->SetStateObject(std::move(state));
+    widget_->Show();
+  }
+
+  void TearDown() override {
+    widget_ = nullptr;
+    AshTestBase::TearDown();
+  }
+
+ protected:
+  aura::Window* window() { return widget_->GetNativeWindow(); }
+  WindowState* window_state() { return GetWindowState(window()); }
+  ClientControlledState* state() { return state_; }
+  TestClientControlledStateDelegate* delegate() { return delegate_; }
+  views::Widget* widget() { return widget_.get(); }
+  ScreenPinningController* GetScreenPinningController() {
+    return Shell::Get()->screen_pinning_controller();
+  }
+
+ private:
+  ClientControlledState* state_ = nullptr;
+  TestClientControlledStateDelegate* delegate_ = nullptr;
+  std::unique_ptr<views::Widget> widget_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClientControlledStateTest);
+};
+
+// Make sure that calling Maximize()/Minimize()/Fullscreen() result in
+// sending the state change request and won't change the state immediately.
+// The state will be updated when ClientControlledState::EnterToNextState
+// is called.
+TEST_F(ClientControlledStateTest, Maximize) {
+  widget()->Maximize();
+  // The state shouldn't be updated until EnterToNextState is called.
+  EXPECT_FALSE(widget()->IsMaximized());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+  EXPECT_EQ(mojom::WindowStateType::DEFAULT, delegate()->old_state());
+  EXPECT_EQ(mojom::WindowStateType::MAXIMIZED, delegate()->new_state());
+  // Now enters the new state.
+  state()->EnterNextState(window_state(), delegate()->new_state());
+  EXPECT_TRUE(widget()->IsMaximized());
+  // Bounds is controlled by client.
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+
+  widget()->Restore();
+  EXPECT_TRUE(widget()->IsMaximized());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+  EXPECT_EQ(mojom::WindowStateType::MAXIMIZED, delegate()->old_state());
+  EXPECT_EQ(mojom::WindowStateType::NORMAL, delegate()->new_state());
+  state()->EnterNextState(window_state(), delegate()->new_state());
+  EXPECT_FALSE(widget()->IsMaximized());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+}
+
+TEST_F(ClientControlledStateTest, Minimize) {
+  widget()->Minimize();
+  EXPECT_FALSE(widget()->IsMinimized());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+  EXPECT_EQ(mojom::WindowStateType::DEFAULT, delegate()->old_state());
+  EXPECT_EQ(mojom::WindowStateType::MINIMIZED, delegate()->new_state());
+  state()->EnterNextState(window_state(), delegate()->new_state());
+  EXPECT_TRUE(widget()->IsMinimized());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+
+  widget()->Restore();
+  EXPECT_TRUE(widget()->IsMinimized());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+  EXPECT_EQ(mojom::WindowStateType::MINIMIZED, delegate()->old_state());
+  EXPECT_EQ(mojom::WindowStateType::NORMAL, delegate()->new_state());
+  state()->EnterNextState(window_state(), delegate()->new_state());
+  EXPECT_FALSE(widget()->IsMinimized());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+}
+
+TEST_F(ClientControlledStateTest, Fullscreen) {
+  widget()->SetFullscreen(true);
+  EXPECT_FALSE(widget()->IsFullscreen());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+  EXPECT_EQ(mojom::WindowStateType::DEFAULT, delegate()->old_state());
+  EXPECT_EQ(mojom::WindowStateType::FULLSCREEN, delegate()->new_state());
+  state()->EnterNextState(window_state(), delegate()->new_state());
+  EXPECT_TRUE(widget()->IsFullscreen());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+
+  widget()->SetFullscreen(false);
+  EXPECT_TRUE(widget()->IsFullscreen());
+  EXPECT_EQ(mojom::WindowStateType::FULLSCREEN, delegate()->old_state());
+  EXPECT_EQ(mojom::WindowStateType::NORMAL, delegate()->new_state());
+  state()->EnterNextState(window_state(), delegate()->new_state());
+  EXPECT_FALSE(widget()->IsFullscreen());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+}
+
+// Make sure toggle fullscreen from maximized state goes back to
+// maximized state.
+TEST_F(ClientControlledStateTest, MaximizeToFullscreen) {
+  widget()->Maximize();
+  EXPECT_FALSE(widget()->IsMaximized());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+  EXPECT_EQ(mojom::WindowStateType::DEFAULT, delegate()->old_state());
+  EXPECT_EQ(mojom::WindowStateType::MAXIMIZED, delegate()->new_state());
+  state()->EnterNextState(window_state(), delegate()->new_state());
+  EXPECT_TRUE(widget()->IsMaximized());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+
+  widget()->SetFullscreen(true);
+  EXPECT_TRUE(widget()->IsMaximized());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+  EXPECT_EQ(mojom::WindowStateType::MAXIMIZED, delegate()->old_state());
+  EXPECT_EQ(mojom::WindowStateType::FULLSCREEN, delegate()->new_state());
+  state()->EnterNextState(window_state(), delegate()->new_state());
+  EXPECT_TRUE(widget()->IsFullscreen());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+
+  widget()->SetFullscreen(false);
+  EXPECT_TRUE(widget()->IsFullscreen());
+  EXPECT_EQ(mojom::WindowStateType::FULLSCREEN, delegate()->old_state());
+  EXPECT_EQ(mojom::WindowStateType::MAXIMIZED, delegate()->new_state());
+  state()->EnterNextState(window_state(), delegate()->new_state());
+  EXPECT_TRUE(widget()->IsMaximized());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+
+  widget()->Restore();
+  EXPECT_TRUE(widget()->IsMaximized());
+  EXPECT_EQ(mojom::WindowStateType::MAXIMIZED, delegate()->old_state());
+  EXPECT_EQ(mojom::WindowStateType::NORMAL, delegate()->new_state());
+  state()->EnterNextState(window_state(), delegate()->new_state());
+  EXPECT_FALSE(widget()->IsMaximized());
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+}
+
+TEST_F(ClientControlledStateTest, IgnoreWorkspace) {
+  widget()->Maximize();
+  state()->EnterNextState(window_state(), delegate()->new_state());
+  EXPECT_TRUE(widget()->IsMaximized());
+  delegate()->reset();
+
+  UpdateDisplay("1000x800");
+
+  // Client is responsible to handle workspace change, so
+  // no action should be taken.
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+  EXPECT_EQ(mojom::WindowStateType::DEFAULT, delegate()->old_state());
+  EXPECT_EQ(mojom::WindowStateType::DEFAULT, delegate()->new_state());
+  EXPECT_EQ(gfx::Rect(), delegate()->requested_bounds());
+}
+
+TEST_F(ClientControlledStateTest, SetBounds) {
+  constexpr gfx::Rect new_bounds(100, 100, 100, 100);
+  widget()->SetBounds(new_bounds);
+  EXPECT_EQ(kInitialBounds, widget()->GetWindowBoundsInScreen());
+  EXPECT_EQ(new_bounds, delegate()->requested_bounds());
+  state()->set_bounds_locally(true);
+  widget()->SetBounds(delegate()->requested_bounds());
+  state()->set_bounds_locally(false);
+  EXPECT_EQ(new_bounds, widget()->GetWindowBoundsInScreen());
+}
+
+// Pin events should be applied immediately.
+TEST_F(ClientControlledStateTest, Pinned) {
+  ASSERT_FALSE(window_state()->IsPinned());
+  ASSERT_FALSE(GetScreenPinningController()->IsPinned());
+
+  const WMEvent pin_event(WM_EVENT_PIN);
+  window_state()->OnWMEvent(&pin_event);
+  EXPECT_TRUE(window_state()->IsPinned());
+  EXPECT_TRUE(GetScreenPinningController()->IsPinned());
+  EXPECT_EQ(mojom::WindowStateType::PINNED, window_state()->GetStateType());
+  EXPECT_EQ(mojom::WindowStateType::DEFAULT, delegate()->old_state());
+  EXPECT_EQ(mojom::WindowStateType::PINNED, delegate()->new_state());
+
+  // All state transition events are ignored except for NORMAL.
+  widget()->Maximize();
+  EXPECT_EQ(mojom::WindowStateType::PINNED, window_state()->GetStateType());
+  EXPECT_TRUE(GetScreenPinningController()->IsPinned());
+
+  widget()->Minimize();
+  EXPECT_EQ(mojom::WindowStateType::PINNED, window_state()->GetStateType());
+  EXPECT_TRUE(GetScreenPinningController()->IsPinned());
+  EXPECT_TRUE(window()->IsVisible());
+
+  widget()->SetFullscreen(true);
+  EXPECT_EQ(mojom::WindowStateType::PINNED, window_state()->GetStateType());
+  EXPECT_TRUE(GetScreenPinningController()->IsPinned());
+
+  widget()->Restore();
+  EXPECT_FALSE(window_state()->IsPinned());
+  EXPECT_EQ(mojom::WindowStateType::NORMAL, window_state()->GetStateType());
+  EXPECT_FALSE(GetScreenPinningController()->IsPinned());
+
+  // Two windows cannot be pinned simultaneously.
+  auto widget2 = CreateTestWidget();
+  WindowState* window_state_2 =
+      ::ash::wm::GetWindowState(widget2->GetNativeWindow());
+  window_state_2->OnWMEvent(&pin_event);
+  EXPECT_TRUE(window_state_2->IsPinned());
+  EXPECT_TRUE(GetScreenPinningController()->IsPinned());
+
+  // Pin request should fail.
+  window_state()->OnWMEvent(&pin_event);
+  EXPECT_FALSE(window_state()->IsPinned());
+}
+
+TEST_F(ClientControlledStateTest, TrustedPinnedBasic) {
+  EXPECT_FALSE(window_state()->IsPinned());
+  EXPECT_FALSE(GetScreenPinningController()->IsPinned());
+
+  const WMEvent trusted_pin_event(WM_EVENT_TRUSTED_PIN);
+  window_state()->OnWMEvent(&trusted_pin_event);
+  EXPECT_TRUE(window_state()->IsPinned());
+  EXPECT_TRUE(GetScreenPinningController()->IsPinned());
+
+  EXPECT_EQ(mojom::WindowStateType::TRUSTED_PINNED,
+            window_state()->GetStateType());
+  EXPECT_EQ(mojom::WindowStateType::DEFAULT, delegate()->old_state());
+  EXPECT_EQ(mojom::WindowStateType::TRUSTED_PINNED, delegate()->new_state());
+
+  // All state transition events are ignored except for NORMAL.
+  widget()->Maximize();
+  EXPECT_EQ(mojom::WindowStateType::TRUSTED_PINNED,
+            window_state()->GetStateType());
+  EXPECT_TRUE(GetScreenPinningController()->IsPinned());
+
+  widget()->Minimize();
+  EXPECT_EQ(mojom::WindowStateType::TRUSTED_PINNED,
+            window_state()->GetStateType());
+  EXPECT_TRUE(GetScreenPinningController()->IsPinned());
+  EXPECT_TRUE(window()->IsVisible());
+
+  widget()->SetFullscreen(true);
+  EXPECT_EQ(mojom::WindowStateType::TRUSTED_PINNED,
+            window_state()->GetStateType());
+  EXPECT_TRUE(GetScreenPinningController()->IsPinned());
+
+  widget()->Restore();
+  EXPECT_FALSE(window_state()->IsPinned());
+  EXPECT_EQ(mojom::WindowStateType::NORMAL, window_state()->GetStateType());
+  EXPECT_FALSE(GetScreenPinningController()->IsPinned());
+
+  // Two windows cannot be trusted-pinned simultaneously.
+  auto widget2 = CreateTestWidget();
+  WindowState* window_state_2 =
+      ::ash::wm::GetWindowState(widget2->GetNativeWindow());
+  window_state_2->OnWMEvent(&trusted_pin_event);
+  EXPECT_TRUE(window_state_2->IsTrustedPinned());
+  EXPECT_TRUE(GetScreenPinningController()->IsPinned());
+
+  EXPECT_FALSE(window_state()->IsTrustedPinned());
+  window_state()->OnWMEvent(&trusted_pin_event);
+  EXPECT_FALSE(window_state()->IsTrustedPinned());
+  EXPECT_TRUE(window_state_2->IsTrustedPinned());
+}
+
+}  // namespace wm
+}  // namespace ash
diff --git a/ash/wm/default_state.cc b/ash/wm/default_state.cc
index 5390a66..2466749 100644
--- a/ash/wm/default_state.cc
+++ b/ash/wm/default_state.cc
@@ -103,79 +103,41 @@
 }  // namespace
 
 DefaultState::DefaultState(mojom::WindowStateType initial_state_type)
-    : state_type_(initial_state_type), stored_window_state_(nullptr) {}
+    : BaseState(initial_state_type), stored_window_state_(nullptr) {}
 
 DefaultState::~DefaultState() {}
 
-void DefaultState::OnWMEvent(WindowState* window_state, const WMEvent* event) {
-  if (ProcessWorkspaceEvents(window_state, event))
-    return;
-
-  // Do not change the PINNED window state if this is not unpin event.
-  if (window_state->IsTrustedPinned() && event->type() != WM_EVENT_NORMAL)
-    return;
-
-  if (ProcessCompoundEvents(window_state, event))
-    return;
-
-  mojom::WindowStateType current_state_type = window_state->GetStateType();
-  mojom::WindowStateType next_state_type = mojom::WindowStateType::NORMAL;
+void DefaultState::HandleBoundsEvents(WindowState* window_state,
+                                      const WMEvent* event) {
   switch (event->type()) {
-    case WM_EVENT_NORMAL:
-      next_state_type = mojom::WindowStateType::NORMAL;
-      break;
-    case WM_EVENT_MAXIMIZE:
-      next_state_type = mojom::WindowStateType::MAXIMIZED;
-      break;
-    case WM_EVENT_MINIMIZE:
-      next_state_type = mojom::WindowStateType::MINIMIZED;
-      break;
-    case WM_EVENT_FULLSCREEN:
-      next_state_type = mojom::WindowStateType::FULLSCREEN;
-      break;
-    case WM_EVENT_SNAP_LEFT:
-      next_state_type = mojom::WindowStateType::LEFT_SNAPPED;
-      break;
-    case WM_EVENT_SNAP_RIGHT:
-      next_state_type = mojom::WindowStateType::RIGHT_SNAPPED;
-      break;
-    case WM_EVENT_SET_BOUNDS:
-      SetBounds(window_state, static_cast<const SetBoundsEvent*>(event));
-      return;
-    case WM_EVENT_SHOW_INACTIVE:
-      next_state_type = mojom::WindowStateType::INACTIVE;
-      break;
-    case WM_EVENT_PIN:
-    case WM_EVENT_TRUSTED_PIN:
-      // If there already is a pinned window, it is not allowed to set it
-      // to this window.
-      // TODO(hidehiko): If a system modal window is openening, the pinning
-      // probably should fail.
-      if (Shell::Get()->screen_pinning_controller()->IsPinned()) {
-        LOG(ERROR) << "An PIN event will be failed since another window is "
-                   << "already in pinned mode.";
-        next_state_type = current_state_type;
-      } else {
-        next_state_type = event->type() == WM_EVENT_PIN
-                              ? mojom::WindowStateType::PINNED
-                              : mojom::WindowStateType::TRUSTED_PINNED;
-      }
-      break;
-    case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION:
-    case WM_EVENT_TOGGLE_MAXIMIZE:
-    case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE:
-    case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE:
-    case WM_EVENT_TOGGLE_FULLSCREEN:
-    case WM_EVENT_CYCLE_SNAP_LEFT:
-    case WM_EVENT_CYCLE_SNAP_RIGHT:
+    case WM_EVENT_SET_BOUNDS: {
+      const SetBoundsEvent* set_bounds_event =
+          static_cast<const SetBoundsEvent*>(event);
+      SetBounds(window_state, set_bounds_event);
+    } break;
     case WM_EVENT_CENTER:
-      NOTREACHED() << "Compound event should not reach here:" << event;
-      return;
-    case WM_EVENT_ADDED_TO_WORKSPACE:
-    case WM_EVENT_WORKAREA_BOUNDS_CHANGED:
-    case WM_EVENT_DISPLAY_BOUNDS_CHANGED:
-      NOTREACHED() << "Workspace event should not reach here:" << event;
-      return;
+      CenterWindow(window_state);
+      break;
+    default:
+      NOTREACHED() << "Unknown event:" << event->type();
+      break;
+  }
+}
+
+void DefaultState::HandleTransitionEvents(WindowState* window_state,
+                                          const WMEvent* event) {
+  mojom::WindowStateType current_state_type = window_state->GetStateType();
+  mojom::WindowStateType next_state_type = GetStateForTransitionEvent(event);
+  if (event->IsPinEvent()) {
+    // If there already is a pinned window, it is not allowed to set it
+    // to this window.
+    // TODO(hidehiko): If a system modal window is openening, the pinning
+    // probably should fail.
+    if (Shell::Get()->screen_pinning_controller()->IsPinned()) {
+      LOG(ERROR) << "An PIN event will be failed since another window is "
+                 << "already in pinned mode.";
+      next_state_type = current_state_type;
+    }
   }
 
   if (next_state_type == current_state_type && window_state->IsSnapped()) {
@@ -196,10 +158,6 @@
   EnterToNextState(window_state, next_state_type);
 }
 
-mojom::WindowStateType DefaultState::GetType() const {
-  return state_type_;
-}
-
 void DefaultState::AttachState(WindowState* window_state,
                                WindowState::State* state_in_previous_mode) {
   DCHECK_EQ(stored_window_state_, window_state);
@@ -234,9 +192,8 @@
       window_state->window());
 }
 
-// static
-bool DefaultState::ProcessCompoundEvents(WindowState* window_state,
-                                         const WMEvent* event) {
+void DefaultState::HandleCompoundEvents(WindowState* window_state,
+                                        const WMEvent* event) {
   aura::Window* window = window_state->window();
 
   switch (event->type()) {
@@ -250,7 +207,7 @@
         if (window_state->CanMaximize())
           window_state->Maximize();
       }
-      return true;
+      return;
     case WM_EVENT_TOGGLE_MAXIMIZE:
       if (window_state->IsFullscreen()) {
         const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
@@ -260,7 +217,7 @@
       } else if (window_state->CanMaximize()) {
         window_state->Maximize();
       }
-      return true;
+      return;
     case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: {
       gfx::Rect work_area =
           ScreenUtil::GetDisplayWorkAreaBoundsInParent(window);
@@ -272,7 +229,7 @@
       //   restored bounds looks weird.
       if (GetWindowMaximumSize(window).height() != 0 ||
           !window_state->IsNormalStateType()) {
-        return true;
+        return;
       }
       if (window_state->HasRestoreBounds() &&
           (window->bounds().height() == work_area.height() &&
@@ -284,16 +241,16 @@
                                     window->bounds().width(),
                                     work_area.height()));
       }
-      return true;
+      return;
     }
     case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: {
       // Maximize horizontally if:
       // - The window does not have a max width defined.
       // - The window is snapped or has the normal state type.
       if (GetWindowMaximumSize(window).width() != 0)
-        return true;
+        return;
       if (!window_state->IsNormalOrSnapped())
-        return true;
+        return;
       gfx::Rect work_area =
           ScreenUtil::GetDisplayWorkAreaBoundsInParent(window);
       if (window_state->IsNormalStateType() &&
@@ -318,40 +275,23 @@
         window_state->SetRestoreBoundsInParent(restore_bounds);
         window->SetBounds(new_bounds);
       }
-      return true;
+      return;
     }
     case WM_EVENT_TOGGLE_FULLSCREEN:
       ToggleFullScreen(window_state, window_state->delegate());
-      return true;
+      return;
     case WM_EVENT_CYCLE_SNAP_LEFT:
     case WM_EVENT_CYCLE_SNAP_RIGHT:
       CycleSnap(window_state, event->type());
-      return true;
-    case WM_EVENT_CENTER:
-      CenterWindow(window_state);
-      return true;
-    case WM_EVENT_NORMAL:
-    case WM_EVENT_MAXIMIZE:
-    case WM_EVENT_MINIMIZE:
-    case WM_EVENT_FULLSCREEN:
-    case WM_EVENT_PIN:
-    case WM_EVENT_TRUSTED_PIN:
-    case WM_EVENT_SNAP_LEFT:
-    case WM_EVENT_SNAP_RIGHT:
-    case WM_EVENT_SET_BOUNDS:
-    case WM_EVENT_SHOW_INACTIVE:
-      break;
-    case WM_EVENT_ADDED_TO_WORKSPACE:
-    case WM_EVENT_WORKAREA_BOUNDS_CHANGED:
-    case WM_EVENT_DISPLAY_BOUNDS_CHANGED:
-      NOTREACHED() << "Workspace event should not reach here:" << event;
+      return;
+    default:
+      NOTREACHED() << "Unknown event:" << event->type();
       break;
   }
-  return false;
 }
 
-bool DefaultState::ProcessWorkspaceEvents(WindowState* window_state,
-                                          const WMEvent* event) {
+void DefaultState::HandleWorkspaceEvents(WindowState* window_state,
+                                         const WMEvent* event) {
   switch (event->type()) {
     case WM_EVENT_ADDED_TO_WORKSPACE: {
       // When a window is dragged and dropped onto a different
@@ -362,7 +302,7 @@
       if (window_state->is_dragged() ||
           window_state->allow_set_bounds_direct() ||
           SetMaximizedOrFullscreenBounds(window_state)) {
-        return true;
+        return;
       }
 
       aura::Window* window = window_state->window();
@@ -371,14 +311,14 @@
       // Don't adjust window bounds if the bounds are empty as this
       // happens when a new views::Widget is created.
       if (bounds.IsEmpty())
-        return true;
+        return;
 
       // Only windows of type WINDOW_TYPE_NORMAL or WINDOW_TYPE_PANEL need to be
       // adjusted to have minimum visibility, because they are positioned by the
       // user and user should always be able to interact with them. Other
       // windows are positioned programmatically.
       if (!window_state->IsUserPositionable())
-        return true;
+        return;
 
       // Use entire display instead of workarea. The logic ensures 30%
       // visibility which should be enough to see where the window gets
@@ -391,13 +331,13 @@
       window_state->AdjustSnappedBounds(&bounds);
       if (window->bounds() != bounds)
         window_state->SetBoundsConstrained(bounds);
-      return true;
+      return;
     }
     case WM_EVENT_DISPLAY_BOUNDS_CHANGED: {
       if (window_state->is_dragged() ||
           window_state->allow_set_bounds_direct() ||
           SetMaximizedOrFullscreenBounds(window_state)) {
-        return true;
+        return;
       }
       gfx::Rect work_area_in_parent =
           ScreenUtil::GetDisplayWorkAreaBoundsInParent(window_state->window());
@@ -408,7 +348,7 @@
       window_state->AdjustSnappedBounds(&bounds);
       if (window_state->window()->GetTargetBounds() != bounds)
         window_state->SetBoundsDirectAnimated(bounds);
-      return true;
+      return;
     }
     case WM_EVENT_WORKAREA_BOUNDS_CHANGED: {
       // Don't resize the maximized window when the desktop is covered
@@ -417,12 +357,12 @@
           RootWindowController::ForWindow(window_state->window())
               ->GetWorkspaceWindowState() == WORKSPACE_WINDOW_STATE_FULL_SCREEN;
       if (in_fullscreen && window_state->IsMaximized())
-        return true;
+        return;
 
       if (window_state->is_dragged() ||
           window_state->allow_set_bounds_direct() ||
           SetMaximizedOrFullscreenBounds(window_state)) {
-        return true;
+        return;
       }
       gfx::Rect work_area_in_parent =
           ScreenUtil::GetDisplayWorkAreaBoundsInParent(window_state->window());
@@ -434,29 +374,11 @@
       window_state->AdjustSnappedBounds(&bounds);
       if (window_state->window()->GetTargetBounds() != bounds)
         window_state->SetBoundsDirectAnimated(bounds);
-      return true;
+      return;
     }
-    case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION:
-    case WM_EVENT_TOGGLE_MAXIMIZE:
-    case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE:
-    case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE:
-    case WM_EVENT_TOGGLE_FULLSCREEN:
-    case WM_EVENT_CYCLE_SNAP_LEFT:
-    case WM_EVENT_CYCLE_SNAP_RIGHT:
-    case WM_EVENT_CENTER:
-    case WM_EVENT_NORMAL:
-    case WM_EVENT_MAXIMIZE:
-    case WM_EVENT_MINIMIZE:
-    case WM_EVENT_FULLSCREEN:
-    case WM_EVENT_PIN:
-    case WM_EVENT_TRUSTED_PIN:
-    case WM_EVENT_SNAP_LEFT:
-    case WM_EVENT_SNAP_RIGHT:
-    case WM_EVENT_SET_BOUNDS:
-    case WM_EVENT_SHOW_INACTIVE:
-      break;
+    default:
+      NOTREACHED() << "Unknown event:" << event->type();
   }
-  return false;
 }
 
 // static
@@ -506,6 +428,10 @@
   window_state->UpdateWindowPropertiesFromStateType();
   window_state->NotifyPreStateTypeChange(previous_state_type);
 
+  // Don't update the window if the window is detached from parent.
+  // This can happen during dragging.
+  // TODO(oshima): This was added for DOCKED windows. Investigate if
+  // we still need this.
   if (window_state->window()->parent()) {
     if (!window_state->HasRestoreBounds() &&
         (previous_state_type == mojom::WindowStateType::DEFAULT ||
@@ -530,6 +456,7 @@
       MoveToDisplayForRestore(window_state);
 
     UpdateBoundsFromState(window_state, previous_state_type);
+    UpdateMinimizedState(window_state, previous_state_type);
 
     // Normal state should have no restore bounds unless it's
     // unminimized.
@@ -580,6 +507,7 @@
   }
 
   UpdateBoundsFromState(window_state, state_in_previous_mode->GetType());
+  UpdateMinimizedState(window_state, state_in_previous_mode->GetType());
 
   // Then restore the restore bounds to their previous value.
   if (!stored_restore_bounds_.IsEmpty())
@@ -666,29 +594,6 @@
       window_state->SetBoundsDirectAnimated(bounds_in_parent);
     }
   }
-
-  if (window_state->IsMinimized()) {
-    // Save the previous show state so that we can correctly restore it after
-    // exiting the minimized mode.
-    window->SetProperty(aura::client::kPreMinimizedShowStateKey,
-                        ToWindowShowState(previous_state_type));
-    ::wm::SetWindowVisibilityAnimationType(
-        window, WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE);
-
-    window->Hide();
-    if (window_state->IsActive())
-      window_state->Deactivate();
-  } else if ((window->layer()->GetTargetVisibility() ||
-              IsMinimizedWindowState(previous_state_type)) &&
-             !window->layer()->visible()) {
-    // The layer may be hidden if the window was previously minimized. Make
-    // sure it's visible.
-    window->Show();
-    if (IsMinimizedWindowState(previous_state_type) &&
-        !window_state->IsMaximizedOrFullscreenOrPinned()) {
-      window_state->set_unminimize_to_restore_bounds(false);
-    }
-  }
 }
 
 // static
diff --git a/ash/wm/default_state.h b/ash/wm/default_state.h
index c2dea52..b98c341 100644
--- a/ash/wm/default_state.h
+++ b/ash/wm/default_state.h
@@ -5,6 +5,7 @@
 #ifndef ASH_WM_DEFAULT_STATE_H_
 #define ASH_WM_DEFAULT_STATE_H_
 
+#include "ash/wm/base_state.h"
 #include "ash/wm/window_state.h"
 #include "base/macros.h"
 #include "ui/display/display.h"
@@ -19,28 +20,27 @@
 class SetBoundsEvent;
 
 // DefaultState implements Ash behavior without state machine.
-class DefaultState : public WindowState::State {
+class DefaultState : public BaseState {
  public:
   explicit DefaultState(mojom::WindowStateType initial_state_type);
   ~DefaultState() override;
 
   // WindowState::State overrides:
-  void OnWMEvent(WindowState* window_state, const WMEvent* event) override;
-  mojom::WindowStateType GetType() const override;
   void AttachState(WindowState* window_state,
                    WindowState::State* previous_state) override;
   void DetachState(WindowState* window_state) override;
 
+  // BaseState:
+  void HandleWorkspaceEvents(WindowState* window_state,
+                             const WMEvent* event) override;
+  void HandleCompoundEvents(WindowState* window_state,
+                            const WMEvent* event) override;
+  void HandleBoundsEvents(WindowState* window_state,
+                          const WMEvent* event) override;
+  void HandleTransitionEvents(WindowState* window_state,
+                              const WMEvent* event) override;
+
  private:
-  // Process state dependent events, such as TOGGLE_MAXIMIZED,
-  // TOGGLE_FULLSCREEN.
-  static bool ProcessCompoundEvents(WindowState* window_state,
-                                    const WMEvent* event);
-
-  // Process workspace related events, such as DISPLAY_BOUNDS_CHANGED.
-  static bool ProcessWorkspaceEvents(WindowState* window_state,
-                                     const WMEvent* event);
-
   // Set the fullscreen/maximized bounds without animation.
   static bool SetMaximizedOrFullscreenBounds(wm::WindowState* window_state);
 
@@ -64,9 +64,6 @@
   void UpdateBoundsFromState(wm::WindowState* window_state,
                              mojom::WindowStateType old_state_type);
 
-  // The current type of the window.
-  mojom::WindowStateType state_type_;
-
   // The saved window state for the case that the state gets de-/activated.
   gfx::Rect stored_bounds_;
   gfx::Rect stored_restore_bounds_;
diff --git a/ash/wm/overview/scoped_transform_overview_window.cc b/ash/wm/overview/scoped_transform_overview_window.cc
index 774cd96..0f94247 100644
--- a/ash/wm/overview/scoped_transform_overview_window.cc
+++ b/ash/wm/overview/scoped_transform_overview_window.cc
@@ -512,7 +512,6 @@
     gfx::Point location(event->location());
     ::wm::ConvertPointToScreen(minimized_widget_->GetNativeWindow(), &location);
     switch (event->type()) {
-      case ui::ET_GESTURE_SCROLL_BEGIN:
       case ui::ET_GESTURE_TAP_DOWN:
         selector_item_->HandlePressEvent(location);
         break;
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index ecb0b34..11bbebae 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -179,7 +179,6 @@
       gfx::Point location(event->location());
       views::View::ConvertPointToScreen(this, &location);
       switch (event->type()) {
-        case ui::ET_GESTURE_SCROLL_BEGIN:
         case ui::ET_GESTURE_TAP_DOWN:
           listener()->HandlePressEvent(location);
           break;
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h
index 6bf98b84..1e10744c 100644
--- a/ash/wm/window_state.h
+++ b/ash/wm/window_state.h
@@ -33,6 +33,7 @@
 class WindowStateDelegate;
 class WindowStateObserver;
 class WMEvent;
+class ClientControlledState;
 
 // Returns the WindowState for the active window, null if there is no active
 // window.
@@ -323,6 +324,7 @@
 
  private:
   friend class DefaultState;
+  friend class ash::wm::ClientControlledState;
   friend class ash::LockWindowState;
   friend class ash::TabletModeWindowState;
   friend WindowState* GetWindowState(aura::Window*);
diff --git a/ash/wm/wm_event.cc b/ash/wm/wm_event.cc
index da5b77d..2a59ad2c 100644
--- a/ash/wm/wm_event.cc
+++ b/ash/wm/wm_event.cc
@@ -7,10 +7,81 @@
 namespace ash {
 namespace wm {
 
-WMEvent::WMEvent(WMEventType type) : type_(type) {}
+WMEvent::WMEvent(WMEventType type) : type_(type) {
+  DCHECK(IsWorkspaceEvent() || IsCompoundEvent() || IsBoundsEvent() ||
+         IsTransitionEvent());
+}
 
 WMEvent::~WMEvent() {}
 
+bool WMEvent::IsWorkspaceEvent() const {
+  switch (type_) {
+    case WM_EVENT_ADDED_TO_WORKSPACE:
+    case WM_EVENT_WORKAREA_BOUNDS_CHANGED:
+    case WM_EVENT_DISPLAY_BOUNDS_CHANGED:
+      return true;
+    default:
+      break;
+  }
+  return false;
+}
+
+bool WMEvent::IsCompoundEvent() const {
+  switch (type_) {
+    case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION:
+    case WM_EVENT_TOGGLE_MAXIMIZE:
+    case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE:
+    case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE:
+    case WM_EVENT_TOGGLE_FULLSCREEN:
+    case WM_EVENT_CYCLE_SNAP_LEFT:
+    case WM_EVENT_CYCLE_SNAP_RIGHT:
+      return true;
+    default:
+      break;
+  }
+  return false;
+}
+
+bool WMEvent::IsPinEvent() const {
+  switch (type_) {
+    case WM_EVENT_PIN:
+    case WM_EVENT_TRUSTED_PIN:
+      return true;
+    default:
+      break;
+  }
+  return false;
+}
+
+bool WMEvent::IsBoundsEvent() const {
+  switch (type_) {
+    case WM_EVENT_SET_BOUNDS:
+    case WM_EVENT_CENTER:
+      return true;
+    default:
+      break;
+  }
+  return false;
+}
+
+bool WMEvent::IsTransitionEvent() const {
+  switch (type_) {
+    case WM_EVENT_NORMAL:
+    case WM_EVENT_MAXIMIZE:
+    case WM_EVENT_MINIMIZE:
+    case WM_EVENT_FULLSCREEN:
+    case WM_EVENT_SNAP_LEFT:
+    case WM_EVENT_SNAP_RIGHT:
+    case WM_EVENT_SHOW_INACTIVE:
+    case WM_EVENT_PIN:
+    case WM_EVENT_TRUSTED_PIN:
+      return true;
+    default:
+      break;
+  }
+  return false;
+}
+
 SetBoundsEvent::SetBoundsEvent(WMEventType type, const gfx::Rect& bounds)
     : WMEvent(type), requested_bounds_(bounds) {}
 
diff --git a/ash/wm/wm_event.h b/ash/wm/wm_event.h
index 3095a31..40f9c4e 100644
--- a/ash/wm/wm_event.h
+++ b/ash/wm/wm_event.h
@@ -20,7 +20,7 @@
   // state and the request may not be fullfilled.
 
   // NORMAL is used as a restore operation with a few exceptions.
-  WM_EVENT_NORMAL,
+  WM_EVENT_NORMAL = 0,
   WM_EVENT_MAXIMIZE,
   WM_EVENT_MINIMIZE,
   WM_EVENT_FULLSCREEN,
@@ -101,6 +101,28 @@
 
   WMEventType type() const { return type_; }
 
+  // Predicates to test the type of event.
+
+  // Event that notifies that workspace has changed. (its size, being
+  // added/moved to another workspace,
+  // e.g. WM_EVENT_ADDED_TO_WORKSPACE).
+  bool IsWorkspaceEvent() const;
+
+  // True if the event will result in another event. For example
+  // TOGGLE_FULLSCREEN sends WM_EVENT_FULLSCREEN or WM_EVENT_NORMAL
+  // depending on the current state.
+  bool IsCompoundEvent() const;
+
+  // WM_EVENT_PIN or WM_EVENT_TRUSTD_PIN.
+  bool IsPinEvent() const;
+
+  // True If the event requurests bounds change, e.g. SET_BOUNDS
+  bool IsBoundsEvent() const;
+
+  // True if the event requests the window state transition,
+  // e.g. WM_EVENT_MAXIMIZED.
+  bool IsTransitionEvent() const;
+
  private:
   WMEventType type_;
   DISALLOW_COPY_AND_ASSIGN(WMEvent);
diff --git a/base/bind_internal.h b/base/bind_internal.h
index c19f759..172ce53 100644
--- a/base/bind_internal.h
+++ b/base/bind_internal.h
@@ -308,7 +308,8 @@
 
 template <typename StorageType, typename R, typename... UnboundArgs>
 struct Invoker<StorageType, R(UnboundArgs...)> {
-  static R RunOnce(BindStateBase* base, UnboundArgs&&... unbound_args) {
+  static R RunOnce(BindStateBase* base,
+                   PassingTraitsType<UnboundArgs>... unbound_args) {
     // Local references to make debugger stepping easier. If in a debugger,
     // you really want to warp ahead and step through the
     // InvokeHelper<>::MakeItSo() call below.
@@ -321,7 +322,8 @@
                    std::forward<UnboundArgs>(unbound_args)...);
   }
 
-  static R Run(BindStateBase* base, UnboundArgs&&... unbound_args) {
+  static R Run(BindStateBase* base,
+               PassingTraitsType<UnboundArgs>... unbound_args) {
     // Local references to make debugger stepping easier. If in a debugger,
     // you really want to warp ahead and step through the
     // InvokeHelper<>::MakeItSo() call below.
diff --git a/base/callback.h b/base/callback.h
index 043f72d..5e230fb 100644
--- a/base/callback.h
+++ b/base/callback.h
@@ -23,7 +23,8 @@
 class OnceCallback<R(Args...)> : public internal::CallbackBase {
  public:
   using RunType = R(Args...);
-  using PolymorphicInvoke = R (*)(internal::BindStateBase*, Args&&...);
+  using PolymorphicInvoke = R (*)(internal::BindStateBase*,
+                                  internal::PassingTraitsType<Args>...);
 
   OnceCallback() : internal::CallbackBase(nullptr) {}
 
@@ -69,7 +70,8 @@
 class RepeatingCallback<R(Args...)> : public internal::CallbackBaseCopyable {
  public:
   using RunType = R(Args...);
-  using PolymorphicInvoke = R (*)(internal::BindStateBase*, Args&&...);
+  using PolymorphicInvoke = R (*)(internal::BindStateBase*,
+                                  internal::PassingTraitsType<Args>...);
 
   RepeatingCallback() : internal::CallbackBaseCopyable(nullptr) {}
 
diff --git a/base/callback_internal.h b/base/callback_internal.h
index 8ad8449..616abdd 100644
--- a/base/callback_internal.h
+++ b/base/callback_internal.h
@@ -31,6 +31,22 @@
   static void Destruct(const BindStateBase*);
 };
 
+template <typename T, bool IsScalar = std::is_scalar<T>::value>
+struct PassingTraits;
+
+template <typename T>
+struct PassingTraits<T, false> {
+  using Type = T&&;
+};
+
+template <typename T>
+struct PassingTraits<T, true> {
+  using Type = T;
+};
+
+template <typename T>
+using PassingTraitsType = typename PassingTraits<T>::Type;
+
 // BindStateBase is used to provide an opaque handle that the Callback
 // class can use to represent a function object with bound arguments.  It
 // behaves as an existential type that is used by a corresponding
diff --git a/base/third_party/dmg_fp/README.chromium b/base/third_party/dmg_fp/README.chromium
index e3270cf..13d5fb2 100644
--- a/base/third_party/dmg_fp/README.chromium
+++ b/base/third_party/dmg_fp/README.chromium
@@ -19,3 +19,4 @@
   - fixed parsing of long exponents, see exp_length.patch and crbug.com/542881
   - made hexdig array const
   - removed deprecated `register` keyword
+  - #undef Long so that it won't change Long in other files in jumbo builds
diff --git a/base/third_party/dmg_fp/dtoa_wrapper.cc b/base/third_party/dmg_fp/dtoa_wrapper.cc
index c314c59d..5141e23 100644
--- a/base/third_party/dmg_fp/dtoa_wrapper.cc
+++ b/base/third_party/dmg_fp/dtoa_wrapper.cc
@@ -44,3 +44,5 @@
 }
 
 #include "base/third_party/dmg_fp/dtoa.cc"
+
+#undef Long  // To avoid breaking jni code in jumbo builds
diff --git a/build/android/gyp/apkbuilder.py b/build/android/gyp/apkbuilder.py
index 7981b341..8afd6b0 100755
--- a/build/android/gyp/apkbuilder.py
+++ b/build/android/gyp/apkbuilder.py
@@ -172,7 +172,8 @@
 
     compress = None
     if (uncompress and os.path.splitext(basename)[1] == '.so'
-        and 'android_linker' not in basename):
+        and 'android_linker' not in basename
+        and 'clang_rt' not in basename):
       compress = False
       # Add prefix to prevent android install from extracting upon install.
       if has_crazy_linker:
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py
index 0651134..dbe0d5a4 100644
--- a/build/android/pylib/instrumentation/instrumentation_test_instance.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -9,7 +9,6 @@
 import re
 
 from devil.android import apk_helper
-from devil.android import md5sum
 from pylib import constants
 from pylib.base import base_test_result
 from pylib.base import test_exception
@@ -276,41 +275,36 @@
 def GetAllTestsFromJar(test_jar):
   pickle_path = '%s-proguard.pickle' % test_jar
   try:
-    tests = GetTestsFromPickle(pickle_path, test_jar)
+    tests = GetTestsFromPickle(pickle_path, os.path.getmtime(test_jar))
   except TestListPickleException as e:
     logging.info('Could not get tests from pickle: %s', e)
     logging.info('Getting tests from JAR via proguard.')
     tests = _GetTestsFromProguard(test_jar)
-    SaveTestsToPickle(pickle_path, test_jar, tests)
+    SaveTestsToPickle(pickle_path, tests)
   return tests
 
 
 def GetAllTestsFromApk(test_apk):
   pickle_path = '%s-dexdump.pickle' % test_apk
   try:
-    tests = GetTestsFromPickle(pickle_path, test_apk)
+    tests = GetTestsFromPickle(pickle_path, os.path.getmtime(test_apk))
   except TestListPickleException as e:
     logging.info('Could not get tests from pickle: %s', e)
     logging.info('Getting tests from dex via dexdump.')
     tests = _GetTestsFromDexdump(test_apk)
-    SaveTestsToPickle(pickle_path, test_apk, tests)
+    SaveTestsToPickle(pickle_path, tests)
   return tests
 
-def GetTestsFromPickle(pickle_path, jar_path):
+def GetTestsFromPickle(pickle_path, test_mtime):
   if not os.path.exists(pickle_path):
     raise TestListPickleException('%s does not exist.' % pickle_path)
-  if os.path.getmtime(pickle_path) <= os.path.getmtime(jar_path):
-    raise TestListPickleException(
-        '%s newer than %s.' % (jar_path, pickle_path))
+  if os.path.getmtime(pickle_path) <= test_mtime:
+    raise TestListPickleException('File is stale: %s' % pickle_path)
 
   with open(pickle_path, 'r') as f:
     pickle_data = pickle.load(f)
-  jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path]
-
   if pickle_data['VERSION'] != _PICKLE_FORMAT_VERSION:
     raise TestListPickleException('PICKLE_FORMAT_VERSION has changed.')
-  if pickle_data['JAR_MD5SUM'] != jar_md5:
-    raise TestListPickleException('JAR file MD5 sum differs.')
   return pickle_data['TEST_METHODS']
 
 
@@ -371,11 +365,9 @@
         })
   return tests
 
-def SaveTestsToPickle(pickle_path, jar_path, tests):
-  jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path]
+def SaveTestsToPickle(pickle_path, tests):
   pickle_data = {
     'VERSION': _PICKLE_FORMAT_VERSION,
-    'JAR_MD5SUM': jar_md5,
     'TEST_METHODS': tests,
   }
   with open(pickle_path, 'w') as pickle_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 63369b1e0..56c372e 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
@@ -21,6 +21,7 @@
 from devil.android.tools import system_app
 from devil.utils import reraiser_thread
 from incremental_install import installer
+from pylib import constants
 from pylib import valgrind_tools
 from pylib.base import base_test_result
 from pylib.base import output_manager
@@ -600,9 +601,20 @@
   def _GetTestsFromRunner(self):
     test_apk_path = self._test_instance.test_apk.path
     pickle_path = '%s-runner.pickle' % test_apk_path
+    # For incremental APKs, the code doesn't live in the apk, so instead check
+    # the timestamp of the target's .stamp file.
+    if self._test_instance.test_apk_incremental_install_json:
+      with open(self._test_instance.test_apk_incremental_install_json) as f:
+        data = json.load(f)
+      out_dir = constants.GetOutDirectory()
+      test_mtime = max(
+          os.path.getmtime(os.path.join(out_dir, p)) for p in data['dex_files'])
+    else:
+      test_mtime = os.path.getmtime(test_apk_path)
+
     try:
       return instrumentation_test_instance.GetTestsFromPickle(
-          pickle_path, test_apk_path)
+          pickle_path, test_mtime)
     except instrumentation_test_instance.TestListPickleException as e:
       logging.info('Could not get tests from pickle: %s', e)
     logging.info('Getting tests by having %s list them.',
@@ -645,8 +657,7 @@
     # Get the first viable list of raw tests
     raw_tests = [tl for tl in raw_test_lists if tl][0]
 
-    instrumentation_test_instance.SaveTestsToPickle(
-        pickle_path, test_apk_path, raw_tests)
+    instrumentation_test_instance.SaveTestsToPickle(pickle_path, raw_tests)
     return raw_tests
 
   def _SaveTraceData(self, trace_device_file, device, test_class):
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index b9a27fc..b8113b8 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -6,6 +6,7 @@
 # Some projects (e.g. V8) do not have non-build directories DEPS'ed in.
 import("//build/config/android/config.gni")
 import("//build/config/android/internal_rules.gni")
+import("//build/config/clang/clang.gni")
 import("//build/config/compiler/compiler.gni")
 import("//build/config/dcheck_always_on.gni")
 import("//build/toolchain/toolchain.gni")
@@ -2449,6 +2450,11 @@
         }
       }
     }
+
+    if (use_cfi_diag || is_ubsan || is_ubsan_security || is_ubsan_vptr) {
+      _extra_native_libs += [ "$clang_base_path/lib/clang/$clang_version/lib/linux/libclang_rt.ubsan_standalone-arm-android.so" ]
+    }
+
     if (defined(invoker.loadable_modules) && invoker.loadable_modules != []) {
       _extra_native_libs_even_when_incremental += invoker.loadable_modules
     }
diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni
index 258f6c86..617f023 100644
--- a/build/config/ios/rules.gni
+++ b/build/config/ios/rules.gni
@@ -1223,6 +1223,7 @@
                              "bundle_deps_filter",
                              "data_deps",
                              "enable_code_signing",
+                             "extra_substitutions",
                              "info_plist",
                              "info_plist_target",
                              "output_name",
@@ -1252,6 +1253,7 @@
                              "bundle_deps_filter",
                              "data_deps",
                              "enable_code_signing",
+                             "extra_substitutions",
                              "info_plist",
                              "info_plist_target",
                              "output_name",
diff --git a/cc/paint/oop_pixeltest.cc b/cc/paint/oop_pixeltest.cc
index bcc105d6..a47db33 100644
--- a/cc/paint/oop_pixeltest.cc
+++ b/cc/paint/oop_pixeltest.cc
@@ -54,6 +54,7 @@
         &image_factory_, base::ThreadTaskRunnerHandle::Get());
 
     ASSERT_EQ(result, gpu::ContextResult::kSuccess);
+    ASSERT_TRUE(context_->GetCapabilities().supports_oop_raster);
   }
 
   void TearDown() override { context_.reset(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
index cb0f0da3..c80da904 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
@@ -56,8 +56,7 @@
     private ViewGroup mMainView;
     private BookmarkModel mBookmarkModel;
     private BookmarkUndoController mUndoController;
-    private final ObserverList<BookmarkUIObserver> mUIObservers =
-            new ObserverList<BookmarkUIObserver>();
+    private final ObserverList<BookmarkUIObserver> mUIObservers = new ObserverList<>();
     private BasicNativePage mNativePage;
     private SelectableListLayout<BookmarkId> mSelectableListLayout;
     private RecyclerView mRecyclerView;
@@ -107,18 +106,6 @@
         }
     };
 
-    private final Runnable mModelLoadedRunnable = new Runnable() {
-        @Override
-        public void run() {
-            mAdapter.onBookmarkDelegateInitialized(BookmarkManager.this);
-            mToolbar.onBookmarkDelegateInitialized(BookmarkManager.this);
-            if (!TextUtils.isEmpty(mInitialUrl)) {
-                setState(BookmarkUIState.createStateFromUrl(mInitialUrl,
-                        mBookmarkModel));
-            }
-        }
-    };
-
     /**
      * Creates an instance of {@link BookmarkManager}. It also initializes resources,
      * bookmark models and jni bridges.
@@ -143,7 +130,7 @@
 
         @SuppressWarnings("unchecked")
         SelectableListLayout<BookmarkId> selectableList =
-                (SelectableListLayout<BookmarkId>) mMainView.findViewById(R.id.selectable_list);
+                mMainView.findViewById(R.id.selectable_list);
         mSelectableListLayout = selectableList;
         mEmptyView = mSelectableListLayout.initializeEmptyView(
                 VectorDrawableCompat.create(
@@ -169,7 +156,14 @@
         mBookmarkModel.addObserver(mBookmarkModelObserver);
         initializeToLoadingState();
         if (!sPreventLoadingForTesting) {
-            mBookmarkModel.finishLoadingBookmarkModel(mModelLoadedRunnable);
+            Runnable modelLoadedRunnable = () -> {
+                mAdapter.onBookmarkDelegateInitialized(BookmarkManager.this);
+                mToolbar.onBookmarkDelegateInitialized(BookmarkManager.this);
+                if (!TextUtils.isEmpty(mInitialUrl)) {
+                    setState(BookmarkUIState.createStateFromUrl(mInitialUrl, mBookmarkModel));
+                }
+            };
+            mBookmarkModel.finishLoadingBookmarkModel(modelLoadedRunnable);
         }
 
         mLargeIconBridge = new LargeIconBridge(Profile.getLastUsedProfile().getOriginalProfile());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
index 5d6783e..efe6989 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
@@ -18,8 +18,6 @@
  * the UI to acquire data from the backend.
  */
 public class BookmarkModel extends BookmarkBridge {
-    private static final int FAVICON_MAX_CACHE_SIZE = 10 * 1024 * 1024; // 10MB
-
     /**
      * Observer that listens to delete event. This interface is used by undo controllers to know
      * which bookmarks were deleted. Note this observer only listens to events that go through
@@ -66,7 +64,7 @@
      * Add an observer that listens to delete events that go through the bookmark model.
      * @param observer The observer to add.
      */
-    public void addDeleteObserver(BookmarkDeleteObserver observer) {
+    void addDeleteObserver(BookmarkDeleteObserver observer) {
         mDeleteObservers.addObserver(observer);
     }
 
@@ -74,7 +72,7 @@
      * Remove the observer from listening to bookmark deleting events.
      * @param observer The observer to remove.
      */
-    public void removeDeleteObserver(BookmarkDeleteObserver observer) {
+    void removeDeleteObserver(BookmarkDeleteObserver observer) {
         mDeleteObservers.removeObserver(observer);
     }
 
@@ -86,7 +84,7 @@
      *                  children, because deleting folder will also remove all its children, and
      *                  deleting children once more will cause errors.
      */
-    public void deleteBookmarks(BookmarkId... bookmarks) {
+    void deleteBookmarks(BookmarkId... bookmarks) {
         assert bookmarks != null && bookmarks.length > 0;
         // Store all titles of bookmarks.
         String[] titles = new String[bookmarks.length];
@@ -115,17 +113,17 @@
      * Calls {@link BookmarkBridge#moveBookmark(BookmarkId, BookmarkId, int)} for the given
      * bookmark list. The bookmarks are appended at the end.
      */
-    public void moveBookmarks(List<BookmarkId> bookmarkIds, BookmarkId newParentId) {
-        int appenedIndex = getChildCount(newParentId);
+    void moveBookmarks(List<BookmarkId> bookmarkIds, BookmarkId newParentId) {
+        int appendIndex = getChildCount(newParentId);
         for (int i = 0; i < bookmarkIds.size(); ++i) {
-            moveBookmark(bookmarkIds.get(i), newParentId, appenedIndex + i);
+            moveBookmark(bookmarkIds.get(i), newParentId, appendIndex + i);
         }
     }
 
     /**
      * @see org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem#getTitle()
      */
-    public String getBookmarkTitle(BookmarkId bookmarkId) {
+    String getBookmarkTitle(BookmarkId bookmarkId) {
         return getBookmarkById(bookmarkId).getTitle();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics.java
index 7ad772e..09c5423 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics.java
@@ -50,6 +50,9 @@
     // Time when the panel was opened beyond peeked. Reset when the panel is closed.
     // Used to log how long the panel was open.
     private long mPanelOpenedBeyondPeekTimeNs;
+    // Duration that the panel was opened beyond peeked. Reset when the panel is closed.
+    // Used to log how long the panel was open.
+    private long mPanelOpenedBeyondPeekDurationMs;
     // The current set of heuristics that should be logged with results seen when the panel closes.
     private ContextualSearchHeuristics mResultsSeenExperiments;
     // The current set of heuristics to be logged through ranker with results seen when the panel
@@ -89,12 +92,23 @@
                     durationMs, mWasSearchContentViewSeen);
         }
 
+        if (isExitingPanelOpenedBeyondPeeked) {
+            assert mPanelOpenedBeyondPeekTimeNs != 0;
+            mPanelOpenedBeyondPeekDurationMs = (System.nanoTime() - mPanelOpenedBeyondPeekTimeNs)
+                    / MILLISECONDS_TO_NANOSECONDS;
+            ContextualSearchUma.logPanelOpenDuration(mPanelOpenedBeyondPeekDurationMs);
+            mPanelOpenedBeyondPeekTimeNs = 0;
+            mWasPanelOpenedBeyondPeek = false;
+        }
+
         if (isEndingSearch) {
-            long durationMs = (System.nanoTime() - mFirstPeekTimeNs) / MILLISECONDS_TO_NANOSECONDS;
-            ContextualSearchUma.logPanelViewDurationAction(durationMs);
+            long panelViewDurationMs =
+                    (System.nanoTime() - mFirstPeekTimeNs) / MILLISECONDS_TO_NANOSECONDS;
+            ContextualSearchUma.logPanelViewDurationAction(panelViewDurationMs);
             if (!mDidSearchInvolvePromo) {
                 // Measure duration only when the promo is not involved.
-                ContextualSearchUma.logDuration(mWasSearchContentViewSeen, isChained, durationMs);
+                ContextualSearchUma.logDuration(
+                        mWasSearchContentViewSeen, isChained, panelViewDurationMs);
             }
             if (mIsPromoActive) {
                 // The user is exiting still in the promo, without choosing an option.
@@ -126,11 +140,14 @@
             if (mResultsSeenExperiments != null) {
                 mResultsSeenExperiments.logResultsSeen(
                         mWasSearchContentViewSeen, mWasActivatedByTap);
+                mResultsSeenExperiments.logPanelViewedDurations(
+                        panelViewDurationMs, mPanelOpenedBeyondPeekDurationMs);
                 if (mRankerLogger != null) {
                     mResultsSeenExperiments.logRankerTapSuppressionOutcome(mRankerLogger);
                 }
                 mResultsSeenExperiments = null;
             }
+            mPanelOpenedBeyondPeekDurationMs = 0;
 
             if (mWasActivatedByTap) {
                 boolean wasAnySuppressionHeuristicSatisfied = mWasAnyHeuristicSatisfiedOnPanelShow;
@@ -158,15 +175,6 @@
                     mWasActivatedByTap, mWasContextualCardsDataShown);
         }
 
-        if (isExitingPanelOpenedBeyondPeeked) {
-            assert mPanelOpenedBeyondPeekTimeNs != 0;
-            long durationPanelOpen = (System.nanoTime() - mPanelOpenedBeyondPeekTimeNs)
-                    / MILLISECONDS_TO_NANOSECONDS;
-            ContextualSearchUma.logPanelOpenDuration(durationPanelOpen);
-            mPanelOpenedBeyondPeekTimeNs = 0;
-            mWasPanelOpenedBeyondPeek = false;
-        }
-
         if (isStartingSearch) {
             mFirstPeekTimeNs = System.nanoTime();
             mWasActivatedByTap = reason == StateChangeReason.TEXT_SELECT_TAP;
@@ -250,6 +258,7 @@
         mWasSearchContentViewSeen = true;
         mWasPanelOpenedBeyondPeek = true;
         mPanelOpenedBeyondPeekTimeNs = System.nanoTime();
+        mPanelOpenedBeyondPeekDurationMs = 0;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
index 588025d59..3ef18f27 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
@@ -41,12 +41,12 @@
      * @param resourceManager Manager to get view and image resources.
      * @param panel The OverlayPanel to render.
      * @param searchBarControl The Search Bar control.
-     * @param peekPromoControl The peeking promotion for Contextual Search.
+     * @param barBannerControl The promotion for Contextual Search.
      * @param imageControl The object controlling the image displayed in the Bar.
      */
     public void update(ResourceManager resourceManager, ContextualSearchPanel panel,
             ContextualSearchBarControl searchBarControl,
-            ContextualSearchBarBannerControl peekPromoControl,
+            ContextualSearchBarBannerControl barBannerControl,
             ContextualSearchPromoControl promoControl, ContextualSearchImageControl imageControl) {
         // Don't try to update the layer if not initialized or showing.
         if (resourceManager == null || !panel.isShowing()) return;
@@ -66,13 +66,13 @@
         float searchPromoHeightPx = promoControl.getHeightPx();
         float searchPromoOpacity = promoControl.getOpacity();
 
-        int searchPeekPromoTextViewId = peekPromoControl.getViewId();
-        boolean searchPeekPromoVisible = peekPromoControl.isVisible();
-        float searchPeekPromoHeightPx = peekPromoControl.getHeightPx();
-        float searchPeekPromoPaddingPx =  peekPromoControl.getPaddingPx();
-        float searchPeekPromoRippleWidthPx = peekPromoControl.getRippleWidthPx();
-        float searchPeekPromoRippleOpacity = peekPromoControl.getRippleOpacity();
-        float searchPeekPromoTextOpacity = peekPromoControl.getTextOpacity();
+        int searchBarBannerTextViewId = barBannerControl.getViewId();
+        boolean searchBarBannerVisible = barBannerControl.isVisible();
+        float searchBarBannerHeightPx = barBannerControl.getHeightPx();
+        float searchBarBannerPaddingPx = barBannerControl.getPaddingPx();
+        float searchBarBannerRippleWidthPx = barBannerControl.getRippleWidthPx();
+        float searchBarBannerRippleOpacity = barBannerControl.getRippleOpacity();
+        float searchBarBannerTextOpacity = barBannerControl.getTextOpacity();
 
         float customImageVisibilityPercentage = imageControl.getCustomImageVisibilityPercentage();
         int barImageSize = imageControl.getBarImageSize();
@@ -134,11 +134,11 @@
                 R.drawable.breadcrumb_arrow, ContextualSearchPanel.CLOSE_ICON_DRAWABLE_ID,
                 R.drawable.progress_bar_background, R.drawable.progress_bar_foreground,
                 searchPromoViewId, R.drawable.contextual_search_promo_ripple,
-                searchPeekPromoTextViewId, mDpToPx, panel.getBasePageBrightness(),
+                searchBarBannerTextViewId, mDpToPx, panel.getBasePageBrightness(),
                 panel.getBasePageY() * mDpToPx, panelWebContents, searchPromoVisible,
-                searchPromoHeightPx, searchPromoOpacity, searchPeekPromoVisible,
-                searchPeekPromoHeightPx, searchPeekPromoPaddingPx, searchPeekPromoRippleWidthPx,
-                searchPeekPromoRippleOpacity, searchPeekPromoTextOpacity, searchPanelX * mDpToPx,
+                searchPromoHeightPx, searchPromoOpacity, searchBarBannerVisible,
+                searchBarBannerHeightPx, searchBarBannerPaddingPx, searchBarBannerRippleWidthPx,
+                searchBarBannerRippleOpacity, searchBarBannerTextOpacity, searchPanelX * mDpToPx,
                 searchPanelY * mDpToPx, searchPanelWidth * mDpToPx, searchPanelHeight * mDpToPx,
                 searchBarMarginSide * mDpToPx, searchBarHeight * mDpToPx, searchContextOpacity,
                 searchBarControl.getTextLayerMinHeight(), searchTermOpacity,
@@ -203,12 +203,12 @@
             int searchTermResourceId, int searchCaptionResourceId, int searchBarShadowResourceId,
             int searchProviderIconResourceId, int quickActionIconResourceId, int arrowUpResourceId,
             int closeIconResourceId, int progressBarBackgroundResourceId, int progressBarResourceId,
-            int searchPromoResourceId, int peekPromoRippleResourceId, int peekPromoTextResourceId,
+            int searchPromoResourceId, int barBannerRippleResourceId, int barBannerTextResourceId,
             float dpToPx, float basePageBrightness, float basePageYOffset, WebContents webContents,
             boolean searchPromoVisible, float searchPromoHeight, float searchPromoOpacity,
-            boolean searchPeekPromoVisible, float searchPeekPromoHeight,
-            float searchPeekPromoPaddingPx, float searchPeekPromoRippleWidth,
-            float searchPeekPromoRippleOpacity, float searchPeekPromoTextOpacity,
+            boolean searchBarBannerVisible, float searchBarBannerHeight,
+            float searchBarBannerPaddingPx, float searchBarBannerRippleWidth,
+            float searchBarBannerRippleOpacity, float searchBarBannerTextOpacity,
             float searchPanelX, float searchPanelY, float searchPanelWidth, float searchPanelHeight,
             float searchBarMarginSide, float searchBarHeight, float searchContextOpacity,
             float searchTextLayerMinHeight, float searchTermOpacity, float searchTermCaptionSpacing,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/BarOverlapTapSuppression.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/BarOverlapTapSuppression.java
index a07d88da..d78e306 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/BarOverlapTapSuppression.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/BarOverlapTapSuppression.java
@@ -55,6 +55,16 @@
     }
 
     @Override
+    protected void logPanelViewedDurations(long panelViewDurationMs, long panelOpenDurationMs) {
+        if (panelOpenDurationMs > 0) {
+            long panelPeekedDuration = panelViewDurationMs - panelOpenDurationMs;
+            assert panelPeekedDuration >= 0;
+            ContextualSearchUma.logBarOverlapPeekDuration(
+                    mIsConditionSatisfied, panelPeekedDuration);
+        }
+    }
+
+    @Override
     protected boolean shouldAggregateLogForTapSuppression() {
         return true;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
index 41f2da98..0da9154 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
@@ -25,12 +25,6 @@
     static final String MANDATORY_PROMO_LIMIT = "mandatory_promo_limit";
     static final int MANDATORY_PROMO_DEFAULT_LIMIT = 10;
 
-    private static final String PEEK_PROMO_FORCED = "peek_promo_forced";
-    @VisibleForTesting
-    static final String PEEK_PROMO_ENABLED = "peek_promo_enabled";
-    private static final String PEEK_PROMO_MAX_SHOW_COUNT = "peek_promo_max_show_count";
-    private static final int PEEK_PROMO_DEFAULT_MAX_SHOW_COUNT = 10;
-
     private static final String DISABLE_SEARCH_TERM_RESOLUTION = "disable_search_term_resolution";
     private static final String WAIT_AFTER_TAP_DELAY_MS = "wait_after_tap_delay_ms";
 
@@ -99,8 +93,6 @@
     private static Boolean sDisableSearchTermResolution;
     private static Boolean sIsMandatoryPromoEnabled;
     private static Integer sMandatoryPromoLimit;
-    private static Boolean sIsPeekPromoEnabled;
-    private static Integer sPeekPromoMaxCount;
     private static Boolean sIsTranslationDisabled;
     private static Boolean sIsEnglishTargetTranslationEnabled;
     private static Integer sScreenTopSuppressionDps;
@@ -202,35 +194,6 @@
     }
 
     /**
-     * @return Whether the Peek Promo is forcibly enabled (used for testing).
-     */
-    static boolean isPeekPromoForced() {
-        return CommandLine.getInstance().hasSwitch(PEEK_PROMO_FORCED);
-    }
-
-    /**
-     * @return Whether the Peek Promo is enabled.
-     */
-    static boolean isPeekPromoEnabled() {
-        if (sIsPeekPromoEnabled == null) {
-            sIsPeekPromoEnabled = getBooleanParam(PEEK_PROMO_ENABLED);
-        }
-        return sIsPeekPromoEnabled.booleanValue();
-    }
-
-    /**
-     * @return The maximum number of times the Peek Promo should be displayed.
-     */
-    static int getPeekPromoMaxShowCount() {
-        if (sPeekPromoMaxCount == null) {
-            sPeekPromoMaxCount = getIntParamValueOrDefault(
-                    PEEK_PROMO_MAX_SHOW_COUNT,
-                    PEEK_PROMO_DEFAULT_MAX_SHOW_COUNT);
-        }
-        return sPeekPromoMaxCount.intValue();
-    }
-
-    /**
      * @return Whether all translate code is disabled.
      */
     static boolean isTranslationDisabled() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchHeuristic.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchHeuristic.java
index 1d5bdcb..16473a56 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchHeuristic.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchHeuristic.java
@@ -36,6 +36,17 @@
     protected void logResultsSeen(boolean wasSearchContentViewSeen, boolean wasActivatedByTap) {}
 
     /**
+     * Optionally logs data about the duration the panel was viewed and /or opened.
+     * Default is to not log anything.
+     * @param panelViewDurationMs The duration that the panel was viewed (Peek and opened) by the
+     *        user.  This should always be a positive number, since this method is only called when
+     *        the panel has been viewed (Peeked).
+     * @param panelOpenDurationMs The duration that the panel was opened, or 0 if it was never
+     *        opened.
+     */
+    protected void logPanelViewedDurations(long panelViewDurationMs, long panelOpenDurationMs) {}
+
+    /**
      * @return Whether this heuristic should be considered when logging aggregate metrics for Tap
      *         suppression.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchHeuristics.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchHeuristics.java
index 9bc63f3..057685b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchHeuristics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchHeuristics.java
@@ -32,6 +32,21 @@
     }
 
     /**
+     * Optionally logs data about the duration the panel was viewed and /or opened.
+     * Default is to not log anything.
+     * @param panelViewDurationMs The duration that the panel was viewed (Peek and opened) by the
+     *        user.  This should always be a positive number, since this method is only called when
+     *        the panel has been viewed (Peeked).
+     * @param panelOpenDurationMs The duration that the panel was opened, or 0 if it was never
+     *        opened.
+     */
+    public void logPanelViewedDurations(long panelViewDurationMs, long panelOpenDurationMs) {
+        for (ContextualSearchHeuristic heuristic : mHeuristics) {
+            heuristic.logPanelViewedDurations(panelViewDurationMs, panelOpenDurationMs);
+        }
+    }
+
+    /**
      * Logs the condition state for all the Tap suppression heuristics.
      */
     public void logContitionState() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
index 4a157e4..1405209 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
@@ -181,66 +181,6 @@
     }
 
     /**
-     * @return Whether the Peek promo is available to be shown above the Search Bar.
-     */
-    public boolean isPeekPromoAvailable() {
-        // Allow Promo to be forcefully enabled for testing.
-        if (ContextualSearchFieldTrial.isPeekPromoForced()) return true;
-
-        // Enabled by Finch.
-        if (!ContextualSearchFieldTrial.isPeekPromoEnabled()) return false;
-
-        return isPeekPromoConditionSatisfied();
-    }
-
-    /**
-     * @return Whether the condition to show the Peek promo is satisfied.
-     */
-    public boolean isPeekPromoConditionSatisfied() {
-        // Check for several conditions to determine whether the Peek Promo can be shown.
-
-        // 1) If the Panel was never opened.
-        if (getPromoOpenCount() > 0) return false;
-
-        // 2) User has not opted in.
-        if (!isUserUndecided()) return false;
-
-        // 3) Selection was caused by a long press.
-        if (mSelectionController.getSelectionType() != SelectionType.LONG_PRESS) return false;
-
-        // 4) Promo was not shown more than the maximum number of times defined by Finch.
-        final int maxShowCount = ContextualSearchFieldTrial.getPeekPromoMaxShowCount();
-        final int peekPromoShowCount = mPreferenceManager.getContextualSearchPeekPromoShowCount();
-        if (peekPromoShowCount >= maxShowCount) return false;
-
-        // 5) Only then, show the promo.
-        return true;
-    }
-
-    /**
-     * Register that the Peek Promo was seen.
-     */
-    public void registerPeekPromoSeen() {
-        final int peekPromoShowCount = mPreferenceManager.getContextualSearchPeekPromoShowCount();
-        mPreferenceManager.setContextualSearchPeekPromoShowCount(peekPromoShowCount + 1);
-    }
-
-    /**
-     * Logs metrics related to the Peek Promo.
-     * @param wasPromoSeen Whether the Peek Promo was seen.
-     * @param wouldHaveShownPromo Whether the Promo would have shown.
-     */
-    public void logPeekPromoMetrics(boolean wasPromoSeen, boolean wouldHaveShownPromo) {
-        final boolean hasOpenedPanel = getPromoOpenCount() > 0;
-        ContextualSearchUma.logPeekPromoOutcome(wasPromoSeen, wouldHaveShownPromo, hasOpenedPanel);
-
-        if (wasPromoSeen) {
-            final int showCount = mPreferenceManager.getContextualSearchPeekPromoShowCount();
-            ContextualSearchUma.logPeekPromoShowCount(showCount, hasOpenedPanel);
-        }
-    }
-
-    /**
      * Registers that a tap has taken place by incrementing tap-tracking counters.
      */
     void registerTap() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
index ba3f4cf..9bea0ad 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
@@ -153,13 +153,6 @@
     private static final int RESULTS_NOT_SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED = 3;
     private static final int RESULTS_SEEN_SUPPRESSION_BOUNDARY = 4;
 
-    // Constants used to log UMA "enum" histograms with details about the Peek Promo Outcome.
-    private static final int PEEK_PROMO_OUTCOME_SEEN_OPENED = 0;
-    private static final int PEEK_PROMO_OUTCOME_SEEN_NOT_OPENED = 1;
-    private static final int PEEK_PROMO_OUTCOME_NOT_SEEN_OPENED = 2;
-    private static final int PEEK_PROMO_OUTCOME_NOT_SEEN_NOT_OPENED = 3;
-    private static final int PEEK_PROMO_OUTCOME_BOUNDARY = 4;
-
     // Constants used to log UMA "enum" histograms with details about whether search results
     // were seen, and what the original triggering gesture was.
     private static final int PROMO_ENABLED_FROM_TAP = 0;
@@ -560,42 +553,6 @@
     }
 
     /**
-     * Logs the number of times the Peek Promo was seen.
-     * @param count Number of times the Peek Promo was seen.
-     * @param hasOpenedPanel Whether the Panel was opened.
-     */
-    public static void logPeekPromoShowCount(int count, boolean hasOpenedPanel) {
-        RecordHistogram.recordCountHistogram("Search.ContextualSearchPeekPromoCount", count);
-        if (hasOpenedPanel) {
-            RecordHistogram.recordCountHistogram(
-                    "Search.ContextualSearchPeekPromoCountUntilOpened", count);
-        }
-    }
-
-    /**
-     * Logs the Peek Promo Outcome.
-     * @param wasPromoSeen Whether the Peek Promo was seen.
-     * @param wouldHaveShownPromo Whether the Promo would have shown.
-     * @param hasOpenedPanel Whether the Panel was opened.
-     */
-    public static void logPeekPromoOutcome(boolean wasPromoSeen, boolean wouldHaveShownPromo,
-            boolean hasOpenedPanel) {
-        int outcome = -1;
-        if (wasPromoSeen) {
-            outcome = hasOpenedPanel
-                    ? PEEK_PROMO_OUTCOME_SEEN_OPENED : PEEK_PROMO_OUTCOME_SEEN_NOT_OPENED;
-        } else if (wouldHaveShownPromo) {
-            outcome = hasOpenedPanel
-                    ? PEEK_PROMO_OUTCOME_NOT_SEEN_OPENED : PEEK_PROMO_OUTCOME_NOT_SEEN_NOT_OPENED;
-        }
-
-        if (outcome != -1) {
-            RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchPeekPromoOutcome",
-                    outcome, PEEK_PROMO_OUTCOME_BOUNDARY);
-        }
-    }
-
-    /**
      * Logs the outcome of the Promo.
      * Logs multiple histograms; with and without the originating gesture.
      * @param wasTap Whether the gesture that originally caused the panel to show was a Tap.
@@ -739,6 +696,8 @@
 
     /**
      * Logs the whether the panel was seen and the type of the trigger and if Bar nearly overlapped.
+     * If the panel was seen, logs the duration of the panel view into a BarOverlap or BarNoOverlap
+     * duration histogram.
      * @param wasPanelSeen Whether the panel was seen.
      * @param wasTap Whether the gesture was a Tap or not.
      * @param wasBarOverlap Whether the trigger location overlapped the Bar area.
@@ -751,6 +710,19 @@
     }
 
     /**
+     * Logs the duration of the panel viewed in its Peeked state before being opened.
+     * @param wasBarOverlap Whether the trigger location overlapped the Bar area.
+     * @param panelPeekDurationMs The duration that the panel was peeking before being opened
+     *        by the user.
+     */
+    public static void logBarOverlapPeekDuration(boolean wasBarOverlap, long panelPeekDurationMs) {
+        String histogram = wasBarOverlap ? "Search.ContextualSearchBarOverlap.DurationSeen"
+                                         : "Search.ContextualSearchBarNoOverlap.DurationSeen";
+        RecordHistogram.recordMediumTimesHistogram(
+                histogram, panelPeekDurationMs, TimeUnit.MILLISECONDS);
+    }
+
+    /**
      * Log whether the UX was suppressed due to Bar overlap.
      * @param wasSuppressed Whether showing the UX was suppressed.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java
index b0eef1115..f6ee92e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java
@@ -50,12 +50,6 @@
         }
     }
 
-    /**
-     * Logs the results seen for the heuristics and whether they would have had their condition
-     * satisfied if enabled.
-     * @param wasSearchContentViewSeen Whether the panel contents were seen.
-     * @param wasActivatedByTap Whether the panel was activated by a Tap or not.
-     */
     @Override
     public void logResultsSeen(boolean wasSearchContentViewSeen, boolean wasActivatedByTap) {
         for (ContextualSearchHeuristic heuristic : mHeuristics) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
index ffb34c95..eac4bf6c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
@@ -16,8 +16,10 @@
 import org.chromium.chrome.browser.download.DownloadNotificationService.Observer;
 import org.chromium.components.offline_items_collection.ContentId;
 
-import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
 import java.util.Set;
 
 import javax.annotation.Nullable;
@@ -43,8 +45,7 @@
     @Nullable
     private DownloadNotificationService mBoundService;
     private Set<String> mActiveDownloads = new HashSet<String>();
-    private ArrayList<PendingNotificationInfo> mPendingNotifications =
-            new ArrayList<PendingNotificationInfo>();
+    private HashMap<ContentId, PendingNotificationInfo> mPendingNotifications = new HashMap<>();
 
     private boolean mIsServiceBound;
 
@@ -116,9 +117,13 @@
     @VisibleForTesting
     void handlePendingNotifications() {
         if (mPendingNotifications.isEmpty()) return;
-        for (int i = 0; i < mPendingNotifications.size(); i++) {
-            updateDownloadNotification(
-                    mPendingNotifications.get(i), i == mPendingNotifications.size() - 1);
+        Iterator<Map.Entry<ContentId, PendingNotificationInfo>> iter =
+                mPendingNotifications.entrySet().iterator();
+        while (iter.hasNext()) {
+            // Get the next PendingNotification, set autoRelease to be true for the last element.
+            PendingNotificationInfo nextPendingNotification = iter.next().getValue();
+            boolean autoRelease = !iter.hasNext();
+            updateDownloadNotification(nextPendingNotification, autoRelease);
         }
         mPendingNotifications.clear();
     }
@@ -256,7 +261,8 @@
         startAndBindToServiceIfNeeded();
 
         if (mBoundService == null) {
-            mPendingNotifications.add(notificationInfo);
+            mPendingNotifications.put(
+                    notificationInfo.downloadInfo.getContentId(), notificationInfo);
             return;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
index af2b1c71..5d7d3b7f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
@@ -337,7 +337,7 @@
         @Override
         public void onBindViewHolder() {
             super.onBindViewHolder();
-            updatePersonalizedSigninPromo();
+            bindPersonalizedSigninPromo();
         }
 
         @Override
@@ -363,6 +363,11 @@
         }
 
         private void updatePersonalizedSigninPromo() {
+            mSigninPromoController.detach();
+            bindPersonalizedSigninPromo();
+        }
+
+        private void bindPersonalizedSigninPromo() {
             DisplayableProfileData profileData = null;
             Account[] accounts = AccountManagerFacade.get().tryGetGoogleAccounts();
             if (accounts.length > 0) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
index c36338f..24fb186 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
@@ -35,8 +35,6 @@
     private static final String CONTEXTUAL_SEARCH_TAP_TRIGGERED_PROMO_COUNT =
             "contextual_search_tap_triggered_promo_count";
     private static final String CONTEXTUAL_SEARCH_TAP_COUNT = "contextual_search_tap_count";
-    private static final String CONTEXTUAL_SEARCH_PEEK_PROMO_SHOW_COUNT =
-            "contextual_search_peek_promo_show_count";
     private static final String CONTEXTUAL_SEARCH_LAST_ANIMATION_TIME =
             "contextual_search_last_animation_time";
     private static final String CONTEXTUAL_SEARCH_TAP_QUICK_ANSWER_COUNT =
@@ -228,21 +226,6 @@
     }
 
     /**
-     * @return Number of times the Peek Promo was shown.
-     */
-    public int getContextualSearchPeekPromoShowCount() {
-        return mSharedPreferences.getInt(CONTEXTUAL_SEARCH_PEEK_PROMO_SHOW_COUNT, 0);
-    }
-
-    /**
-     * Sets the number of times the Peek Promo was shown.
-     * @param count Number of times the Peek Promo was shown.
-     */
-    public void setContextualSearchPeekPromoShowCount(int count) {
-        writeInt(CONTEXTUAL_SEARCH_PEEK_PROMO_SHOW_COUNT, count);
-    }
-
-    /**
      * @return The last time the search provider icon was animated on tap.
      */
     public long getContextualSearchLastAnimationTime() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
index 3580c07..8ff1dff 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
@@ -323,7 +323,11 @@
             accountNames = result.get();
         } catch (GmsAvailabilityException e) {
             dismissGmsUpdatingDialog();
-            showGmsErrorDialog(e.getGmsAvailabilityReturnCode());
+            if (e.isUserResolvableError()) {
+                showGmsErrorDialog(e.getGmsAvailabilityReturnCode());
+            } else {
+                Log.e(TAG, "Unresolvable GmsAvailabilityException.", e);
+            }
             return;
         } catch (GmsJustUpdatedException e) {
             dismissGmsErrorDialog();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
index fe0d5cf2..c17e13d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -212,6 +212,8 @@
      */
     public static void finalizePendingFeatures() {
         if (sChromeHomeNeedsUpdate) {
+            // Clear the Chrome Home flag so that it can be re-cached below.
+            sChromeHomeEnabled = null;
             // Re-cache the Chrome Home state.
             cacheChromeHomeEnabled();
             notifyChromeHomeStatusChanged(isChromeHomeEnabled());
@@ -272,10 +274,6 @@
         // Chrome Home doesn't work with tablets.
         if (DeviceFormFactor.isTablet()) return;
 
-        // Any time this method is called, clear the cached Chrome Home state so it can be set in
-        // isChromeHomeEnabled below.
-        sChromeHomeEnabled = null;
-
         boolean isChromeHomeEnabled = ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_HOME);
         ChromePreferenceManager manager = ChromePreferenceManager.getInstance();
         manager.setChromeHomeEnabled(isChromeHomeEnabled);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
index 86bd64f..46c3f2b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
@@ -360,6 +360,9 @@
         ViewGroup snackbarContainer =
                 (ViewGroup) mActivity.findViewById(R.id.bottom_sheet_snackbar_container);
         ((MarginLayoutParams) snackbarContainer.getLayoutParams()).bottomMargin = mBottomNavHeight;
+
+        setMenuBackgroundColor(
+                mTabModelSelector != null ? mTabModelSelector.isIncognitoSelected() : false);
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java
index df366e4d..f0d3fe2c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java
@@ -32,7 +32,6 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisableIf;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
@@ -101,7 +100,6 @@
 
     @Test
     @MediumTest
-    @DisabledTest(message = "crbug.com/782409")
     public void testSigninButtonDefaultAccount() throws Exception {
         addTestAccount();
         openBookmarkManager();
@@ -123,7 +121,6 @@
 
     @Test
     @MediumTest
-    @DisabledTest(message = "crbug.com/782409")
     public void testSigninButtonNotDefaultAccount() throws Exception {
         addTestAccount();
         openBookmarkManager();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
index fc02a1ed..eec89281 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.bookmarks;
 
-import android.app.Activity;
 import android.support.annotation.Nullable;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
@@ -25,7 +24,6 @@
 
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
-import org.chromium.base.ApplicationStatus.ActivityStateListener;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
@@ -83,7 +81,7 @@
 
     private BookmarkManager mManager;
     private BookmarkModel mBookmarkModel;
-    protected RecyclerView mItemsContainer;
+    private RecyclerView mItemsContainer;
     private String mTestPage;
     private String mTestPageFoo;
     private EmbeddedTestServer mTestServer;
@@ -106,12 +104,8 @@
 
     private void readPartnerBookmarks() throws InterruptedException {
         // Do not read partner bookmarks in setUp(), so that the lazy reading is covered.
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                PartnerBookmarksShim.kickOffReading(mActivityTestRule.getActivity());
-            }
-        });
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> PartnerBookmarksShim.kickOffReading(mActivityTestRule.getActivity()));
         BookmarkTestUtil.waitForBookmarkModelLoaded();
     }
 
@@ -194,13 +188,8 @@
         Assert.assertTrue("Grid view does not contain added bookmark: ",
                 isItemPresentInBookmarkList(TEST_PAGE_TITLE_GOOGLE));
         final View tile = getViewWithText(mItemsContainer, TEST_PAGE_TITLE_GOOGLE);
-        ChromeTabUtils.waitForTabPageLoaded(
-                mActivityTestRule.getActivity().getActivityTab(), new Runnable() {
-                    @Override
-                    public void run() {
-                        TouchCommon.singleClickView(tile);
-                    }
-                });
+        ChromeTabUtils.waitForTabPageLoaded(mActivityTestRule.getActivity().getActivityTab(),
+                () -> TouchCommon.singleClickView(tile));
         Assert.assertEquals(TEST_PAGE_TITLE_GOOGLE,
                 mActivityTestRule.getActivity().getActivityTab().getTitle());
     }
@@ -244,7 +233,7 @@
 
         // Open the "Mobile bookmarks" folder.
         ThreadUtils.runOnUiThreadBlocking(
-                () -> { delegate.openFolder(mBookmarkModel.getMobileFolderId()); });
+                () -> delegate.openFolder(mBookmarkModel.getMobileFolderId()));
 
         // Check that we are in the mobile bookmarks folder.
         Assert.assertEquals("Mobile bookmarks", toolbar.getTitle());
@@ -253,7 +242,7 @@
         Assert.assertFalse(toolbar.getMenu().findItem(R.id.edit_menu_id).isVisible());
 
         // Open the new test folder.
-        ThreadUtils.runOnUiThreadBlocking(() -> { delegate.openFolder(testFolder); });
+        ThreadUtils.runOnUiThreadBlocking(() -> delegate.openFolder(testFolder));
 
         // Check that we are in the editable test folder.
         Assert.assertEquals(TEST_FOLDER_TITLE, toolbar.getTitle());
@@ -262,7 +251,7 @@
         Assert.assertTrue(toolbar.getMenu().findItem(R.id.edit_menu_id).isVisible());
 
         // Call BookmarkActionBar#onClick() to activate the navigation button.
-        ThreadUtils.runOnUiThreadBlocking(() -> { toolbar.onClick(toolbar); });
+        ThreadUtils.runOnUiThreadBlocking(() -> toolbar.onClick(toolbar));
 
         // Check that we are back in the mobile folder
         Assert.assertEquals("Mobile bookmarks", toolbar.getTitle());
@@ -271,7 +260,7 @@
         Assert.assertFalse(toolbar.getMenu().findItem(R.id.edit_menu_id).isVisible());
 
         // Call BookmarkActionBar#onClick() to activate the navigation button.
-        ThreadUtils.runOnUiThreadBlocking(() -> { toolbar.onClick(toolbar); });
+        ThreadUtils.runOnUiThreadBlocking(() -> toolbar.onClick(toolbar));
 
         // Check that we are in the root folder.
         Assert.assertEquals("Bookmarks", toolbar.getTitle());
@@ -298,12 +287,7 @@
         Assert.assertEquals(BookmarkUIState.STATE_FOLDER, delegate.getCurrentState());
         assertBookmarkItems("Wrong number of items before starting search.", 3, adapter, delegate);
 
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                delegate.openSearchUI();
-            }
-        });
+        ThreadUtils.runOnUiThreadBlocking(delegate::openSearchUI);
 
         Assert.assertEquals(BookmarkUIState.STATE_SEARCHING, delegate.getCurrentState());
         assertBookmarkItems(
@@ -326,12 +310,8 @@
         assertBookmarkItems("Wrong number of items after searching for non-existent item.", 0,
                 mItemsContainer.getAdapter(), delegate);
 
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                ((BookmarkManager) delegate).getToolbarForTests().hideSearchView();
-            }
-        });
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> ((BookmarkManager) delegate).getToolbarForTests().hideSearchView());
         assertBookmarkItems("Wrong number of items after closing search UI.", 3,
                 mItemsContainer.getAdapter(), delegate);
         Assert.assertEquals(BookmarkUIState.STATE_FOLDER, delegate.getCurrentState());
@@ -359,9 +339,8 @@
 
         mRenderTestRule.render(manager.getView(), "bookmark_manager_folder_selected");
 
-        ThreadUtils.runOnUiThreadBlocking(() -> {
-            manager.getSelectionDelegate().toggleSelectionForItem(adapter.getItem(0));
-        });
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> manager.getSelectionDelegate().toggleSelectionForItem(adapter.getItem(0)));
 
         mRenderTestRule.render(manager.getView(), "bookmark_manager_one_folder");
     }
@@ -375,17 +354,14 @@
         openBookmarkManager();
 
         CallbackHelper activityDestroyedCallback = new CallbackHelper();
-        ApplicationStatus.registerStateListenerForActivity(new ActivityStateListener() {
-            @Override
-            public void onActivityStateChange(Activity activity, int newState) {
-                if (newState == ActivityState.DESTROYED) activityDestroyedCallback.notifyCalled();
-            }
+        ApplicationStatus.registerStateListenerForActivity((activity, newState) -> {
+            if (newState == ActivityState.DESTROYED) activityDestroyedCallback.notifyCalled();
         }, mBookmarkActivity);
 
         final BookmarkActionBar toolbar = mManager.getToolbarForTests();
 
         ThreadUtils.runOnUiThreadBlocking(
-                () -> { toolbar.onMenuItemClick(toolbar.getMenu().findItem(R.id.close_menu_id)); });
+                () -> toolbar.onMenuItemClick(toolbar.getMenu().findItem(R.id.close_menu_id)));
 
         activityDestroyedCallback.waitForCallback(0);
 
@@ -436,8 +412,8 @@
         return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<View>() {
             @Override
             public View call() throws Exception {
-                ArrayList<View> outViews = new ArrayList<View>();
-                ArrayList<View> matchingViews = new ArrayList<View>();
+                ArrayList<View> outViews = new ArrayList<>();
+                ArrayList<View> matchingViews = new ArrayList<>();
                 viewGroup.findViewsWithText(outViews, expectedText, View.FIND_VIEWS_WITH_TEXT);
                 // outViews includes all views whose text contains expectedText as a
                 // case-insensitive substring. Filter these views to find only exact string matches.
@@ -455,40 +431,23 @@
     private BookmarkId addBookmark(final String title, final String url)
             throws InterruptedException, ExecutionException {
         readPartnerBookmarks();
-        return ThreadUtils.runOnUiThreadBlocking(new Callable<BookmarkId>() {
-            @Override
-            public BookmarkId call() throws Exception {
-                return mBookmarkModel.addBookmark(mBookmarkModel.getDefaultFolder(), 0, title, url);
-            }
-        });
+        return ThreadUtils.runOnUiThreadBlocking(
+                () -> mBookmarkModel.addBookmark(mBookmarkModel.getDefaultFolder(), 0, title, url));
     }
 
     private BookmarkId addFolder(final String title)
             throws InterruptedException, ExecutionException {
         readPartnerBookmarks();
-        return ThreadUtils.runOnUiThreadBlocking(new Callable<BookmarkId>() {
-            @Override
-            public BookmarkId call() throws Exception {
-                return mBookmarkModel.addFolder(mBookmarkModel.getDefaultFolder(), 0, title);
-            }
-        });
+        return ThreadUtils.runOnUiThreadBlocking(
+                () -> mBookmarkModel.addFolder(mBookmarkModel.getDefaultFolder(), 0, title));
     }
 
     private void removeBookmark(final BookmarkId bookmarkId) {
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                mBookmarkModel.deleteBookmark(bookmarkId);
-            }
-        });
+        ThreadUtils.runOnUiThreadBlocking(() -> mBookmarkModel.deleteBookmark(bookmarkId));
     }
 
     private void searchBookmarks(final String query) {
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                ((BookmarkItemsAdapter) mItemsContainer.getAdapter()).search(query);
-            }
-        });
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> ((BookmarkItemsAdapter) mItemsContainer.getAdapter()).search(query));
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/MockContextualSearchPolicy.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/MockContextualSearchPolicy.java
index fc91f99..bd5dec6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/MockContextualSearchPolicy.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/MockContextualSearchPolicy.java
@@ -24,11 +24,6 @@
     }
 
     @Override
-    public boolean isPeekPromoConditionSatisfied() {
-        return false;
-    }
-
-    @Override
     public boolean shouldAnimateSearchProviderIcon() {
         return false;
     }
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index d0be9a4..b49dcca 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -387,6 +387,7 @@
 chrome_packaged_services = [
   ":chrome_manifest",
   "//chrome/profiling:manifest",
+  "//components/patch_service:manifest",
   "//services/metrics:manifest",
   "//services/proxy_resolver:proxy_resolver_manifest",
   "//services/preferences:local_state_manifest",
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index ae23437..44883e7a 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3299,6 +3299,9 @@
       <message name="IDS_UTILITY_PROCESS_DIAL_DEVICE_DESCRIPTION_PARSER_NAME" desc="The name of the utility process used for parsing XML of uPnP device descriptions of DIAL devices.">
         DIAL Device Description Parser
       </message>
+      <message name="IDS_UTILITY_PROCESS_PATCH_NAME" desc="The name of the utility process used for patching file operations.">
+          Patch Service
+      </message>
 
       <!-- Theme preview info bar -->
       <message name="IDS_THEME_INSTALL_INFOBAR_LABEL" desc="Text displayed on an infobar when a theme has been installed.">
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 7cabe94..4ddd86f5 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -257,8 +257,6 @@
     "command_updater_delegate.h",
     "component_updater/chrome_component_updater_configurator.cc",
     "component_updater/chrome_component_updater_configurator.h",
-    "component_updater/component_patcher_operation_out_of_process.cc",
-    "component_updater/component_patcher_operation_out_of_process.h",
     "component_updater/component_updater_prefs.cc",
     "component_updater/component_updater_prefs.h",
     "component_updater/component_updater_resource_throttle.cc",
@@ -702,6 +700,8 @@
     "metrics/metrics_reporting_state.h",
     "metrics/network_quality_estimator_provider_impl.cc",
     "metrics/network_quality_estimator_provider_impl.h",
+    "metrics/oom/out_of_memory_reporter.cc",
+    "metrics/oom/out_of_memory_reporter.h",
     "metrics/perf/perf_provider_chromeos.cc",
     "metrics/perf/perf_provider_chromeos.h",
     "metrics/process_memory_metrics_emitter.cc",
@@ -1626,6 +1626,7 @@
     "//components/password_manager/core/browser",
     "//components/password_manager/core/common",
     "//components/password_manager/sync/browser",
+    "//components/patch_service/public/interfaces",
     "//components/payments/core",
     "//components/physical_web/eddystone",
     "//components/policy:generated",
diff --git a/chrome/browser/android/compositor/layer/contextual_search_layer.cc b/chrome/browser/android/compositor/layer/contextual_search_layer.cc
index ec8e735..cabf5bc7 100644
--- a/chrome/browser/android/compositor/layer/contextual_search_layer.cc
+++ b/chrome/browser/android/compositor/layer/contextual_search_layer.cc
@@ -20,12 +20,12 @@
 
 const SkColor kSearchBackgroundColor = SkColorSetRGB(0xee, 0xee, 0xee);
 const SkColor kSearchBarBackgroundColor = SkColorSetRGB(0xff, 0xff, 0xff);
-const SkColor kPeekPromoRippleBackgroundColor = SkColorSetRGB(0x42, 0x85, 0xF4);
+const SkColor kBarBannerRippleBackgroundColor = SkColorSetRGB(0x42, 0x85, 0xF4);
 const SkColor kTouchHighlightColor = SkColorSetARGB(0x33, 0x99, 0x99, 0x99);
 
-// The alpha blend used in the Peek Promo Background in order to achieve
-// a lighter shade of the color of the Peek Promo Ripple.
-const SkAlpha kPeekPromoBackgroundMaximumAlphaBlend = 0.25f * 255;
+// The alpha blend used in the Bar Banner Background in order to achieve
+// a lighter shade of the color of the Bar Banner Ripple.
+const SkAlpha kBarBannerBackgroundMaximumAlphaBlend = 0.25f * 255;
 
 }  // namespace
 
@@ -50,19 +50,19 @@
     int progress_bar_background_resource_id,
     int progress_bar_resource_id,
     int search_promo_resource_id,
-    int peek_promo_ripple_resource_id,
-    int peek_promo_text_resource_id,
+    int bar_banner_ripple_resource_id,
+    int bar_banner_text_resource_id,
     float dp_to_px,
     const scoped_refptr<cc::Layer>& content_layer,
     bool search_promo_visible,
     float search_promo_height,
     float search_promo_opacity,
-    bool search_peek_promo_visible,
-    float search_peek_promo_height,
-    float search_peek_promo_padding,
-    float search_peek_promo_ripple_width,
-    float search_peek_promo_ripple_opacity,
-    float search_peek_promo_text_opacity,
+    bool search_bar_banner_visible,
+    float search_bar_banner_height,
+    float search_bar_banner_padding,
+    float search_bar_banner_ripple_width,
+    float search_bar_banner_ripple_opacity,
+    float search_bar_banner_text_opacity,
     float search_panel_x,
     float search_panel_y,
     float search_panel_width,
@@ -101,7 +101,7 @@
   // Round values to avoid pixel gap between layers.
   search_bar_height = floor(search_bar_height);
 
-  float search_bar_top = search_peek_promo_height;
+  float search_bar_top = search_bar_banner_height;
   float search_bar_bottom = search_bar_top + search_bar_height;
   bool should_render_progress_bar =
       progress_bar_visible && progress_bar_opacity > 0.f;
@@ -128,95 +128,94 @@
   bool is_rtl = l10n_util::IsLayoutRtl();
 
   // ---------------------------------------------------------------------------
-  // Peek Promo
+  // Bar Banner
   // ---------------------------------------------------------------------------
-  if (search_peek_promo_visible) {
-    // Grabs the Search Opt Out Promo resource.
-    ui::Resource* peek_promo_text_resource = resource_manager_->GetResource(
-        ui::ANDROID_RESOURCE_TYPE_DYNAMIC, peek_promo_text_resource_id);
+  if (search_bar_banner_visible) {
+    // Grabs the Bar Banner resource.
+    ui::Resource* bar_banner_text_resource = resource_manager_->GetResource(
+        ui::ANDROID_RESOURCE_TYPE_DYNAMIC, bar_banner_text_resource_id);
 
-    ui::NinePatchResource* peek_promo_ripple_resource =
+    ui::NinePatchResource* bar_banner_ripple_resource =
         ui::NinePatchResource::From(resource_manager_->GetResource(
-            ui::ANDROID_RESOURCE_TYPE_STATIC, peek_promo_ripple_resource_id));
+            ui::ANDROID_RESOURCE_TYPE_STATIC, bar_banner_ripple_resource_id));
 
     // -----------------------------------------------------------------
-    // Peek Promo Container
+    // Bar Banner Container
     // -----------------------------------------------------------------
-    if (peek_promo_container_->parent() != layer_) {
-      layer_->AddChild(peek_promo_container_);
+    if (bar_banner_container_->parent() != layer_) {
+      layer_->AddChild(bar_banner_container_);
     }
 
-    gfx::Size peek_promo_size(search_panel_width, search_peek_promo_height);
-    peek_promo_container_->SetBounds(peek_promo_size);
-    peek_promo_container_->SetPosition(gfx::PointF(0.f, 0.f));
-    peek_promo_container_->SetMasksToBounds(true);
+    gfx::Size bar_banner_size(search_panel_width, search_bar_banner_height);
+    bar_banner_container_->SetBounds(bar_banner_size);
+    bar_banner_container_->SetPosition(gfx::PointF(0.f, 0.f));
+    bar_banner_container_->SetMasksToBounds(true);
 
     // Apply a blend based on the ripple opacity. The resulting color will
     // be an interpolation between the background color of the Search Bar and
     // a lighter shade of the background color of the Ripple. The range of
     // the alpha value used in the blend will be:
-    // [0.f, kPeekPromoBackgroundMaximumAlphaBlend]
-    peek_promo_container_->SetBackgroundColor(
-        color_utils::AlphaBlend(kPeekPromoRippleBackgroundColor,
-                                kSearchBarBackgroundColor,
-                                kPeekPromoBackgroundMaximumAlphaBlend *
-                                    search_peek_promo_ripple_opacity));
+    // [0.f, kBarBannerBackgroundMaximumAlphaBlend]
+    bar_banner_container_->SetBackgroundColor(color_utils::AlphaBlend(
+        kBarBannerRippleBackgroundColor, kSearchBarBackgroundColor,
+        kBarBannerBackgroundMaximumAlphaBlend *
+            search_bar_banner_ripple_opacity));
 
     // -----------------------------------------------------------------
-    // Peek Promo Ripple
+    // Bar Banner Ripple
     // -----------------------------------------------------------------
-    gfx::Size peek_promo_ripple_size(
-        search_peek_promo_ripple_width, search_peek_promo_height);
-    gfx::Rect peek_promo_ripple_border(
-        peek_promo_ripple_resource->Border(peek_promo_ripple_size));
+    gfx::Size bar_banner_ripple_size(search_bar_banner_ripple_width,
+                                     search_bar_banner_height);
+    gfx::Rect bar_banner_ripple_border(
+        bar_banner_ripple_resource->Border(bar_banner_ripple_size));
 
     // Add padding so the ripple will occupy the whole width at 100%.
-    peek_promo_ripple_size.set_width(
-        peek_promo_ripple_size.width() + peek_promo_ripple_border.width());
+    bar_banner_ripple_size.set_width(bar_banner_ripple_size.width() +
+                                     bar_banner_ripple_border.width());
 
     float ripple_rotation = 0.f;
     float ripple_left = 0.f;
     if (is_rtl) {
       // Rotate the ripple 180 degrees to make it point to the left side.
       ripple_rotation = 180.f;
-      ripple_left = search_panel_width - peek_promo_ripple_size.width();
+      ripple_left = search_panel_width - bar_banner_ripple_size.width();
     }
 
-    peek_promo_ripple_->SetUIResourceId(
-        peek_promo_ripple_resource->ui_resource()->id());
-    peek_promo_ripple_->SetBorder(peek_promo_ripple_border);
-    peek_promo_ripple_->SetAperture(peek_promo_ripple_resource->aperture());
-    peek_promo_ripple_->SetBounds(peek_promo_ripple_size);
-    peek_promo_ripple_->SetPosition(gfx::PointF(ripple_left, 0.f));
-    peek_promo_ripple_->SetOpacity(search_peek_promo_ripple_opacity);
+    bar_banner_ripple_->SetUIResourceId(
+        bar_banner_ripple_resource->ui_resource()->id());
+    bar_banner_ripple_->SetBorder(bar_banner_ripple_border);
+    bar_banner_ripple_->SetAperture(bar_banner_ripple_resource->aperture());
+    bar_banner_ripple_->SetBounds(bar_banner_ripple_size);
+    bar_banner_ripple_->SetPosition(gfx::PointF(ripple_left, 0.f));
+    bar_banner_ripple_->SetOpacity(search_bar_banner_ripple_opacity);
 
     if (ripple_rotation != 0.f) {
       // Apply rotation about the center of the resource.
-      float pivot_x = floor(peek_promo_ripple_size.width() / 2);
-      float pivot_y = floor(peek_promo_ripple_size.height() / 2);
+      float pivot_x = floor(bar_banner_ripple_size.width() / 2);
+      float pivot_y = floor(bar_banner_ripple_size.height() / 2);
       gfx::PointF pivot_origin(pivot_x, pivot_y);
       gfx::Transform transform;
       transform.Translate(pivot_origin.x(), pivot_origin.y());
       transform.RotateAboutZAxis(ripple_rotation);
       transform.Translate(-pivot_origin.x(), -pivot_origin.y());
-      peek_promo_ripple_->SetTransform(transform);
+      bar_banner_ripple_->SetTransform(transform);
     }
 
     // -----------------------------------------------------------------
-    // Peek Promo Text
+    // Bar Banner Text
     // -----------------------------------------------------------------
-    if (peek_promo_text_resource) {
-      peek_promo_text_->SetUIResourceId(
-          peek_promo_text_resource->ui_resource()->id());
-      peek_promo_text_->SetBounds(peek_promo_text_resource->size());
-      peek_promo_text_->SetPosition(
-          gfx::PointF(0.f, search_peek_promo_padding));
-      peek_promo_text_->SetOpacity(search_peek_promo_text_opacity);
+    if (bar_banner_text_resource) {
+      bar_banner_text_->SetUIResourceId(
+          bar_banner_text_resource->ui_resource()->id());
+      bar_banner_text_->SetBounds(bar_banner_text_resource->size());
+      bar_banner_text_->SetPosition(
+          gfx::PointF(0.f, search_bar_banner_padding));
+      bar_banner_text_->SetOpacity(search_bar_banner_text_opacity);
     }
   } else {
-    // Peek Promo Container
-    if (peek_promo_container_.get() && peek_promo_container_->parent())
-      peek_promo_container_->RemoveFromParent();
+    // Bar Banner Container
+    if (bar_banner_container_.get() && bar_banner_container_->parent())
+      bar_banner_container_->RemoveFromParent();
   }
 
   // ---------------------------------------------------------------------------
@@ -727,23 +726,23 @@
       arrow_icon_(cc::UIResourceLayer::Create()),
       search_promo_(cc::UIResourceLayer::Create()),
       search_promo_container_(cc::SolidColorLayer::Create()),
-      peek_promo_container_(cc::SolidColorLayer::Create()),
-      peek_promo_ripple_(cc::NinePatchLayer::Create()),
-      peek_promo_text_(cc::UIResourceLayer::Create()),
+      bar_banner_container_(cc::SolidColorLayer::Create()),
+      bar_banner_ripple_(cc::NinePatchLayer::Create()),
+      bar_banner_text_(cc::UIResourceLayer::Create()),
       progress_bar_(cc::NinePatchLayer::Create()),
       progress_bar_background_(cc::NinePatchLayer::Create()),
       search_caption_(cc::UIResourceLayer::Create()),
       text_layer_(cc::UIResourceLayer::Create()),
       divider_line_(cc::SolidColorLayer::Create()),
       touch_highlight_layer_(cc::SolidColorLayer::Create()) {
-  // Search Peek Promo
-  peek_promo_container_->SetIsDrawable(true);
-  peek_promo_container_->SetBackgroundColor(kSearchBarBackgroundColor);
-  peek_promo_ripple_->SetIsDrawable(true);
-  peek_promo_ripple_->SetFillCenter(true);
-  peek_promo_text_->SetIsDrawable(true);
-  peek_promo_container_->AddChild(peek_promo_ripple_);
-  peek_promo_container_->AddChild(peek_promo_text_);
+  // Search Bar Banner
+  bar_banner_container_->SetIsDrawable(true);
+  bar_banner_container_->SetBackgroundColor(kSearchBarBackgroundColor);
+  bar_banner_ripple_->SetIsDrawable(true);
+  bar_banner_ripple_->SetFillCenter(true);
+  bar_banner_text_->SetIsDrawable(true);
+  bar_banner_container_->AddChild(bar_banner_ripple_);
+  bar_banner_container_->AddChild(bar_banner_text_);
 
   // Search Bar Text
   search_context_->SetIsDrawable(true);
diff --git a/chrome/browser/android/compositor/layer/contextual_search_layer.h b/chrome/browser/android/compositor/layer/contextual_search_layer.h
index 1c0f1b78..7a4c31b 100644
--- a/chrome/browser/android/compositor/layer/contextual_search_layer.h
+++ b/chrome/browser/android/compositor/layer/contextual_search_layer.h
@@ -43,19 +43,19 @@
                      int progress_bar_background_resource_id,
                      int progress_bar_resource_id,
                      int search_promo_resource_id,
-                     int peek_promo_ripple_resource_id,
-                     int peek_promo_text_resource_id,
+                     int bar_banner_ripple_resource_id,
+                     int bar_banner_text_resource_id,
                      float dp_to_px,
                      const scoped_refptr<cc::Layer>& content_layer,
                      bool search_promo_visible,
                      float search_promo_height,
                      float search_promo_opacity,
-                     bool search_peek_promo_visible,
-                     float search_peek_promo_height,
-                     float search_peek_promo_padding,
-                     float search_peek_promo_ripple_width,
-                     float search_peek_promo_ripple_opacity,
-                     float search_peek_promo_text_opacity,
+                     bool search_bar_banner_visible,
+                     float search_bar_banner_height,
+                     float search_bar_banner_padding,
+                     float search_bar_banner_ripple_width,
+                     float search_bar_banner_ripple_opacity,
+                     float search_bar_banner_text_opacity,
                      float search_panel_x,
                      float search_panel_y,
                      float search_panel_width,
@@ -139,9 +139,9 @@
   scoped_refptr<cc::UIResourceLayer> arrow_icon_;
   scoped_refptr<cc::UIResourceLayer> search_promo_;
   scoped_refptr<cc::SolidColorLayer> search_promo_container_;
-  scoped_refptr<cc::SolidColorLayer> peek_promo_container_;
-  scoped_refptr<cc::NinePatchLayer> peek_promo_ripple_;
-  scoped_refptr<cc::UIResourceLayer> peek_promo_text_;
+  scoped_refptr<cc::SolidColorLayer> bar_banner_container_;
+  scoped_refptr<cc::NinePatchLayer> bar_banner_ripple_;
+  scoped_refptr<cc::UIResourceLayer> bar_banner_text_;
   scoped_refptr<cc::NinePatchLayer> progress_bar_;
   scoped_refptr<cc::NinePatchLayer> progress_bar_background_;
   scoped_refptr<cc::UIResourceLayer> search_caption_;
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
index 665d1f08..1418fa8 100644
--- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
@@ -73,8 +73,8 @@
     jint progress_bar_background_resource_id,
     jint progress_bar_resource_id,
     jint search_promo_resource_id,
-    jint peek_promo_ripple_resource_id,
-    jint peek_promo_text_resource_id,
+    jint bar_banner_ripple_resource_id,
+    jint bar_banner_text_resource_id,
     jfloat dp_to_px,
     jfloat base_page_brightness,
     jfloat base_page_offset,
@@ -82,12 +82,12 @@
     jboolean search_promo_visible,
     jfloat search_promo_height,
     jfloat search_promo_opacity,
-    jboolean search_peek_promo_visible,
-    jfloat search_peek_promo_height,
-    jfloat search_peek_promo_padding,
-    jfloat search_peek_promo_ripple_width,
-    jfloat search_peek_promo_ripple_opacity,
-    jfloat search_peek_promo_text_opacity,
+    jboolean search_bar_banner_visible,
+    jfloat search_bar_banner_height,
+    jfloat search_bar_banner_padding,
+    jfloat search_bar_banner_ripple_width,
+    jfloat search_bar_banner_ripple_opacity,
+    jfloat search_bar_banner_text_opacity,
     jfloat search_panel_x,
     jfloat search_panel_y,
     jfloat search_panel_width,
@@ -163,11 +163,11 @@
       quick_action_icon_resource_id, arrow_up_resource_id,
       close_icon_resource_id, progress_bar_background_resource_id,
       progress_bar_resource_id, search_promo_resource_id,
-      peek_promo_ripple_resource_id, peek_promo_text_resource_id, dp_to_px,
+      bar_banner_ripple_resource_id, bar_banner_text_resource_id, dp_to_px,
       content_layer, search_promo_visible, search_promo_height,
-      search_promo_opacity, search_peek_promo_visible, search_peek_promo_height,
-      search_peek_promo_padding, search_peek_promo_ripple_width,
-      search_peek_promo_ripple_opacity, search_peek_promo_text_opacity,
+      search_promo_opacity, search_bar_banner_visible, search_bar_banner_height,
+      search_bar_banner_padding, search_bar_banner_ripple_width,
+      search_bar_banner_ripple_opacity, search_bar_banner_text_opacity,
       search_panel_x, search_panel_y, search_panel_width, search_panel_height,
       search_bar_margin_side, search_bar_height, search_context_opacity,
       search_text_layer_min_height, search_term_opacity,
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h
index 86b90fd..5a2e27c 100644
--- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h
+++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h
@@ -50,8 +50,8 @@
       jint progress_bar_background_resource_id,
       jint progress_bar_resource_id,
       jint search_promo_resource_id,
-      jint peek_promo_ripple_resource_id,
-      jint peek_promo_text_resource_id,
+      jint bar_banner_ripple_resource_id,
+      jint bar_banner_text_resource_id,
       jfloat dp_to_px,
       jfloat base_page_brightness,
       jfloat base_page_offset,
@@ -59,12 +59,12 @@
       jboolean search_promo_visible,
       jfloat search_promo_height,
       jfloat search_promo_opacity,
-      jboolean search_peek_promo_visible,
-      jfloat search_peek_promo_height,
-      jfloat search_peek_promo_padding,
-      jfloat search_peek_promo_ripple_width,
-      jfloat search_peek_promo_ripple_opacity,
-      jfloat search_peek_promo_text_opacity,
+      jboolean search_bar_banner_visible,
+      jfloat search_bar_banner_height,
+      jfloat search_bar_banner_padding,
+      jfloat search_bar_banner_ripple_width,
+      jfloat search_bar_banner_ripple_opacity,
+      jfloat search_bar_banner_text_opacity,
       jfloat search_panel_x,
       jfloat search_panel_y,
       jfloat search_panel_width,
diff --git a/chrome/browser/background/background_contents_service.cc b/chrome/browser/background/background_contents_service.cc
index dacd329b..83526ef 100644
--- a/chrome/browser/background/background_contents_service.cc
+++ b/chrome/browser/background/background_contents_service.cc
@@ -55,7 +55,6 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image.h"
-#include "ui/message_center/message_center.h"
 #include "ui/message_center/notification.h"
 #include "ui/message_center/notification_delegate.h"
 #include "ui/message_center/notification_types.h"
@@ -79,15 +78,8 @@
 bool g_disable_close_balloon_for_testing = false;
 
 void CloseBalloon(const std::string& balloon_id, ProfileID profile_id) {
-  NotificationUIManager* notification_ui_manager =
-      g_browser_process->notification_ui_manager();
-  bool cancelled = notification_ui_manager->CancelById(balloon_id, profile_id);
-  if (cancelled) {
-    // TODO(dewittj): Add this functionality to the notification UI manager's
-    // API.
-    g_browser_process->message_center()->SetVisibility(
-        message_center::VISIBILITY_TRANSIENT);
-  }
+  g_browser_process->notification_ui_manager()->CancelById(balloon_id,
+                                                           profile_id);
 }
 
 // Closes the crash notification balloon for the app/extension with this id.
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 388f667..acfc64d 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -156,6 +156,7 @@
 #include "components/nacl/common/nacl_constants.h"
 #include "components/net_log/chrome_net_log.h"
 #include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
+#include "components/patch_service/public/interfaces/constants.mojom.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
@@ -352,6 +353,7 @@
 #include "components/guest_view/browser/guest_view_base.h"
 #include "components/guest_view/browser/guest_view_manager.h"
 #include "extensions/browser/extension_navigation_throttle.h"
+#include "extensions/browser/extension_protocols.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_util.h"
 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
@@ -3140,6 +3142,9 @@
       l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_FILE_UTILITY_NAME);
 #endif
 
+  (*services)[patch::mojom::kServiceName] =
+      l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_PATCH_NAME);
+
 #if BUILDFLAG(ENABLE_MUS)
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kMash))
     mash_service_registry::RegisterOutOfProcessServices(services);
@@ -3597,6 +3602,29 @@
   return result;
 }
 
+void ChromeContentBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories(
+    content::RenderFrameHost* frame_host,
+    NonNetworkURLLoaderFactoryMap* factories) {
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  factories->emplace(
+      extensions::kExtensionScheme,
+      extensions::CreateExtensionNavigationURLLoaderFactory(frame_host));
+#endif
+}
+
+void ChromeContentBrowserClient::
+    RegisterNonNetworkSubresourceURLLoaderFactories(
+        content::RenderFrameHost* frame_host,
+        const GURL& frame_url,
+        NonNetworkURLLoaderFactoryMap* factories) {
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  auto factory = extensions::MaybeCreateExtensionSubresourceURLLoaderFactory(
+      frame_host, frame_url);
+  if (factory)
+    factories->emplace(extensions::kExtensionScheme, std::move(factory));
+#endif
+}
+
 // Static; handles rewriting Web UI URLs.
 bool ChromeContentBrowserClient::HandleWebUI(
     GURL* url,
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 351650c1..3da33835 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -363,6 +363,13 @@
   std::vector<std::unique_ptr<content::URLLoaderThrottle>>
   CreateURLLoaderThrottles(
       const base::Callback<content::WebContents*()>& wc_getter) override;
+  void RegisterNonNetworkNavigationURLLoaderFactories(
+      content::RenderFrameHost* frame_host,
+      NonNetworkURLLoaderFactoryMap* factories) override;
+  void RegisterNonNetworkSubresourceURLLoaderFactories(
+      content::RenderFrameHost* frame_host,
+      const GURL& frame_url,
+      NonNetworkURLLoaderFactoryMap* factories) override;
 
  protected:
   static bool HandleWebUI(GURL* url, content::BrowserContext* browser_context);
diff --git a/chrome/browser/chrome_content_browser_manifest_overlay.json b/chrome/browser/chrome_content_browser_manifest_overlay.json
index 983ffa3..51588d4 100644
--- a/chrome/browser/chrome_content_browser_manifest_overlay.json
+++ b/chrome/browser/chrome_content_browser_manifest_overlay.json
@@ -39,6 +39,7 @@
         "local_state": [ "pref_client" ],
         "nacl_broker": [ "browser" ],
         "nacl_loader": [ "browser" ],
+        "patch": [ "patch_file" ],
         "pdf_compositor": [ "compositor" ],
         "profile_import": [ "import" ],
         "profiling": [ "profiling" ],
diff --git a/chrome/browser/chrome_content_utility_manifest_overlay.json b/chrome/browser/chrome_content_utility_manifest_overlay.json
index 17db13477..174ac82 100644
--- a/chrome/browser/chrome_content_utility_manifest_overlay.json
+++ b/chrome/browser/chrome_content_utility_manifest_overlay.json
@@ -5,7 +5,6 @@
       "provides": {
         "browser": [
           "chrome::mojom::DialDeviceDescriptionParser",
-          "chrome::mojom::FilePatcher",
           "chrome::mojom::ProfileImport",
           "chrome::mojom::ResourceUsageReporter",
           "chrome::mojom::SafeArchiveAnalyzer",
diff --git a/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc b/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc
index 3339f83..64d22430 100644
--- a/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc
+++ b/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc
@@ -53,8 +53,14 @@
   const bool is_play_store_enabled = IsArcPlayStoreEnabledForProfile(profile_);
   VLOG(1) << "Start observing Google Play Store enabled preference. "
           << "Initial value: " << is_play_store_enabled;
-  UpdateArcSessionManager();
 
+  // If the OOBE screen is shown, don't kill the mini-container.
+  // We'll do it if and when the user declines the TOS. We need to check
+  // |is_play_store_enabled| to handle the case where |kArcEnabled| is managed
+  // but some of the preferences still need to be set by the user.
+  // TODO(cmtm): This feature isn't covered by unittests. Add a unittest for it.
+  if (!IsArcOobeOptInActive() || is_play_store_enabled)
+    UpdateArcSessionManager();
   if (is_play_store_enabled)
     return;
 
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc
index 563efc0..2c001e12d 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -24,8 +24,6 @@
 #include "chrome/browser/chromeos/arc/optin/arc_terms_of_service_oobe_negotiator.h"
 #include "chrome/browser/chromeos/arc/policy/arc_android_management_checker.h"
 #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h"
-#include "chrome/browser/chromeos/login/ui/login_display_host.h"
-#include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/policy/profile_policy_connector_factory.h"
@@ -164,41 +162,6 @@
 }
 
 // static
-bool ArcSessionManager::IsOobeOptInActive() {
-  // Check if Chrome OS OOBE or OPA OptIn flow is currently showing.
-  // TODO(b/65861628): Rename the method since it is no longer accurate.
-  // Redesign the OptIn flow since there is no longer reason to have two
-  // different OptIn flows.
-  chromeos::LoginDisplayHost* host = chromeos::LoginDisplayHost::default_host();
-  if (!host)
-    return false;
-
-  // Make sure the wizard controller is active and have the ARC ToS screen
-  // showing for the voice interaction OptIn flow.
-  if (host->IsVoiceInteractionOobe()) {
-    const chromeos::WizardController* wizard_controller =
-        host->GetWizardController();
-    if (!wizard_controller)
-      return false;
-    const chromeos::BaseScreen* screen = wizard_controller->current_screen();
-    if (!screen)
-      return false;
-    return screen->screen_id() ==
-           chromeos::OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE;
-  }
-
-  // Use the legacy logic for first sign-in OOBE OptIn flow. Make sure the user
-  // is new and the swtich is appended.
-  if (!user_manager::UserManager::Get()->IsCurrentUserNew())
-    return false;
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          chromeos::switches::kEnableArcOOBEOptIn)) {
-    return false;
-  }
-  return true;
-}
-
-// static
 void ArcSessionManager::DisableUIForTesting() {
   g_disable_ui_for_testing = true;
 }
@@ -486,8 +449,11 @@
       break;
     case State::NEGOTIATING_TERMS_OF_SERVICE:
     case State::CHECKING_ANDROID_MANAGEMENT:
-      // Those operations are synchronously cancelled, so set the state to
-      // STOPPED immediately.
+      // We need to kill the mini-container that might be running here.
+      arc_session_runner_->RequestStop();
+      // While RequestStop is asynchronous, ArcSessionManager is agnostic to the
+      // state of the mini-container, so we can set it's state_ to STOPPED
+      // immediately.
       state_ = State::STOPPED;
       break;
     case State::REMOVING_DATA_DIR:
@@ -614,7 +580,7 @@
     return false;
   }
 
-  oobe_start_ = IsOobeOptInActive();
+  oobe_start_ = IsArcOobeOptInActive();
 
   PrefService* const prefs = profile_->GetPrefs();
 
@@ -743,7 +709,7 @@
     return;
   }
 
-  if (IsOobeOptInActive()) {
+  if (IsArcOobeOptInActive()) {
     VLOG(1) << "Use OOBE negotiator.";
     terms_of_service_negotiator_ =
         std::make_unique<ArcTermsOfServiceOobeNegotiator>();
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.h b/chrome/browser/chromeos/arc/arc_session_manager.h
index 6d8f887..287bc4c 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.h
+++ b/chrome/browser/chromeos/arc/arc_session_manager.h
@@ -137,9 +137,6 @@
 
   static ArcSessionManager* Get();
 
-  // Returns true if OOBE flow is active currently.
-  static bool IsOobeOptInActive();
-
   static void DisableUIForTesting();
   static void EnableCheckAndroidManagementForTesting();
 
@@ -361,9 +358,9 @@
   bool reenable_arc_ = false;
   bool provisioning_reported_ = false;
   // In case ARC is started from OOBE |oobe_start_|, set to true. This flag is
-  // used to remember |IsOobeOptInActive| state when ARC start request was made.
-  // |IsOobeOptInActive| will be changed by the time when |oobe_start_| is
-  // checked to prevent the Play Store auto-launch.
+  // used to remember |IsArcOobeOptInActive| state when ARC start request was
+  // made.  |IsArcOobeOptInActive| will be changed by the time when
+  // |oobe_start_| is checked to prevent the Play Store auto-launch.
   bool oobe_start_ = false;
   bool directly_started_ = false;
   base::OneShotTimer arc_sign_in_timer_;
diff --git a/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc b/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
index 7daa8323..c78c3a6 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
@@ -847,21 +847,21 @@
 TEST_F(ArcSessionOobeOptInTest, OobeOptInActive) {
   // OOBE OptIn is active in case of OOBE controller is alive and the ARC ToS
   // screen is currently showing.
-  EXPECT_FALSE(ArcSessionManager::IsOobeOptInActive());
+  EXPECT_FALSE(IsArcOobeOptInActive());
   CreateLoginDisplayHost();
-  EXPECT_FALSE(ArcSessionManager::IsOobeOptInActive());
+  EXPECT_FALSE(IsArcOobeOptInActive());
   GetFakeUserManager()->set_current_user_new(true);
-  EXPECT_FALSE(ArcSessionManager::IsOobeOptInActive());
+  EXPECT_FALSE(IsArcOobeOptInActive());
   AppendEnableArcOOBEOptInSwitch();
-  EXPECT_TRUE(ArcSessionManager::IsOobeOptInActive());
+  EXPECT_TRUE(IsArcOobeOptInActive());
   login_display_host()->StartVoiceInteractionOobe();
-  EXPECT_FALSE(ArcSessionManager::IsOobeOptInActive());
+  EXPECT_FALSE(IsArcOobeOptInActive());
   login_display_host()->StartWizard(
       chromeos::OobeScreen::SCREEN_VOICE_INTERACTION_VALUE_PROP);
-  EXPECT_FALSE(ArcSessionManager::IsOobeOptInActive());
+  EXPECT_FALSE(IsArcOobeOptInActive());
   login_display_host()->StartWizard(
       chromeos::OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE);
-  EXPECT_TRUE(ArcSessionManager::IsOobeOptInActive());
+  EXPECT_TRUE(IsArcOobeOptInActive());
 }
 
 class ArcSessionOobeOptInNegotiatorTest
diff --git a/chrome/browser/chromeos/arc/arc_util.cc b/chrome/browser/chromeos/arc/arc_util.cc
index e74e3ac..ffa850e0 100644
--- a/chrome/browser/chromeos/arc/arc_util.cc
+++ b/chrome/browser/chromeos/arc/arc_util.cc
@@ -20,8 +20,10 @@
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/chromeos/arc/arc_session_manager.h"
 #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h"
+#include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/user_flow.h"
 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
+#include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/chromeos_switches.h"
@@ -359,6 +361,40 @@
   return user ? user->IsActiveDirectoryUser() : false;
 }
 
+bool IsArcOobeOptInActive() {
+  // Check if Chrome OS OOBE or OPA OptIn flow is currently showing.
+  // TODO(b/65861628): Rename the method since it is no longer accurate.
+  // Redesign the OptIn flow since there is no longer reason to have two
+  // different OptIn flows.
+  chromeos::LoginDisplayHost* host = chromeos::LoginDisplayHost::default_host();
+  if (!host)
+    return false;
+
+  // Make sure the wizard controller is active and have the ARC ToS screen
+  // showing for the voice interaction OptIn flow.
+  if (host->IsVoiceInteractionOobe()) {
+    const chromeos::WizardController* wizard_controller =
+        host->GetWizardController();
+    if (!wizard_controller)
+      return false;
+    const chromeos::BaseScreen* screen = wizard_controller->current_screen();
+    if (!screen)
+      return false;
+    return screen->screen_id() ==
+           chromeos::OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE;
+  }
+
+  // Use the legacy logic for first sign-in OOBE OptIn flow. Make sure the user
+  // is new and the swtich is appended.
+  if (!user_manager::UserManager::Get()->IsCurrentUserNew())
+    return false;
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kEnableArcOOBEOptIn)) {
+    return false;
+  }
+  return true;
+}
+
 void UpdateArcFileSystemCompatibilityPrefIfNeeded(
     const AccountId& account_id,
     const base::FilePath& profile_path,
diff --git a/chrome/browser/chromeos/arc/arc_util.h b/chrome/browser/chromeos/arc/arc_util.h
index 3d12564..1eb77bb4b 100644
--- a/chrome/browser/chromeos/arc/arc_util.h
+++ b/chrome/browser/chromeos/arc/arc_util.h
@@ -115,6 +115,9 @@
 // Active Directory user.
 bool IsActiveDirectoryUserForProfile(const Profile* profile);
 
+// Returns true if ChromeOS OOBE opt-in window is currently showing.
+bool IsArcOobeOptInActive();
+
 // Checks and updates the preference value whether the underlying filesystem
 // for the profile is compatible with ARC, when necessary. After it's done (or
 // skipped), |callback| is run either synchronously or asynchronously.
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
index 5ba6da6..ebef2b89 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -1081,18 +1081,23 @@
 }
 
 void WallpaperManager::UpdateWallpaper(bool clear_cache) {
+  // TODO(crbug.com/776464): Call |ShowSigninWallpaper| if |last_selected_user_|
+  // is empty, call |ShowUserWallpaper| otherwise.
+  bool device_wallpaper_set =
+      SetDeviceWallpaperIfApplicable(user_manager::SignInAccountId());
   // For GAIA login flow, the last_selected_user_ may not be set before user
   // login. If UpdateWallpaper is called at GAIA login screen, no wallpaper will
   // be set. It could result a black screen on external monitors.
   // See http://crbug.com/265689 for detail.
-  if (last_selected_user_.empty())
+  if (!device_wallpaper_set && last_selected_user_.empty())
     GetPendingWallpaper()->SetDefaultWallpaper(user_manager::SignInAccountId());
 
   for (auto& observer : observers_)
     observer.OnUpdateWallpaperForTesting();
   if (clear_cache)
     wallpaper_cache_.clear();
-  ShowUserWallpaper(last_selected_user_);
+  if (!device_wallpaper_set)
+    ShowUserWallpaper(last_selected_user_);
 }
 
 bool WallpaperManager::IsPendingWallpaper(uint32_t image_id) {
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.cc b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
index 02b83a6..2a53f42 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
@@ -6,6 +6,7 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -13,7 +14,6 @@
 #include "base/version.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/component_updater/component_patcher_operation_out_of_process.h"
 #include "chrome/browser/component_updater/component_updater_utils.h"
 #include "chrome/browser/google/google_brand.h"
 #include "chrome/browser/update_client/chrome_update_query_params_delegate.h"
@@ -24,6 +24,9 @@
 #include "components/prefs/pref_service.h"
 #include "components/update_client/activity_data_service.h"
 #include "components/update_client/update_query_params.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 #if defined(OS_WIN)
 #include "base/win/win_util.h"
@@ -56,7 +59,7 @@
   std::string ExtraRequestParams() const override;
   std::string GetDownloadPreference() const override;
   net::URLRequestContextGetter* RequestContext() const override;
-  scoped_refptr<update_client::OutOfProcessPatcher> CreateOutOfProcessPatcher()
+  std::unique_ptr<service_manager::Connector> CreateServiceManagerConnector()
       const override;
   bool EnabledDeltas() const override;
   bool EnabledComponentUpdates() const override;
@@ -159,9 +162,12 @@
   return configurator_impl_.RequestContext();
 }
 
-scoped_refptr<update_client::OutOfProcessPatcher>
-ChromeConfigurator::CreateOutOfProcessPatcher() const {
-  return base::MakeRefCounted<ChromeOutOfProcessPatcher>();
+std::unique_ptr<service_manager::Connector>
+ChromeConfigurator::CreateServiceManagerConnector() const {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  return content::ServiceManagerConnection::GetForProcess()
+      ->GetConnector()
+      ->Clone();
 }
 
 bool ChromeConfigurator::EnabledDeltas() const {
diff --git a/chrome/browser/component_updater/component_patcher_operation_out_of_process_browsertest.cc b/chrome/browser/component_updater/component_patcher_operation_browsertest.cc
similarity index 76%
rename from chrome/browser/component_updater/component_patcher_operation_out_of_process_browsertest.cc
rename to chrome/browser/component_updater/component_patcher_operation_browsertest.cc
index 7f418e8..35817e5 100644
--- a/chrome/browser/component_updater/component_patcher_operation_out_of_process_browsertest.cc
+++ b/chrome/browser/component_updater/component_patcher_operation_browsertest.cc
@@ -15,12 +15,14 @@
 #include "base/run_loop.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/task_scheduler/task_traits.h"
-#include "chrome/browser/component_updater/component_patcher_operation_out_of_process.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "components/patch_service/public/cpp/patch.h"
 #include "components/update_client/component_patcher_operation.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/common/service_manager_connection.h"
 #include "courgette/courgette.h"
 #include "courgette/third_party/bsdiff/bsdiff.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 namespace {
 
@@ -30,9 +32,9 @@
 
 }  // namespace
 
-class OutOfProcessPatchTest : public InProcessBrowserTest {
+class PatchTest : public InProcessBrowserTest {
  public:
-  OutOfProcessPatchTest() {
+  PatchTest() {
     EXPECT_TRUE(installed_dir_.CreateUniqueTempDir());
     EXPECT_TRUE(input_dir_.CreateUniqueTempDir());
     EXPECT_TRUE(unpack_dir_.CreateUniqueTempDir());
@@ -54,7 +56,7 @@
     base::RunLoop run_loop;
     base::PostTaskWithTraitsAndReply(
         FROM_HERE, kTaskTraits,
-        base::BindOnce(&OutOfProcessPatchTest::CopyFile, TestFile(name), path),
+        base::BindOnce(&PatchTest::CopyFile, TestFile(name), path),
         run_loop.QuitClosure());
 
     run_loop.Run();
@@ -67,7 +69,7 @@
     base::RunLoop run_loop;
     base::PostTaskWithTraitsAndReply(
         FROM_HERE, kTaskTraits,
-        base::BindOnce(&OutOfProcessPatchTest::CopyFile, TestFile(name), path),
+        base::BindOnce(&PatchTest::CopyFile, TestFile(name), path),
         run_loop.QuitClosure());
 
     run_loop.Run();
@@ -91,28 +93,31 @@
     quit_closure_ = run_loop.QuitClosure();
     done_called_ = false;
 
+    std::unique_ptr<service_manager::Connector> connector =
+        content::ServiceManagerConnection::GetForProcess()
+            ->GetConnector()
+            ->Clone();
     base::CreateSequencedTaskRunnerWithTraits(kTaskTraits)
-        ->PostTask(FROM_HERE,
-                   base::BindOnce(
-                       &OutOfProcessPatchTest::PatchAsyncSequencedTaskRunner,
-                       base::Unretained(this), operation, input, patch, output,
-                       expected_result));
+        ->PostTask(
+            FROM_HERE,
+            base::BindOnce(&PatchTest::PatchAsyncSequencedTaskRunner,
+                           base::Unretained(this), base::Passed(&connector),
+                           operation, input, patch, output, expected_result));
     run_loop.Run();
     EXPECT_TRUE(done_called_);
   }
 
  private:
-  void PatchAsyncSequencedTaskRunner(const std::string& operation,
-                                     const base::FilePath& input,
-                                     const base::FilePath& patch,
-                                     const base::FilePath& output,
-                                     int expected_result) {
-    scoped_refptr<update_client::OutOfProcessPatcher> patcher =
-        base::MakeRefCounted<component_updater::ChromeOutOfProcessPatcher>();
-
-    patcher->Patch(operation, input, patch, output,
-                   base::BindOnce(&OutOfProcessPatchTest::PatchDone,
-                                  base::Unretained(this), expected_result));
+  void PatchAsyncSequencedTaskRunner(
+      std::unique_ptr<service_manager::Connector> connector,
+      const std::string& operation,
+      const base::FilePath& input,
+      const base::FilePath& patch,
+      const base::FilePath& output,
+      int expected_result) {
+    patch::Patch(connector.get(), operation, input, patch, output,
+                 base::BindOnce(&PatchTest::PatchDone, base::Unretained(this),
+                                expected_result));
   }
 
   void PatchDone(int expected, int result) {
@@ -133,10 +138,10 @@
   base::OnceClosure quit_closure_;
   bool done_called_;
 
-  DISALLOW_COPY_AND_ASSIGN(OutOfProcessPatchTest);
+  DISALLOW_COPY_AND_ASSIGN(PatchTest);
 };
 
-IN_PROC_BROWSER_TEST_F(OutOfProcessPatchTest, CheckBsdiffOperation) {
+IN_PROC_BROWSER_TEST_F(PatchTest, CheckBsdiffOperation) {
   constexpr int kExpectedResult = bsdiff::OK;
 
   base::FilePath input_file = InputFilePath("binary_input.bin");
@@ -149,7 +154,7 @@
   EXPECT_TRUE(base::ContentsEqual(TestFile("binary_output.bin"), output_file));
 }
 
-IN_PROC_BROWSER_TEST_F(OutOfProcessPatchTest, CheckCourgetteOperation) {
+IN_PROC_BROWSER_TEST_F(PatchTest, CheckCourgetteOperation) {
   constexpr int kExpectedResult = courgette::C_OK;
 
   base::FilePath input_file = InputFilePath("binary_input.bin");
@@ -162,7 +167,7 @@
   EXPECT_TRUE(base::ContentsEqual(TestFile("binary_output.bin"), output_file));
 }
 
-IN_PROC_BROWSER_TEST_F(OutOfProcessPatchTest, InvalidInputFile) {
+IN_PROC_BROWSER_TEST_F(PatchTest, InvalidInputFile) {
   constexpr int kInvalidInputFile = -1;
 
   base::FilePath invalid = InvalidPath("binary_input.bin");
@@ -173,7 +178,7 @@
                kInvalidInputFile);
 }
 
-IN_PROC_BROWSER_TEST_F(OutOfProcessPatchTest, InvalidPatchFile) {
+IN_PROC_BROWSER_TEST_F(PatchTest, InvalidPatchFile) {
   constexpr int kInvalidPatchFile = -1;
 
   base::FilePath input_file = InputFilePath("binary_input.bin");
@@ -184,7 +189,7 @@
                kInvalidPatchFile);
 }
 
-IN_PROC_BROWSER_TEST_F(OutOfProcessPatchTest, InvalidOutputFile) {
+IN_PROC_BROWSER_TEST_F(PatchTest, InvalidOutputFile) {
   constexpr int kInvalidOutputFile = -1;
 
   base::FilePath input_file = InputFilePath("binary_input.bin");
diff --git a/chrome/browser/component_updater/component_patcher_operation_out_of_process.cc b/chrome/browser/component_updater/component_patcher_operation_out_of_process.cc
deleted file mode 100644
index 0064cd2..0000000
--- a/chrome/browser/component_updater/component_patcher_operation_out_of_process.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2014 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/component_updater/component_patcher_operation_out_of_process.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/files/file.h"
-#include "base/files/file_path.h"
-#include "base/sequenced_task_runner.h"
-#include "base/strings/string16.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/update_client/component_patcher_operation.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace component_updater {
-
-ChromeOutOfProcessPatcher::ChromeOutOfProcessPatcher() = default;
-
-ChromeOutOfProcessPatcher::~ChromeOutOfProcessPatcher() = default;
-
-void ChromeOutOfProcessPatcher::Patch(
-    const std::string& operation,
-    const base::FilePath& input_path,
-    const base::FilePath& patch_path,
-    const base::FilePath& output_path,
-    base::OnceCallback<void(int result)> callback) {
-  DCHECK(!callback.is_null());
-
-  callback_ = std::move(callback);
-
-  base::File input_file(input_path,
-                        base::File::FLAG_OPEN | base::File::FLAG_READ);
-  base::File patch_file(patch_path,
-                        base::File::FLAG_OPEN | base::File::FLAG_READ);
-  base::File output_file(output_path, base::File::FLAG_CREATE |
-                                          base::File::FLAG_WRITE |
-                                          base::File::FLAG_EXCLUSIVE_WRITE);
-
-  if (!input_file.IsValid() || !patch_file.IsValid() ||
-      !output_file.IsValid()) {
-    base::SequencedTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(std::move(callback_), -1));
-    return;
-  }
-
-  DCHECK(!utility_process_mojo_client_);
-
-  utility_process_mojo_client_ = base::MakeUnique<
-      content::UtilityProcessMojoClient<chrome::mojom::FilePatcher>>(
-      l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_COMPONENT_PATCHER_NAME));
-  utility_process_mojo_client_->set_error_callback(
-      base::Bind(&ChromeOutOfProcessPatcher::PatchDone, this, -1));
-
-  utility_process_mojo_client_->Start();  // Start the utility process.
-
-  if (operation == update_client::kBsdiff) {
-    utility_process_mojo_client_->service()->PatchFileBsdiff(
-        std::move(input_file), std::move(patch_file), std::move(output_file),
-        base::Bind(&ChromeOutOfProcessPatcher::PatchDone, this));
-  } else if (operation == update_client::kCourgette) {
-    utility_process_mojo_client_->service()->PatchFileCourgette(
-        std::move(input_file), std::move(patch_file), std::move(output_file),
-        base::Bind(&ChromeOutOfProcessPatcher::PatchDone, this));
-  } else {
-    NOTREACHED();
-  }
-}
-
-void ChromeOutOfProcessPatcher::PatchDone(int result) {
-  utility_process_mojo_client_.reset();  // Terminate the utility process.
-  base::SequencedTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback_), result));
-}
-
-}  // namespace component_updater
diff --git a/chrome/browser/component_updater/component_patcher_operation_out_of_process.h b/chrome/browser/component_updater/component_patcher_operation_out_of_process.h
deleted file mode 100644
index dd3461d..0000000
--- a/chrome/browser/component_updater/component_patcher_operation_out_of_process.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2014 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_COMPONENT_UPDATER_COMPONENT_PATCHER_OPERATION_OUT_OF_PROCESS_H_
-#define CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_PATCHER_OPERATION_OUT_OF_PROCESS_H_
-
-#include <memory>
-#include <string>
-
-#include "base/callback_forward.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "chrome/common/file_patcher.mojom.h"
-#include "components/update_client/out_of_process_patcher.h"
-#include "content/public/browser/utility_process_mojo_client.h"
-
-namespace base {
-class FilePath;
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace component_updater {
-
-class ChromeOutOfProcessPatcher : public update_client::OutOfProcessPatcher {
- public:
-  ChromeOutOfProcessPatcher();
-
-  // update_client::OutOfProcessPatcher:
-  void Patch(const std::string& operation,
-             const base::FilePath& input_path,
-             const base::FilePath& patch_path,
-             const base::FilePath& output_path,
-             const base::OnceCallback<void(int result)> callback) override;
-
- private:
-  ~ChromeOutOfProcessPatcher() override;
-
-  // Patch operation result handler.
-  void PatchDone(int result);
-
-  // Used to signal the operation result back to the Patch() requester.
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-  base::OnceCallback<void(int result)> callback_;
-
-  // Utility process used to perform out-of-process file patching.
-  std::unique_ptr<content::UtilityProcessMojoClient<chrome::mojom::FilePatcher>>
-      utility_process_mojo_client_;
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeOutOfProcessPatcher);
-};
-
-}  // namespace component_updater
-
-#endif  // CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_PATCHER_OPERATION_OUT_OF_PROCESS_H_
diff --git a/chrome/browser/component_updater/crl_set_component_installer.cc b/chrome/browser/component_updater/crl_set_component_installer.cc
index 76f4b913..9b6468d5 100644
--- a/chrome/browser/component_updater/crl_set_component_installer.cc
+++ b/chrome/browser/component_updater/crl_set_component_installer.cc
@@ -55,6 +55,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   bool VerifyInstallation(const base::DictionaryValue& manifest,
                           const base::FilePath& install_dir) const override;
   void ComponentReady(const base::Version& version,
@@ -87,6 +88,8 @@
   return update_client::CrxInstaller::Result(0);  // Nothing custom here.
 }
 
+void CRLSetPolicy::OnCustomUninstall() {}
+
 bool CRLSetPolicy::VerifyInstallation(const base::DictionaryValue& manifest,
                                       const base::FilePath& install_dir) const {
   return base::PathExists(install_dir.Append(FILE_PATH_LITERAL("crl-set")));
diff --git a/chrome/browser/component_updater/cros_component_installer.cc b/chrome/browser/component_updater/cros_component_installer.cc
index ad7a119..55a56de 100644
--- a/chrome/browser/component_updater/cros_component_installer.cc
+++ b/chrome/browser/component_updater/cros_component_installer.cc
@@ -107,6 +107,15 @@
   return update_client::CrxInstaller::Result(update_client::InstallError::NONE);
 }
 
+void CrOSComponentInstallerPolicy::OnCustomUninstall() {
+  chromeos::ImageLoaderClient* loader =
+      chromeos::DBusThreadManager::Get()->GetImageLoaderClient();
+  if (loader) {
+    loader->RemoveComponent(
+        name, base::BindOnce(base::Callback<void(base::Optional<bool>)>()));
+  }
+}
+
 void CrOSComponentInstallerPolicy::ComponentReady(
     const base::Version& version,
     const base::FilePath& path,
diff --git a/chrome/browser/component_updater/cros_component_installer.h b/chrome/browser/component_updater/cros_component_installer.h
index 323405e..9afcdd93 100644
--- a/chrome/browser/component_updater/cros_component_installer.h
+++ b/chrome/browser/component_updater/cros_component_installer.h
@@ -59,6 +59,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   bool VerifyInstallation(const base::DictionaryValue& manifest,
                           const base::FilePath& install_dir) const override;
   void ComponentReady(const base::Version& version,
diff --git a/chrome/browser/component_updater/file_type_policies_component_installer.cc b/chrome/browser/component_updater/file_type_policies_component_installer.cc
index ad1a9f5..832b283 100644
--- a/chrome/browser/component_updater/file_type_policies_component_installer.cc
+++ b/chrome/browser/component_updater/file_type_policies_component_installer.cc
@@ -75,6 +75,8 @@
   return update_client::CrxInstaller::Result(0);  // Nothing custom here.
 }
 
+void FileTypePoliciesComponentInstallerPolicy::OnCustomUninstall() {}
+
 base::FilePath FileTypePoliciesComponentInstallerPolicy::GetInstalledPath(
     const base::FilePath& base) {
   return base.Append(kFileTypePoliciesBinaryPbFileName);
diff --git a/chrome/browser/component_updater/file_type_policies_component_installer.h b/chrome/browser/component_updater/file_type_policies_component_installer.h
index f87c86f..e9a3bed 100644
--- a/chrome/browser/component_updater/file_type_policies_component_installer.h
+++ b/chrome/browser/component_updater/file_type_policies_component_installer.h
@@ -37,6 +37,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   bool VerifyInstallation(const base::DictionaryValue& manifest,
                           const base::FilePath& install_dir) const override;
   void ComponentReady(const base::Version& version,
diff --git a/chrome/browser/component_updater/optimization_hints_component_installer.cc b/chrome/browser/component_updater/optimization_hints_component_installer.cc
index 296c6f6..0b46b68d8 100644
--- a/chrome/browser/component_updater/optimization_hints_component_installer.cc
+++ b/chrome/browser/component_updater/optimization_hints_component_installer.cc
@@ -67,6 +67,8 @@
   return update_client::CrxInstaller::Result(0);  // Nothing custom here.
 }
 
+void OptimizationHintsComponentInstallerPolicy::OnCustomUninstall() {}
+
 void OptimizationHintsComponentInstallerPolicy::ComponentReady(
     const base::Version& version,
     const base::FilePath& install_dir,
diff --git a/chrome/browser/component_updater/optimization_hints_component_installer.h b/chrome/browser/component_updater/optimization_hints_component_installer.h
index d8461068..90ae6018 100644
--- a/chrome/browser/component_updater/optimization_hints_component_installer.h
+++ b/chrome/browser/component_updater/optimization_hints_component_installer.h
@@ -41,6 +41,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   bool VerifyInstallation(const base::DictionaryValue& manifest,
                           const base::FilePath& install_dir) const override;
   void ComponentReady(const base::Version& version,
diff --git a/chrome/browser/component_updater/origin_trials_component_installer.cc b/chrome/browser/component_updater/origin_trials_component_installer.cc
index 4d67736..40c7f6ea 100644
--- a/chrome/browser/component_updater/origin_trials_component_installer.cc
+++ b/chrome/browser/component_updater/origin_trials_component_installer.cc
@@ -79,6 +79,8 @@
   return update_client::CrxInstaller::Result(0);
 }
 
+void OriginTrialsComponentInstallerPolicy::OnCustomUninstall() {}
+
 void OriginTrialsComponentInstallerPolicy::ComponentReady(
     const base::Version& version,
     const base::FilePath& install_dir,
diff --git a/chrome/browser/component_updater/origin_trials_component_installer.h b/chrome/browser/component_updater/origin_trials_component_installer.h
index f988a00..81df45b2 100644
--- a/chrome/browser/component_updater/origin_trials_component_installer.h
+++ b/chrome/browser/component_updater/origin_trials_component_installer.h
@@ -34,6 +34,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   void ComponentReady(const base::Version& version,
                       const base::FilePath& install_dir,
                       std::unique_ptr<base::DictionaryValue> manifest) override;
diff --git a/chrome/browser/component_updater/pepper_flash_component_installer.cc b/chrome/browser/component_updater/pepper_flash_component_installer.cc
index 2d10a08..3b11e5c 100644
--- a/chrome/browser/component_updater/pepper_flash_component_installer.cc
+++ b/chrome/browser/component_updater/pepper_flash_component_installer.cc
@@ -251,6 +251,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   bool VerifyInstallation(const base::DictionaryValue& manifest,
                           const base::FilePath& install_dir) const override;
   void ComponentReady(const base::Version& version,
@@ -302,6 +303,8 @@
   return update_client::CrxInstaller::Result(update_client::InstallError::NONE);
 }
 
+void FlashComponentInstallerPolicy::OnCustomUninstall() {}
+
 void FlashComponentInstallerPolicy::ComponentReady(
     const base::Version& version,
     const base::FilePath& path,
diff --git a/chrome/browser/component_updater/pnacl_component_installer.cc b/chrome/browser/component_updater/pnacl_component_installer.cc
index 3284822..7af2799 100644
--- a/chrome/browser/component_updater/pnacl_component_installer.cc
+++ b/chrome/browser/component_updater/pnacl_component_installer.cc
@@ -174,6 +174,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   bool VerifyInstallation(const base::DictionaryValue& manifest,
                           const base::FilePath& install_dir) const override;
   void ComponentReady(const base::Version& version,
@@ -207,6 +208,8 @@
   return update_client::CrxInstaller::Result(0);  // Nothing custom here.
 }
 
+void PnaclComponentInstallerPolicy::OnCustomUninstall() {}
+
 bool PnaclComponentInstallerPolicy::VerifyInstallation(
     const base::DictionaryValue& manifest,
     const base::FilePath& install_dir) const {
diff --git a/chrome/browser/component_updater/recovery_improved_component_installer.cc b/chrome/browser/component_updater/recovery_improved_component_installer.cc
index d93fc223..e519b67 100644
--- a/chrome/browser/component_updater/recovery_improved_component_installer.cc
+++ b/chrome/browser/component_updater/recovery_improved_component_installer.cc
@@ -45,6 +45,8 @@
   return update_client::CrxInstaller::Result(0);
 }
 
+void RecoveryImprovedInstallerPolicy::OnCustomUninstall() {}
+
 void RecoveryImprovedInstallerPolicy::ComponentReady(
     const base::Version& version,
     const base::FilePath& install_dir,
diff --git a/chrome/browser/component_updater/recovery_improved_component_installer.h b/chrome/browser/component_updater/recovery_improved_component_installer.h
index fea874e..5b5a11f 100644
--- a/chrome/browser/component_updater/recovery_improved_component_installer.h
+++ b/chrome/browser/component_updater/recovery_improved_component_installer.h
@@ -33,6 +33,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   bool VerifyInstallation(const base::DictionaryValue& manifest,
                           const base::FilePath& install_dir) const override;
   void ComponentReady(const base::Version& version,
diff --git a/chrome/browser/component_updater/ssl_error_assistant_component_installer.cc b/chrome/browser/component_updater/ssl_error_assistant_component_installer.cc
index f0dc624..b9099d8 100644
--- a/chrome/browser/component_updater/ssl_error_assistant_component_installer.cc
+++ b/chrome/browser/component_updater/ssl_error_assistant_component_installer.cc
@@ -72,6 +72,8 @@
   return update_client::CrxInstaller::Result(0);  // Nothing custom here.
 }
 
+void SSLErrorAssistantComponentInstallerPolicy::OnCustomUninstall() {}
+
 base::FilePath SSLErrorAssistantComponentInstallerPolicy::GetInstalledPath(
     const base::FilePath& base) {
   return base.Append(kConfigBinaryPbFileName);
diff --git a/chrome/browser/component_updater/ssl_error_assistant_component_installer.h b/chrome/browser/component_updater/ssl_error_assistant_component_installer.h
index 46408df9..91ab3de 100644
--- a/chrome/browser/component_updater/ssl_error_assistant_component_installer.h
+++ b/chrome/browser/component_updater/ssl_error_assistant_component_installer.h
@@ -31,6 +31,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   bool VerifyInstallation(const base::DictionaryValue& manifest,
                           const base::FilePath& install_dir) const override;
   void ComponentReady(const base::Version& version,
diff --git a/chrome/browser/component_updater/sth_set_component_installer.cc b/chrome/browser/component_updater/sth_set_component_installer.cc
index 38e7bd7e..06e2cae 100644
--- a/chrome/browser/component_updater/sth_set_component_installer.cc
+++ b/chrome/browser/component_updater/sth_set_component_installer.cc
@@ -74,6 +74,8 @@
   return update_client::CrxInstaller::Result(0);  // Nothing custom here.
 }
 
+void STHSetComponentInstallerPolicy::OnCustomUninstall() {}
+
 void STHSetComponentInstallerPolicy::ComponentReady(
     const base::Version& version,
     const base::FilePath& install_dir,
diff --git a/chrome/browser/component_updater/sth_set_component_installer.h b/chrome/browser/component_updater/sth_set_component_installer.h
index 6efd75a..a2d181f 100644
--- a/chrome/browser/component_updater/sth_set_component_installer.h
+++ b/chrome/browser/component_updater/sth_set_component_installer.h
@@ -53,6 +53,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   bool VerifyInstallation(const base::DictionaryValue& manifest,
                           const base::FilePath& install_dir) const override;
   void ComponentReady(const base::Version& version,
diff --git a/chrome/browser/component_updater/subresource_filter_component_installer.cc b/chrome/browser/component_updater/subresource_filter_component_installer.cc
index fa87ee8c..5011068 100644
--- a/chrome/browser/component_updater/subresource_filter_component_installer.cc
+++ b/chrome/browser/component_updater/subresource_filter_component_installer.cc
@@ -63,6 +63,8 @@
   return update_client::CrxInstaller::Result(0);  // Nothing custom here.
 }
 
+void SubresourceFilterComponentInstallerPolicy::OnCustomUninstall() {}
+
 void SubresourceFilterComponentInstallerPolicy::ComponentReady(
     const base::Version& version,
     const base::FilePath& install_dir,
diff --git a/chrome/browser/component_updater/subresource_filter_component_installer.h b/chrome/browser/component_updater/subresource_filter_component_installer.h
index d2a0ae0..71efd40 100644
--- a/chrome/browser/component_updater/subresource_filter_component_installer.h
+++ b/chrome/browser/component_updater/subresource_filter_component_installer.h
@@ -43,6 +43,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   bool VerifyInstallation(const base::DictionaryValue& manifest,
                           const base::FilePath& install_dir) const override;
   void ComponentReady(const base::Version& version,
diff --git a/chrome/browser/component_updater/supervised_user_whitelist_installer.cc b/chrome/browser/component_updater/supervised_user_whitelist_installer.cc
index b50b06a..9413d19 100644
--- a/chrome/browser/component_updater/supervised_user_whitelist_installer.cc
+++ b/chrome/browser/component_updater/supervised_user_whitelist_installer.cc
@@ -264,6 +264,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   void ComponentReady(const base::Version& version,
                       const base::FilePath& install_dir,
                       std::unique_ptr<base::DictionaryValue> manifest) override;
@@ -310,6 +311,8 @@
               : update_client::InstallError::GENERIC_ERROR);
 }
 
+void SupervisedUserWhitelistComponentInstallerPolicy::OnCustomUninstall() {}
+
 void SupervisedUserWhitelistComponentInstallerPolicy::ComponentReady(
     const base::Version& version,
     const base::FilePath& install_dir,
diff --git a/chrome/browser/component_updater/sw_reporter_installer_win.cc b/chrome/browser/component_updater/sw_reporter_installer_win.cc
index 6a7d1ac3..bf5b848 100644
--- a/chrome/browser/component_updater/sw_reporter_installer_win.cc
+++ b/chrome/browser/component_updater/sw_reporter_installer_win.cc
@@ -315,6 +315,8 @@
   return update_client::CrxInstaller::Result(0);
 }
 
+void SwReporterInstallerPolicy::OnCustomUninstall() {}
+
 void SwReporterInstallerPolicy::ComponentReady(
     const base::Version& version,
     const base::FilePath& install_dir,
diff --git a/chrome/browser/component_updater/sw_reporter_installer_win.h b/chrome/browser/component_updater/sw_reporter_installer_win.h
index c4593b3..2049ac1 100644
--- a/chrome/browser/component_updater/sw_reporter_installer_win.h
+++ b/chrome/browser/component_updater/sw_reporter_installer_win.h
@@ -60,6 +60,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   void ComponentReady(const base::Version& version,
                       const base::FilePath& install_dir,
                       std::unique_ptr<base::DictionaryValue> manifest) override;
diff --git a/chrome/browser/component_updater/third_party_module_list_component_installer_win.cc b/chrome/browser/component_updater/third_party_module_list_component_installer_win.cc
index 0bfb1933..6c678d0 100644
--- a/chrome/browser/component_updater/third_party_module_list_component_installer_win.cc
+++ b/chrome/browser/component_updater/third_party_module_list_component_installer_win.cc
@@ -69,6 +69,8 @@
   return update_client::CrxInstaller::Result(0);  // Nothing custom here.
 }
 
+void ThirdPartyModuleListComponentInstallerPolicy::OnCustomUninstall() {}
+
 // NOTE: This is always called on the main UI thread. It is called once every
 // startup to notify of an already installed component, and may be called
 // repeatedly after that every time a new component is ready.
diff --git a/chrome/browser/component_updater/third_party_module_list_component_installer_win.h b/chrome/browser/component_updater/third_party_module_list_component_installer_win.h
index 4aa3e5a..d8562e6 100644
--- a/chrome/browser/component_updater/third_party_module_list_component_installer_win.h
+++ b/chrome/browser/component_updater/third_party_module_list_component_installer_win.h
@@ -48,6 +48,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   bool VerifyInstallation(const base::DictionaryValue& manifest,
                           const base::FilePath& install_dir) const override;
   void ComponentReady(const base::Version& version,
diff --git a/chrome/browser/component_updater/widevine_cdm_component_installer.cc b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
index e87e5a6..ef8034278 100644
--- a/chrome/browser/component_updater/widevine_cdm_component_installer.cc
+++ b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
@@ -282,6 +282,7 @@
   update_client::CrxInstaller::Result OnCustomInstall(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
   bool VerifyInstallation(
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) const override;
@@ -324,6 +325,8 @@
   return update_client::CrxInstaller::Result(0);
 }
 
+void WidevineCdmComponentInstallerPolicy::OnCustomUninstall() {}
+
 // Once the CDM is ready, check the CDM adapter.
 void WidevineCdmComponentInstallerPolicy::ComponentReady(
     const base::Version& version,
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index 17c4ec2..605586c 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -178,14 +178,20 @@
 }
 
 bool ChromeExtensionsBrowserClient::AllowCrossRendererResourceLoad(
-    net::URLRequest* request,
+    const GURL& url,
+    content::ResourceType resource_type,
+    ui::PageTransition page_transition,
+    int child_id,
     bool is_incognito,
     const Extension* extension,
-    InfoMap* extension_info_map) {
+    const ExtensionSet& extensions,
+    const ProcessMap& process_map) {
   bool allowed = false;
   if (chrome_url_request_util::AllowCrossRendererResourceLoad(
-          request, is_incognito, extension, extension_info_map, &allowed))
+          url, resource_type, page_transition, child_id, is_incognito,
+          extension, extensions, process_map, &allowed)) {
     return allowed;
+  }
 
   // Couldn't determine if resource is allowed. Block the load.
   return false;
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.h b/chrome/browser/extensions/chrome_extensions_browser_client.h
index e61c9ed..e74dfee 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.h
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.h
@@ -71,10 +71,14 @@
       const base::FilePath& directory_path,
       const std::string& content_security_policy,
       bool send_cors_header) override;
-  bool AllowCrossRendererResourceLoad(net::URLRequest* request,
+  bool AllowCrossRendererResourceLoad(const GURL& url,
+                                      content::ResourceType resource_type,
+                                      ui::PageTransition page_transition,
+                                      int child_id,
                                       bool is_incognito,
                                       const Extension* extension,
-                                      InfoMap* extension_info_map) override;
+                                      const ExtensionSet& extensions,
+                                      const ProcessMap& process_map) override;
   PrefService* GetPrefServiceForContext(
       content::BrowserContext* context) override;
   void GetEarlyExtensionPrefsObservers(
diff --git a/chrome/browser/extensions/chrome_url_request_util.cc b/chrome/browser/extensions/chrome_url_request_util.cc
index c23634ee..fbe3463 100644
--- a/chrome/browser/extensions/chrome_url_request_util.cc
+++ b/chrome/browser/extensions/chrome_url_request_util.cc
@@ -19,7 +19,6 @@
 #include "extensions/browser/component_extension_resource_manager.h"
 #include "extensions/browser/extension_protocols.h"
 #include "extensions/browser/extensions_browser_client.h"
-#include "extensions/browser/info_map.h"
 #include "extensions/browser/url_request_util.h"
 #include "extensions/common/file_util.h"
 #include "net/base/mime_util.h"
@@ -122,13 +121,18 @@
 namespace extensions {
 namespace chrome_url_request_util {
 
-bool AllowCrossRendererResourceLoad(net::URLRequest* request,
+bool AllowCrossRendererResourceLoad(const GURL& url,
+                                    content::ResourceType resource_type,
+                                    ui::PageTransition page_transition,
+                                    int child_id,
                                     bool is_incognito,
                                     const Extension* extension,
-                                    InfoMap* extension_info_map,
+                                    const ExtensionSet& extensions,
+                                    const ProcessMap& process_map,
                                     bool* allowed) {
   if (url_request_util::AllowCrossRendererResourceLoad(
-          request, is_incognito, extension, extension_info_map, allowed)) {
+          url, resource_type, page_transition, child_id, is_incognito,
+          extension, extensions, process_map, allowed)) {
     return true;
   }
 
diff --git a/chrome/browser/extensions/chrome_url_request_util.h b/chrome/browser/extensions/chrome_url_request_util.h
index 4e7aa55a..1077ef24 100644
--- a/chrome/browser/extensions/chrome_url_request_util.h
+++ b/chrome/browser/extensions/chrome_url_request_util.h
@@ -7,6 +7,12 @@
 
 #include <string>
 
+#include "content/public/common/resource_type.h"
+#include "content/public/common/url_loader.mojom.h"
+#include "ui/base/page_transition_types.h"
+
+class GURL;
+
 namespace base {
 class FilePath;
 }
@@ -19,7 +25,8 @@
 
 namespace extensions {
 class Extension;
-class InfoMap;
+class ExtensionSet;
+class ProcessMap;
 
 // Utilities related to URLRequest jobs for extension resources. See
 // chrome/browser/extensions/extension_protocols_unittest.cc for related tests.
@@ -28,10 +35,14 @@
 // Sets allowed=true to allow a chrome-extension:// resource request coming from
 // renderer A to access a resource in an extension running in renderer B.
 // Returns false when it couldn't determine if the resource is allowed or not
-bool AllowCrossRendererResourceLoad(net::URLRequest* request,
+bool AllowCrossRendererResourceLoad(const GURL& url,
+                                    content::ResourceType resource_type,
+                                    ui::PageTransition page_transition,
+                                    int child_id,
                                     bool is_incognito,
                                     const Extension* extension,
-                                    InfoMap* extension_info_map,
+                                    const ExtensionSet& extensions,
+                                    const ProcessMap& process_map,
                                     bool* allowed);
 
 // Creates a URLRequestJob for loading component extension resources out of
diff --git a/chrome/browser/extensions/updater/chrome_update_client_config.cc b/chrome/browser/extensions/updater/chrome_update_client_config.cc
index 5e9a0553..c8d6d56b5 100644
--- a/chrome/browser/extensions/updater/chrome_update_client_config.cc
+++ b/chrome/browser/extensions/updater/chrome_update_client_config.cc
@@ -8,7 +8,6 @@
 
 #include "base/command_line.h"
 #include "base/version.h"
-#include "chrome/browser/component_updater/component_patcher_operation_out_of_process.h"
 #include "chrome/browser/component_updater/component_updater_utils.h"
 #include "chrome/browser/google/google_brand.h"
 #include "chrome/browser/update_client/chrome_update_query_params_delegate.h"
@@ -17,8 +16,11 @@
 #include "components/update_client/activity_data_service.h"
 #include "components/update_client/update_query_params.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/common/service_manager_connection.h"
 #include "extensions/browser/extension_prefs.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 namespace extensions {
 
@@ -84,7 +86,7 @@
     : impl_(base::CommandLine::ForCurrentProcess(),
             content::BrowserContext::GetDefaultStoragePartition(context)
                 ->GetURLRequestContext(),
-            true),
+            /*require_encryption=*/true),
       pref_service_(ExtensionPrefs::Get(context)->pref_service()),
       activity_data_service_(std::make_unique<ExtensionActivityDataService>(
           ExtensionPrefs::Get(context))) {
@@ -154,9 +156,12 @@
   return impl_.RequestContext();
 }
 
-scoped_refptr<update_client::OutOfProcessPatcher>
-ChromeUpdateClientConfig::CreateOutOfProcessPatcher() const {
-  return base::MakeRefCounted<component_updater::ChromeOutOfProcessPatcher>();
+std::unique_ptr<service_manager::Connector>
+ChromeUpdateClientConfig::CreateServiceManagerConnector() const {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  return content::ServiceManagerConnection::GetForProcess()
+      ->GetConnector()
+      ->Clone();
 }
 
 bool ChromeUpdateClientConfig::EnabledDeltas() const {
diff --git a/chrome/browser/extensions/updater/chrome_update_client_config.h b/chrome/browser/extensions/updater/chrome_update_client_config.h
index 2de53221..e27d3393 100644
--- a/chrome/browser/extensions/updater/chrome_update_client_config.h
+++ b/chrome/browser/extensions/updater/chrome_update_client_config.h
@@ -45,7 +45,7 @@
   std::string ExtraRequestParams() const override;
   std::string GetDownloadPreference() const override;
   net::URLRequestContextGetter* RequestContext() const override;
-  scoped_refptr<update_client::OutOfProcessPatcher> CreateOutOfProcessPatcher()
+  std::unique_ptr<service_manager::Connector> CreateServiceManagerConnector()
       const override;
   bool EnabledDeltas() const override;
   bool EnabledComponentUpdates() const override;
diff --git a/chrome/browser/history/history_browsertest.cc b/chrome/browser/history/history_browsertest.cc
index 9a67bb22..c8db789 100644
--- a/chrome/browser/history/history_browsertest.cc
+++ b/chrome/browser/history/history_browsertest.cc
@@ -33,6 +33,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_frame_navigation_observer.h"
+#include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "url/gurl.h"
 
@@ -51,9 +52,9 @@
     test_server_.ServeFilesFromSourceDirectory(base::FilePath(kDocRoot));
   }
 
-  void SetUp() override {
+  void SetUpOnMainThread() override {
+    host_resolver()->AddRule("*", "127.0.0.1");
     ASSERT_TRUE(test_server_.Start());
-    InProcessBrowserTest::SetUp();
   }
 
   PrefService* GetPrefs() {
@@ -474,7 +475,7 @@
   ASSERT_FALSE(HistoryContainsURL(auto_subframe));
 }
 
-// HTTP meta-refresh redirects should have separate history entries.
+// HTTP meta-refresh redirects should only have an entry for the landing page.
 IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, RedirectHistory) {
   GURL redirector = ui_test_utils::GetTestUrl(
       base::FilePath().AppendASCII("History"),
@@ -484,12 +485,31 @@
       base::FilePath().AppendASCII("landing.html"));
   ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
       browser(), redirector, 2);
-  ASSERT_EQ(landing_url,
-            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
+  ASSERT_EQ(
+      landing_url,
+      browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL());
   std::vector<GURL> urls(GetHistoryContents());
-  ASSERT_EQ(2u, urls.size());
+  ASSERT_EQ(1u, urls.size());
   ASSERT_EQ(landing_url, urls[0]);
-  ASSERT_EQ(redirector, urls[1]);
+}
+
+// Cross-site HTTP meta-refresh redirects should only have an entry for the
+// landing page.
+IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, CrossSiteRedirectHistory) {
+  // Use the default embedded_test_server() for this test in order to support a
+  // cross-site redirect.
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL landing_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
+  GURL redirector(embedded_test_server()->GetURL(
+      "bar.com", "/client-redirect?" + landing_url.spec()));
+  ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(browser(),
+                                                            redirector, 2);
+  ASSERT_EQ(
+      landing_url,
+      browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL());
+  std::vector<GURL> urls(GetHistoryContents());
+  ASSERT_EQ(1u, urls.size());
+  ASSERT_EQ(landing_url, urls[0]);
 }
 
 // Verify that navigation brings current page to top of history list.
@@ -609,9 +629,9 @@
   content::WebContents* active_web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_EQ(web_contents, active_web_contents);
-  ASSERT_EQ(history_url, active_web_contents->GetURL());
+  ASSERT_EQ(history_url, active_web_contents->GetVisibleURL());
 
   content::WebContents* second_tab =
       browser()->tab_strip_model()->GetWebContentsAt(1);
-  ASSERT_NE(history_url, second_tab->GetURL());
+  ASSERT_NE(history_url, second_tab->GetVisibleURL());
 }
diff --git a/chrome/browser/metrics/oom/OWNERS b/chrome/browser/metrics/oom/OWNERS
new file mode 100644
index 0000000..cd2293f
--- /dev/null
+++ b/chrome/browser/metrics/oom/OWNERS
@@ -0,0 +1,5 @@
+csharrison@chromium.org
+mariakhomenko@chromium.org
+ssid@chromium.org
+
+# TEAM: memory-dev@chromium.org
diff --git a/chrome/browser/metrics/oom/out_of_memory_reporter.cc b/chrome/browser/metrics/oom/out_of_memory_reporter.cc
new file mode 100644
index 0000000..1695a81b
--- /dev/null
+++ b/chrome/browser/metrics/oom/out_of_memory_reporter.cc
@@ -0,0 +1,109 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/metrics/oom/out_of_memory_reporter.h"
+
+#include "base/logging.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(OutOfMemoryReporter);
+
+OutOfMemoryReporter::~OutOfMemoryReporter() {}
+
+void OutOfMemoryReporter::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void OutOfMemoryReporter::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+OutOfMemoryReporter::OutOfMemoryReporter(content::WebContents* web_contents)
+    : content::WebContentsObserver(web_contents)
+#if defined(OS_ANDROID)
+      ,
+      scoped_observer_(this) {
+  // This adds N async observers for N WebContents, which isn't great but
+  // probably won't be a big problem on Android, where many multiple tabs are
+  // rarer.
+  auto* crash_manager = breakpad::CrashDumpManager::GetInstance();
+  DCHECK(crash_manager);
+  scoped_observer_.Add(crash_manager);
+#else
+{
+#endif
+}
+
+void OutOfMemoryReporter::OnForegroundOOMDetected(const GURL& url,
+                                                  ukm::SourceId source_id) {
+  for (auto& observer : observers_) {
+    observer.OnForegroundOOMDetected(url, source_id);
+  }
+}
+
+void OutOfMemoryReporter::DidFinishNavigation(
+    content::NavigationHandle* handle) {
+  // Only care about main frame navigations that commit to another document.
+  if (!handle->IsInMainFrame() || !handle->HasCommitted() ||
+      handle->IsSameDocument()) {
+    return;
+  }
+  last_committed_source_id_.reset();
+  crashed_render_process_id_ = content::ChildProcessHost::kInvalidUniqueID;
+  if (handle->IsErrorPage())
+    return;
+  last_committed_source_id_ = ukm::ConvertToSourceId(
+      handle->GetNavigationId(), ukm::SourceIdType::NAVIGATION_ID);
+}
+
+void OutOfMemoryReporter::RenderProcessGone(base::TerminationStatus status) {
+  if (!last_committed_source_id_.has_value())
+    return;
+  if (!web_contents()->IsVisible())
+    return;
+
+  crashed_render_process_id_ =
+      web_contents()->GetMainFrame()->GetProcess()->GetID();
+
+// On Android, we care about OOM protected crashes, which are obtained via
+// crash dump analysis. Otherwise we can use the termination status to
+// deterine OOM.
+#if !defined(OS_ANDROID)
+  if (status == base::TERMINATION_STATUS_OOM
+#if defined(OS_CHROMEOS)
+      || status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM
+#endif
+      ) {
+    OnForegroundOOMDetected(web_contents()->GetLastCommittedURL(),
+                            *last_committed_source_id_);
+  }
+#endif  // !defined(OS_ANDROID)
+}
+
+#if defined(OS_ANDROID)
+// This should always be called *after* the associated RenderProcessGone. This
+// is because the crash dump is processed asynchronously on the IO thread in
+// response to RenderProcessHost::ProcessDied, while RenderProcessGone is called
+// synchronously from the call to ProcessDied.
+void OutOfMemoryReporter::OnCrashDumpProcessed(
+    const breakpad::CrashDumpManager::CrashDumpDetails& details) {
+  if (!last_committed_source_id_.has_value())
+    return;
+  // Make sure the crash happened in the correct RPH.
+  if (details.process_host_id != crashed_render_process_id_)
+    return;
+
+  if (details.process_type == content::PROCESS_TYPE_RENDERER &&
+      details.termination_status == base::TERMINATION_STATUS_OOM_PROTECTED &&
+      details.file_size == 0 &&
+      details.app_state ==
+          base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) {
+    OnForegroundOOMDetected(web_contents()->GetLastCommittedURL(),
+                            *last_committed_source_id_);
+  }
+}
+#endif  // defined(OS_ANDROID)
diff --git a/chrome/browser/metrics/oom/out_of_memory_reporter.h b/chrome/browser/metrics/oom/out_of_memory_reporter.h
new file mode 100644
index 0000000..63318f3
--- /dev/null
+++ b/chrome/browser/metrics/oom/out_of_memory_reporter.h
@@ -0,0 +1,72 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_METRICS_OOM_OUT_OF_MEMORY_REPORTER_H_
+#define CHROME_BROWSER_METRICS_OOM_OUT_OF_MEMORY_REPORTER_H_
+
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "base/scoped_observer.h"
+#include "build/build_config.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+#include "content/public/common/child_process_host.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
+#include "url/gurl.h"
+
+#if defined(OS_ANDROID)
+#include "components/crash/content/browser/crash_dump_manager_android.h"
+#endif
+
+// This class listens for OOM notifications from WebContentsObserver and
+// breakpad::CrashDumpManager::Observer methods. It forwards foreground OOM
+// notifications to observers.
+class OutOfMemoryReporter
+    : public content::WebContentsObserver,
+      public content::WebContentsUserData<OutOfMemoryReporter>
+#if defined(OS_ANDROID)
+    ,
+      public breakpad::CrashDumpManager::Observer
+#endif
+{
+ public:
+  class Observer {
+   public:
+    virtual void OnForegroundOOMDetected(const GURL& url,
+                                         ukm::SourceId source_id) = 0;
+  };
+  ~OutOfMemoryReporter() override;
+
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
+ private:
+  friend class content::WebContentsUserData<OutOfMemoryReporter>;
+
+  OutOfMemoryReporter(content::WebContents* web_contents);
+  void OnForegroundOOMDetected(const GURL& url, ukm::SourceId source_id);
+
+  // content::WebContentsObserver:
+  void DidFinishNavigation(content::NavigationHandle* handle) override;
+  void RenderProcessGone(base::TerminationStatus termination_status) override;
+
+// breakpad::CrashDumpManager::Observer:
+#if defined(OS_ANDROID)
+  void OnCrashDumpProcessed(
+      const breakpad::CrashDumpManager::CrashDumpDetails& details) override;
+
+  ScopedObserver<breakpad::CrashDumpManager,
+                 breakpad::CrashDumpManager::Observer>
+      scoped_observer_;
+#endif  // defined(OS_ANDROID)
+
+  base::ObserverList<Observer> observers_;
+
+  base::Optional<ukm::SourceId> last_committed_source_id_;
+  int crashed_render_process_id_ = content::ChildProcessHost::kInvalidUniqueID;
+
+  DISALLOW_COPY_AND_ASSIGN(OutOfMemoryReporter);
+};
+
+#endif  // CHROME_BROWSER_METRICS_OOM_OUT_OF_MEMORY_REPORTER_H_
diff --git a/chrome/browser/metrics/oom/out_of_memory_reporter_browsertest.cc b/chrome/browser/metrics/oom/out_of_memory_reporter_browsertest.cc
new file mode 100644
index 0000000..acaf2b2
--- /dev/null
+++ b/chrome/browser/metrics/oom/out_of_memory_reporter_browsertest.cc
@@ -0,0 +1,73 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/metrics/oom/out_of_memory_reporter.h"
+
+#include <set>
+#include <utility>
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "build/build_config.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/common/url_constants.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/service_manager/embedder/switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+class OutOfMemoryReporterBrowserTest : public InProcessBrowserTest,
+                                       public OutOfMemoryReporter::Observer {
+ public:
+  OutOfMemoryReporterBrowserTest() {}
+  ~OutOfMemoryReporterBrowserTest() override {}
+
+  // InProcessBrowserTest:
+  void SetUp() override {
+    ASSERT_TRUE(embedded_test_server()->Start());
+    InProcessBrowserTest::SetUp();
+  }
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // Disable stack traces during this test since DbgHelp is unreliable in
+    // low-memory conditions (see crbug.com/692564).
+    command_line->AppendSwitch(
+        service_manager::switches::kDisableInProcessStackTraces);
+  }
+
+  // OutOfMemoryReporter::Observer:
+  void OnForegroundOOMDetected(const GURL& url,
+                               ukm::SourceId source_id) override {
+    last_oom_url_ = url;
+  }
+
+ protected:
+  base::Optional<GURL> last_oom_url_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OutOfMemoryReporterBrowserTest);
+};
+
+// No current reliable way to determine OOM on Linux/Mac.
+#if defined(OS_LINUX) || defined(OS_MACOSX)
+#define MAYBE_MemoryExhaust DISABLED_MemoryExhaust
+#else
+#define MAYBE_MemoryExhaust MemoryExhaust
+#endif
+IN_PROC_BROWSER_TEST_F(OutOfMemoryReporterBrowserTest, MAYBE_MemoryExhaust) {
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  OutOfMemoryReporter::FromWebContents(web_contents)->AddObserver(this);
+
+  const GURL crash_url = embedded_test_server()->GetURL("/title1.html");
+  ui_test_utils::NavigateToURL(browser(), crash_url);
+
+  // Careful, this doesn't actually commit the navigation. So, navigating to
+  // this URL will cause an OOM associated with the previous committed URL.
+  ui_test_utils::NavigateToURL(browser(),
+                               GURL(content::kChromeUIMemoryExhaustURL));
+  EXPECT_EQ(crash_url, last_oom_url_.value());
+}
diff --git a/chrome/browser/metrics/oom/out_of_memory_reporter_unittest.cc b/chrome/browser/metrics/oom/out_of_memory_reporter_unittest.cc
new file mode 100644
index 0000000..d30ae2f
--- /dev/null
+++ b/chrome/browser/metrics/oom/out_of_memory_reporter_unittest.cc
@@ -0,0 +1,204 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/metrics/oom/out_of_memory_reporter.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/scoped_file.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "base/process/kill.h"
+#include "base/run_loop.h"
+#include "base/task_scheduler/post_task.h"
+#include "build/build_config.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
+#include "net/base/net_errors.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+#if defined(OS_ANDROID)
+#include "chrome/common/descriptors_android.h"
+#include "components/crash/content/browser/child_process_crash_observer_android.h"
+#include "components/crash/content/browser/crash_dump_manager_android.h"
+#include "components/crash/content/browser/crash_dump_observer_android.h"
+#endif
+
+#if defined(OS_ANDROID)
+// This class listens for notifications that crash dumps have been processed.
+// Notifications will come from all crashes, even if an associated crash dump
+// was not created. On destruction, waits for a crash dump message.
+class CrashDumpWaiter : public breakpad::CrashDumpManager::Observer {
+ public:
+  CrashDumpWaiter() {
+    breakpad::CrashDumpManager::GetInstance()->AddObserver(this);
+  }
+  ~CrashDumpWaiter() {
+    base::RunLoop run_loop;
+    wait_closure_ = run_loop.QuitClosure();
+    run_loop.Run();
+    breakpad::CrashDumpManager::GetInstance()->RemoveObserver(this);
+  }
+
+ private:
+  // CrashDumpManager::Observer:
+  void OnCrashDumpProcessed(
+      const breakpad::CrashDumpManager::CrashDumpDetails& details) override {
+    if (!wait_closure_.is_null())
+      std::move(wait_closure_).Run();
+  }
+
+  base::OnceClosure wait_closure_;
+  DISALLOW_COPY_AND_ASSIGN(CrashDumpWaiter);
+};
+#endif  // defined(OS_ANDROID)
+
+class OutOfMemoryReporterTest : public ChromeRenderViewHostTestHarness,
+                                public OutOfMemoryReporter::Observer {
+ public:
+  OutOfMemoryReporterTest() {}
+  ~OutOfMemoryReporterTest() override {}
+
+  // ChromeRenderViewHostTestHarness:
+  void SetUp() override {
+    ChromeRenderViewHostTestHarness::SetUp();
+    EXPECT_NE(content::ChildProcessHost::kInvalidUniqueID, process()->GetID());
+#if defined(OS_ANDROID)
+    ASSERT_TRUE(breakpad::CrashDumpManager::GetInstance());
+    breakpad::CrashDumpObserver::Create();
+    breakpad::CrashDumpObserver::GetInstance()->RegisterClient(
+        std::make_unique<breakpad::ChildProcessCrashObserver>(
+            base::FilePath(), kAndroidMinidumpDescriptor));
+
+    // Simulate a call to ChildStart and create an empty crash dump.
+    base::PostTaskWithTraits(
+        FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
+        base::Bind(base::IgnoreResult(
+                       &breakpad::CrashDumpManager::CreateMinidumpFileForChild),
+                   base::Unretained(breakpad::CrashDumpManager::GetInstance()),
+                   process()->GetID()));
+#endif
+    OutOfMemoryReporter::CreateForWebContents(web_contents());
+    OutOfMemoryReporter::FromWebContents(web_contents())->AddObserver(this);
+  }
+
+  // OutOfMemoryReporter::Observer:
+  void OnForegroundOOMDetected(const GURL& url,
+                               ukm::SourceId source_id) override {
+    last_oom_url_ = url;
+    if (!oom_closure_.is_null())
+      std::move(oom_closure_).Run();
+  }
+
+  void SimulateOOM() {
+#if defined(OS_ANDROID)
+    process()->SimulateRenderProcessExit(base::TERMINATION_STATUS_OOM_PROTECTED,
+                                         0);
+#elif defined(OS_CHROMEOS)
+    process()->SimulateRenderProcessExit(
+        base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM, 0);
+#else
+    process()->SimulateRenderProcessExit(base::TERMINATION_STATUS_OOM, 0);
+#endif
+  }
+
+  void RunClosureAndWaitForNotification(base::OnceClosure closure) {
+#if defined(OS_ANDROID)
+    {
+      CrashDumpWaiter crash_waiter;
+      std::move(closure).Run();
+    }
+    // Since the observer list is not ordered, it isn't guaranteed that the
+    // OutOfMemoryReporter will be notified at this point. However, we do know
+    // the task to notify the reporter will be posted, so just pump the run loop
+    // here.
+    base::RunLoop().RunUntilIdle();
+#else
+    // No need to wait on non-android platforms. The message will be
+    // synchronous.
+    std::move(closure).Run();
+#endif
+  }
+
+  void SimulateOOMAndWait() {
+    RunClosureAndWaitForNotification(base::BindOnce(
+        &OutOfMemoryReporterTest::SimulateOOM, base::Unretained(this)));
+  }
+
+ protected:
+  base::ShadowingAtExitManager at_exit_;
+
+  base::Optional<GURL> last_oom_url_;
+  base::OnceClosure oom_closure_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OutOfMemoryReporterTest);
+};
+
+TEST_F(OutOfMemoryReporterTest, SimpleOOM) {
+  const GURL url("https://example.test/");
+  NavigateAndCommit(url);
+
+  SimulateOOMAndWait();
+  EXPECT_EQ(url, last_oom_url_.value());
+}
+
+TEST_F(OutOfMemoryReporterTest, NormalCrash_NoOOM) {
+  const GURL url("https://example.test/");
+  NavigateAndCommit(url);
+  RunClosureAndWaitForNotification(
+      base::BindOnce(&content::MockRenderProcessHost::SimulateRenderProcessExit,
+                     base::Unretained(process()),
+                     base::TERMINATION_STATUS_ABNORMAL_TERMINATION, 0));
+  EXPECT_FALSE(last_oom_url_.has_value());
+}
+
+TEST_F(OutOfMemoryReporterTest, SubframeNavigation_IsNotLogged) {
+  const GURL url("https://example.test/");
+  NavigateAndCommit(url);
+
+  // Navigate a subframe, make sure it isn't the navigation that is logged.
+  const GURL subframe_url("https://subframe.test/");
+  auto* subframe =
+      content::RenderFrameHostTester::For(main_rfh())->AppendChild("subframe");
+  subframe = content::NavigationSimulator::NavigateAndCommitFromDocument(
+      subframe_url, subframe);
+  EXPECT_TRUE(subframe);
+
+  SimulateOOMAndWait();
+  EXPECT_EQ(last_oom_url_.value(), url);
+}
+
+TEST_F(OutOfMemoryReporterTest, OOMOnPreviousPage) {
+  const GURL url1("https://example.test1/");
+  const GURL url2("https://example.test2/");
+  const GURL url3("https://example.test2/");
+  NavigateAndCommit(url1);
+  NavigateAndCommit(url2);
+
+  // Should not commit.
+  content::NavigationSimulator::NavigateAndFailFromBrowser(web_contents(), url3,
+                                                           net::ERR_ABORTED);
+  SimulateOOMAndWait();
+  EXPECT_EQ(url2, last_oom_url_.value());
+
+  last_oom_url_.reset();
+  NavigateAndCommit(url1);
+
+  // Should navigate to an error page.
+  content::NavigationSimulator::NavigateAndFailFromBrowser(
+      web_contents(), url3, net::ERR_CONNECTION_RESET);
+  // Don't report OOMs on error pages.
+  SimulateOOMAndWait();
+  EXPECT_FALSE(last_oom_url_.has_value());
+}
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
index 4e19cb97..ec69add 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
@@ -476,17 +476,17 @@
                         timing.paint_timing->first_meaningful_paint.value() -
                             timing.parse_timing->parse_start.value());
     RecordFirstMeaningfulPaintStatus(internal::FIRST_MEANINGFUL_PAINT_RECORDED);
-
-    if (WasStartedInBackgroundOptionalEventInForeground(
-            timing.paint_timing->first_meaningful_paint, info)) {
-      PAGE_LOAD_HISTOGRAM(internal::kHistogramForegroundToFirstMeaningfulPaint,
-                          timing.paint_timing->first_meaningful_paint.value() -
-                              info.first_foreground_time.value());
-    }
   } else {
     RecordFirstMeaningfulPaintStatus(
         internal::FIRST_MEANINGFUL_PAINT_BACKGROUNDED);
   }
+
+  if (WasStartedInBackgroundOptionalEventInForeground(
+          timing.paint_timing->first_meaningful_paint, info)) {
+    PAGE_LOAD_HISTOGRAM(internal::kHistogramForegroundToFirstMeaningfulPaint,
+                        timing.paint_timing->first_meaningful_paint.value() -
+                            info.first_foreground_time.value());
+  }
 }
 
 void CorePageLoadMetricsObserver::OnParseStart(
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
index 869132b..b6cf9722 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
@@ -45,6 +45,8 @@
 extern const char kHistogramPageTimingForegroundDuration[];
 extern const char kHistogramPageTimingForegroundDurationNoCommit[];
 
+extern const char kHistogramForegroundToFirstMeaningfulPaint[];
+
 extern const char kRapporMetricsNameCoarseTiming[];
 extern const char kHistogramFirstMeaningfulPaintStatus[];
 
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
index 26d58a77..504aa41 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
@@ -738,3 +738,25 @@
       internal::kHistogramFirstMeaningfulPaintStatus,
       internal::FIRST_MEANINGFUL_PAINT_RECORDED, 1);
 }
+
+TEST_F(CorePageLoadMetricsObserverTest, ForegroundToFirstMeaningfulPaint) {
+  page_load_metrics::mojom::PageLoadTiming timing;
+  page_load_metrics::InitPageLoadTimingForTest(&timing);
+  timing.navigation_start = base::Time::FromDoubleT(1);
+  timing.paint_timing->first_meaningful_paint = base::TimeDelta::FromSeconds(2);
+  PopulateRequiredTimingFields(&timing);
+
+  // Simulate "Open link in new tab."
+  web_contents()->WasHidden();
+  NavigateAndCommit(GURL(kDefaultTestUrl));
+
+  // First Meaningful Paint happens after tab is foregrounded.
+  web_contents()->WasShown();
+  SimulateTimingUpdate(timing);
+
+  // Navigate again to force histogram recording.
+  NavigateAndCommit(GURL(kDefaultTestUrl2));
+
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramForegroundToFirstMeaningfulPaint, 1);
+}
diff --git a/chrome/browser/resources/interventions_internals/index.css b/chrome/browser/resources/interventions_internals/index.css
index ea23ebb..e4f90a0 100644
--- a/chrome/browser/resources/interventions_internals/index.css
+++ b/chrome/browser/resources/interventions_internals/index.css
@@ -10,7 +10,21 @@
 }
 
 button {
-  margin-bottom: 5px;
+  background: rgb(53, 106, 222);
+  border-radius: 5px;
+  box-shadow: 2px silver;
+  color: white;
+  font-size: 65%;
+  font-weight: bold;
+  margin: 5px 0;
+  padding: 5px;
+  text-align: center;
+  text-decoration: none;
+  text-transform: uppercase;
+}
+
+#clear-log-button {
+  float: right;
 }
 
 .hidden-tab {
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index 8dd5baff..9e2cb9b1 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -17,8 +17,8 @@
    * values in most_visited_single.css. */
   --mv-tiles-height: calc(
       4px + var(--tile-height) + var(--tile-margin) + var(--tile-height) + 8px);
-  /* Base height 16px, plus 10px each of padding on top and bottom. */
-  --mv-notice-height: calc(10px + 16px + 10px);
+  /* Base height 16px, plus 8px each of padding on top and bottom. */
+  --mv-notice-height: calc(8px + 16px + 8px);
   height: 100%;
 }
 
@@ -412,7 +412,7 @@
   font-size: 12px;
   font-weight: bold;
   opacity: 1;
-  padding: 10px 0;
+  padding: 8px 0;
 }
 
 #mv-notice span {
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.css b/chrome/browser/resources/local_ntp/most_visited_single.css
index 269b786..6e51f66f 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.css
+++ b/chrome/browser/resources/local_ntp/most_visited_single.css
@@ -70,11 +70,11 @@
   width: var(--tile-width);
 }
 
-/* Min height for showing 1 row: 4px + 128px */
-/* Min height for showing 2 rows: 4px + 128px + 16px + 128px */
+/* Min height for showing 1 row: 4px + 128px + 8px */
+/* Min height for showing 2 rows: 4px + 128px + 16px + 128px + 8px */
 
 /* Minimal layout: 1 row, 2 columns; only first 2 tiles are visible. */
-@media (min-height: 132px) {
+@media (min-height: 140px) {
   .mv-tile:nth-child(-n+2),
   .mv-empty-tile:nth-child(-n+2) {
     display: inline-block;
@@ -83,7 +83,7 @@
 
 /* width >= (3 cols * (16px + 154px))
  * 1 row, 3 columns; first 3 tiles are visible. */
-@media (min-height: 132px) and (min-width: 510px) {
+@media (min-height: 140px) and (min-width: 510px) {
   .mv-tile:nth-child(-n+3),
   .mv-empty-tile:nth-child(-n+3) {
     display: inline-block;
@@ -92,7 +92,7 @@
 
 /* width >= (4 cols * (16px + 154px))
  * 1 row, 4 columns; first 4 tiles are visible. */
-@media (min-height: 132px) and (min-width: 680px) {
+@media (min-height: 140px) and (min-width: 680px) {
   .mv-tile:nth-child(-n+4),
   .mv-empty-tile:nth-child(-n+4) {
     display: inline-block;
@@ -100,7 +100,7 @@
 }
 
 /* 2 rows, 2 columns; only first 4 tiles are visible. */
-@media (min-height: 276px) {
+@media (min-height: 284px) {
   .mv-tile:nth-child(-n+4),
   .mv-empty-tile:nth-child(-n+4) {
     display: inline-block;
@@ -109,7 +109,7 @@
 
 /* width >= (3 cols * (16px + 154px))
  * 2 rows, 3 columns; first 6 tiles are visible. */
-@media (min-height: 276px) and (min-width: 510px) {
+@media (min-height: 284px) and (min-width: 510px) {
   .mv-tile:nth-child(-n+6),
   .mv-empty-tile:nth-child(-n+6) {
     display: inline-block;
@@ -118,7 +118,7 @@
 
 /* width >= (4 cols * (16px + 154px))
  * 2 rows, 4 columns; first 8 tiles are visible. */
-@media (min-height: 276px) and (min-width: 680px) {
+@media (min-height: 284px) and (min-width: 680px) {
   .mv-tile:nth-child(-n+8),
   .mv-empty-tile:nth-child(-n+8) {
     display: inline-block;
diff --git a/chrome/browser/resources/settings/internet_page/internet_config.html b/chrome/browser/resources/settings/internet_page/internet_config.html
index 95e63e4..8d555df 100644
--- a/chrome/browser/resources/settings/internet_page/internet_config.html
+++ b/chrome/browser/resources/settings/internet_page/internet_config.html
@@ -25,7 +25,7 @@
             enable-connect="{{enableConnect_}}" enable-save="{{enableSave_}}"
             share-allow-enable="[[shareAllowEnable_]]"
             share-default="[[shareDefault_]]"
-            on-close="close_">
+            on-close="close">
         </network-config>
       </div>
 
diff --git a/chrome/browser/sync/test/integration/bookmarks_helper.cc b/chrome/browser/sync/test/integration/bookmarks_helper.cc
index f94d7a2..08ebdd52 100644
--- a/chrome/browser/sync/test/integration/bookmarks_helper.cc
+++ b/chrome/browser/sync/test/integration/bookmarks_helper.cc
@@ -90,7 +90,6 @@
     wait_for_load_ = true;
     content::RunMessageLoop();
     ASSERT_TRUE(node_->is_favicon_loaded());
-    ASSERT_FALSE(model_->GetFavicon(node_).IsEmpty());
   }
   void WaitForSetFavicon() {
     wait_for_load_ = false;
@@ -278,16 +277,46 @@
   favicon_service->SetFaviconOutOfDateForPage(node->url());
 }
 
-// Called asynchronously from CheckFaviconExpired() with the favicon data from
-// the database.
-void OnGotFaviconForExpiryCheck(
+// Used to call FaviconService APIs synchronously by making |callback| quit a
+// RunLoop.
+void OnGotFaviconData(
     const base::Closure& callback,
+    favicon_base::FaviconRawBitmapResult* output_bitmap_result,
     const favicon_base::FaviconRawBitmapResult& bitmap_result) {
-  ASSERT_TRUE(bitmap_result.is_valid());
-  ASSERT_TRUE(bitmap_result.expired);
+  *output_bitmap_result = bitmap_result;
   callback.Run();
 }
 
+// Deletes favicon mappings for |profile| and |node|. |profile| may be
+// |test()->verifier()|.
+void DeleteFaviconMappingsImpl(Profile* profile,
+                               const BookmarkNode* node,
+                               bookmarks_helper::FaviconSource favicon_source) {
+  BookmarkModel* model = BookmarkModelFactory::GetForBrowserContext(profile);
+
+  FaviconChangeObserver observer(model, node);
+  favicon::FaviconService* favicon_service =
+      FaviconServiceFactory::GetForProfile(profile,
+                                           ServiceAccessType::EXPLICIT_ACCESS);
+
+  if (favicon_source == bookmarks_helper::FROM_UI) {
+    favicon_service->DeleteFaviconMappings({node->url()},
+                                           favicon_base::IconType::kFavicon);
+  } else {
+    browser_sync::ProfileSyncService* pss =
+        ProfileSyncServiceFactory::GetForProfile(profile);
+    sync_bookmarks::BookmarkChangeProcessor::ApplyBookmarkFavicon(
+        node, pss->GetSyncClient(), /*icon_url=*/GURL(),
+        scoped_refptr<base::RefCountedString>(new base::RefCountedString()));
+  }
+
+  // Wait for the favicon for |node| to be invalidated.
+  observer.WaitForSetFavicon();
+  // Wait for the BookmarkModel to fetch the updated favicon and for the new
+  // favicon to be sent to BookmarkChangeProcessor.
+  GetFaviconData(model, node);
+}
+
 // Wait for all currently scheduled tasks on the history thread for all
 // profiles to complete and any notifications sent to the UI thread to have
 // finished processing.
@@ -633,12 +662,55 @@
           sync_datatype_helper::test()->GetProfile(profile),
           ServiceAccessType::EXPLICIT_ACCESS);
   base::CancelableTaskTracker task_tracker;
+  favicon_base::FaviconRawBitmapResult bitmap_result;
   favicon_service->GetRawFavicon(
       icon_url, favicon_base::IconType::kFavicon, 0,
-      base::Bind(&OnGotFaviconForExpiryCheck, run_loop.QuitClosure()),
+      base::Bind(&OnGotFaviconData, run_loop.QuitClosure(), &bitmap_result),
       &task_tracker);
-
   run_loop.Run();
+
+  ASSERT_TRUE(bitmap_result.is_valid());
+  ASSERT_TRUE(bitmap_result.expired);
+}
+
+void CheckHasNoFavicon(int profile, const GURL& page_url) {
+  base::RunLoop run_loop;
+
+  favicon::FaviconService* favicon_service =
+      FaviconServiceFactory::GetForProfile(
+          sync_datatype_helper::test()->GetProfile(profile),
+          ServiceAccessType::EXPLICIT_ACCESS);
+  base::CancelableTaskTracker task_tracker;
+  favicon_base::FaviconRawBitmapResult bitmap_result;
+  favicon_service->GetRawFaviconForPageURL(
+      page_url, {favicon_base::IconType::kFavicon}, 0,
+      base::Bind(&OnGotFaviconData, run_loop.QuitClosure(), &bitmap_result),
+      &task_tracker);
+  run_loop.Run();
+
+  ASSERT_FALSE(bitmap_result.is_valid());
+}
+
+void DeleteFaviconMappings(int profile,
+                           const BookmarkNode* node,
+                           FaviconSource favicon_source) {
+  BookmarkModel* model = GetBookmarkModel(profile);
+  ASSERT_EQ(bookmarks::GetBookmarkNodeByID(model, node->id()), node)
+      << "Node " << node->GetTitle() << " does not belong to "
+      << "Profile " << profile;
+  ASSERT_EQ(BookmarkNode::URL, node->type())
+      << "Node " << node->GetTitle() << " must be a url.";
+
+  if (sync_datatype_helper::test()->use_verifier()) {
+    const BookmarkNode* v_node = nullptr;
+    FindNodeInVerifier(model, node, &v_node);
+    DeleteFaviconMappingsImpl(sync_datatype_helper::test()->verifier(), v_node,
+                              favicon_source);
+  }
+  DeleteFaviconMappingsImpl(sync_datatype_helper::test()->GetProfile(profile),
+                            node, favicon_source);
+
+  WaitForHistoryToProcessPendingTasks();
 }
 
 const BookmarkNode* SetURL(int profile,
diff --git a/chrome/browser/sync/test/integration/bookmarks_helper.h b/chrome/browser/sync/test/integration/bookmarks_helper.h
index 115de8e..a149ed80 100644
--- a/chrome/browser/sync/test/integration/bookmarks_helper.h
+++ b/chrome/browser/sync/test/integration/bookmarks_helper.h
@@ -115,6 +115,14 @@
 // Checks whether the favicon at |icon_url| for |profile| is expired;
 void CheckFaviconExpired(int profile, const GURL& icon_url);
 
+// Deletes the favicon mappings for |node| in the bookmark model for |profile|.
+void DeleteFaviconMappings(int profile,
+                           const bookmarks::BookmarkNode* node,
+                           FaviconSource favicon_source);
+
+// Checks whether |page_url| for |profile| has no favicon mappings.
+void CheckHasNoFavicon(int profile, const GURL& page_url);
+
 // Changes the url of the node |node| in the bookmark model of profile
 // |profile| to |new_url|. Returns a pointer to the node with the changed url.
 const bookmarks::BookmarkNode* SetURL(int profile,
diff --git a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
index 751b14b..f31e6fba 100644
--- a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
@@ -22,10 +22,12 @@
 using bookmarks::BookmarkNode;
 using bookmarks_helper::AddFolder;
 using bookmarks_helper::AddURL;
+using bookmarks_helper::CheckHasNoFavicon;
 using bookmarks_helper::CountBookmarksWithTitlesMatching;
 using bookmarks_helper::CountBookmarksWithUrlsMatching;
 using bookmarks_helper::CountFoldersWithTitlesMatching;
 using bookmarks_helper::Create1xFaviconFromPNGFile;
+using bookmarks_helper::CreateFavicon;
 using bookmarks_helper::GetBookmarkBarNode;
 using bookmarks_helper::GetBookmarkModel;
 using bookmarks_helper::GetOtherNode;
@@ -267,6 +269,34 @@
   EXPECT_TRUE(original_favicon_bytes->Equals(final_favicon_bytes));
 }
 
+// Test that a client deletes favicons from sync when they have been removed
+// from the local database.
+IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest, DeleteFaviconFromSync) {
+  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(ModelMatchesVerifier(kSingleProfileIndex));
+
+  const GURL page_url("http://www.google.com");
+  const GURL icon_url("http://www.google.com/favicon.ico");
+  const BookmarkNode* bookmark = AddURL(kSingleProfileIndex, "title", page_url);
+  SetFavicon(0, bookmark, icon_url, CreateFavicon(SK_ColorWHITE),
+             bookmarks_helper::FROM_UI);
+  ASSERT_TRUE(
+      UpdatedProgressMarkerChecker(GetSyncService(kSingleProfileIndex)).Wait());
+  ASSERT_TRUE(ModelMatchesVerifier(kSingleProfileIndex));
+
+  // Simulate receiving a favicon deletion from sync.
+  DeleteFaviconMappings(kSingleProfileIndex, bookmark,
+                        bookmarks_helper::FROM_SYNC);
+
+  ASSERT_TRUE(
+      UpdatedProgressMarkerChecker(GetSyncService(kSingleProfileIndex)).Wait());
+  ASSERT_TRUE(ModelMatchesVerifier(kSingleProfileIndex));
+
+  CheckHasNoFavicon(kSingleProfileIndex, page_url);
+  EXPECT_TRUE(
+      GetBookmarkModel(kSingleProfileIndex)->GetFavicon(bookmark).IsEmpty());
+}
+
 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest,
                        BookmarkAllNodesRemovedEvent) {
   ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
diff --git a/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
index f2aacf1..537f07ec 100644
--- a/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
@@ -37,12 +37,14 @@
 using bookmarks_helper::AllModelsMatch;
 using bookmarks_helper::AllModelsMatchVerifier;
 using bookmarks_helper::CheckFaviconExpired;
+using bookmarks_helper::CheckHasNoFavicon;
 using bookmarks_helper::ContainsDuplicateBookmarks;
 using bookmarks_helper::CountAllBookmarks;
 using bookmarks_helper::CountBookmarksWithTitlesMatching;
 using bookmarks_helper::CountBookmarksWithUrlsMatching;
 using bookmarks_helper::CountFoldersWithTitlesMatching;
 using bookmarks_helper::CreateFavicon;
+using bookmarks_helper::DeleteFaviconMappings;
 using bookmarks_helper::ExpireFavicon;
 using bookmarks_helper::GetBookmarkBarNode;
 using bookmarks_helper::GetManagedNode;
@@ -306,6 +308,35 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
+IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_DeleteFavicon) {
+  const GURL page_url("http://www.google.com/a");
+  const GURL icon_url("http://www.google.com/favicon.ico");
+
+  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(AllModelsMatchVerifier());
+
+  const BookmarkNode* bookmark0 = AddURL(0, kGenericURLTitle, page_url);
+  ASSERT_NE(nullptr, bookmark0);
+
+  SetFavicon(0, bookmark0, icon_url, CreateFavicon(SK_ColorWHITE),
+             bookmarks_helper::FROM_UI);
+  ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
+
+  DeleteFaviconMappings(0, bookmark0, bookmarks_helper::FROM_UI);
+  ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
+
+  // Set the title for |page_url|. This should not revert the deletion of
+  // favicon mappings.
+  const char kNewTitle[] = "New Title";
+  ASSERT_STRNE(kGenericURLTitle, kNewTitle);
+  const BookmarkNode* bookmark1 = GetUniqueNodeByURL(1, page_url);
+  SetTitle(1, bookmark1, std::string(kNewTitle));
+  ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
+
+  // |page_url| should still have no mapping.
+  CheckHasNoFavicon(0, page_url);
+}
+
 IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_AddNonHTTPBMs) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
diff --git a/chrome/browser/translate/translate_browsertest.cc b/chrome/browser/translate/translate_browsertest.cc
index 503193d9..76257a7 100644
--- a/chrome/browser/translate/translate_browsertest.cc
+++ b/chrome/browser/translate/translate_browsertest.cc
@@ -290,13 +290,16 @@
       kRefreshMetaTagAtOnloadTestPath, false));
 }
 
-IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, UpdateLocation) {
-  ASSERT_NO_FATAL_FAILURE(CheckForTranslateUI(
-      kUpdateLocationTestPath, false));
+// TODO(toyoshim, creis): The infobar should be dismissed on client redirects.
+// See https://crbug.com/781879.
+IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, DISABLED_UpdateLocation) {
+  ASSERT_NO_FATAL_FAILURE(CheckForTranslateUI(kUpdateLocationTestPath, false));
 }
 
-IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, UpdateLocationAtOnload) {
-  ASSERT_NO_FATAL_FAILURE(CheckForTranslateUI(
-      kUpdateLocationAtOnloadTestPath, false));
+// TODO(toyoshim, creis): The infobar should be dismissed on client redirects.
+// See https://crbug.com/781879.
+IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, DISABLED_UpdateLocationAtOnload) {
+  ASSERT_NO_FATAL_FAILURE(
+      CheckForTranslateUI(kUpdateLocationAtOnloadTestPath, false));
 }
 #endif  // !defined(USE_AURA)
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc
index ab0565f0..fefd06e 100644
--- a/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc
@@ -38,10 +38,8 @@
   // Make the newly active window the active (first) entry in the controller.
   AppWindowLauncherItemController* new_controller =
       ControllerForWindow(new_active);
-  if (new_controller) {
+  if (new_controller)
     new_controller->SetActiveWindow(new_active);
-    owner_->SetItemStatus(new_controller->shelf_id(), ash::STATUS_ACTIVE);
-  }
 
   // Mark the old active window's launcher item as running (if different).
   AppWindowLauncherItemController* old_controller =
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
index 6367587..9a5ce99 100644
--- a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
@@ -138,9 +138,9 @@
     intptr_t old) {
   if (key == aura::client::kDrawAttentionKey) {
     ash::ShelfItemStatus status;
-    if (wm::IsActiveWindow(window)) {
-      status = ash::STATUS_ACTIVE;
-    } else if (window->GetProperty(aura::client::kDrawAttentionKey)) {
+    // Active windows don't draw attention because the user is looking at them.
+    if (window->GetProperty(aura::client::kDrawAttentionKey) &&
+        !wm::IsActiveWindow(window)) {
       status = ash::STATUS_ATTENTION;
     } else {
       status = ash::STATUS_RUNNING;
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
index 1aae31a..aed2c57b 100644
--- a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
@@ -65,6 +65,7 @@
  protected:
   explicit AppWindowLauncherItemController(const ash::ShelfID& shelf_id);
 
+ private:
   // Returns the action performed. Should be one of SHELF_ACTION_NONE,
   // SHELF_ACTION_WINDOW_ACTIVATED, or SHELF_ACTION_WINDOW_MINIMIZED.
   ash::ShelfAction ShowAndActivateOrMinimize(ui::BaseWindow* window);
@@ -79,7 +80,6 @@
   // Returns last active window in the controller or first window.
   ui::BaseWindow* GetLastActiveWindow();
 
- private:
   WindowList::iterator GetFromNativeWindow(aura::Window* window);
 
   // Handles the case when the app window in this controller has been changed,
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
index 4b7f7ec8..cb19e54cb 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
@@ -452,14 +452,10 @@
   ArcAppWindow* current_app_window = GetAppWindowForTask(task_id);
   if (current_app_window) {
     if (current_app_window->widget() && current_app_window->IsActive()) {
-      owner()->SetItemStatus(current_app_window->shelf_id(),
-                             ash::STATUS_ACTIVE);
       current_app_window->controller()->SetActiveWindow(
           current_app_window->GetNativeWindow());
-    } else {
-      owner()->SetItemStatus(current_app_window->shelf_id(),
-                             ash::STATUS_RUNNING);
     }
+    owner()->SetItemStatus(current_app_window->shelf_id(), ash::STATUS_RUNNING);
     // TODO(reveman): Figure out how to support fullscreen in interleaved
     // window mode.
     // if (new_active_app_it->second->widget()) {
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
index 7ac8dbe..c6bec804 100644
--- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -127,30 +127,10 @@
   DCHECK_GE(browser_index, 0);
   ash::ShelfItem browser_item = shelf_model_->items()[browser_index];
   ash::ShelfItemStatus browser_status = ash::STATUS_CLOSED;
-
-  Browser* browser = BrowserList::GetInstance()->GetLastActive();
-  if (browser && browser->window()->IsActive() &&
-      IsBrowserRepresentedInBrowserList(browser)) {
-    // Check if the active browser / tab is a browser which is not an app,
-    // a windowed app, a popup or any other item which is not a browser of
-    // interest.
-    browser_status = ash::STATUS_ACTIVE;
-    // If an app that has item is running in active WebContents, browser item
-    // status cannot be active.
-    content::WebContents* contents =
-        browser->tab_strip_model()->GetActiveWebContents();
-    if (contents &&
-        (ChromeLauncherController::instance()->GetShelfIDForWebContents(
-             contents) != browser_item.id))
+  for (auto* browser : *BrowserList::GetInstance()) {
+    if (IsBrowserRepresentedInBrowserList(browser)) {
       browser_status = ash::STATUS_RUNNING;
-  }
-
-  if (browser_status == ash::STATUS_CLOSED) {
-    for (auto* browser : *BrowserList::GetInstance()) {
-      if (IsBrowserRepresentedInBrowserList(browser)) {
-        browser_status = ash::STATUS_RUNNING;
-        break;
-      }
+      break;
     }
   }
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index d9fba53..37e4c0ff 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -473,10 +473,7 @@
   else
     web_contents_to_app_id_[contents] = shelf_id.app_id;
 
-  SetItemStatus(shelf_id, (app_state == APP_STATE_WINDOW_ACTIVE ||
-                           app_state == APP_STATE_ACTIVE)
-                              ? ash::STATUS_ACTIVE
-                              : GetAppState(shelf_id.app_id));
+  SetItemStatus(shelf_id, GetAppState(shelf_id.app_id));
 }
 
 ash::ShelfID ChromeLauncherController::GetShelfIDForWebContents(
@@ -1057,26 +1054,19 @@
 
 ash::ShelfItemStatus ChromeLauncherController::GetAppState(
     const std::string& app_id) {
-  ash::ShelfItemStatus status = ash::STATUS_CLOSED;
-  for (WebContentsToAppIDMap::iterator it = web_contents_to_app_id_.begin();
-       it != web_contents_to_app_id_.end(); ++it) {
-    if (it->second == app_id) {
-      Browser* browser = chrome::FindBrowserWithWebContents(it->first);
+  for (auto& it : web_contents_to_app_id_) {
+    if (it.second == app_id) {
+      Browser* browser = chrome::FindBrowserWithWebContents(it.first);
       // Usually there should never be an item in our |web_contents_to_app_id_|
       // list which got deleted already. However - in some situations e.g.
       // Browser::SwapTabContent there is temporarily no associated browser.
+      // TODO(jamescook): This test may not be necessary anymore.
       if (!browser)
         continue;
-      if (browser->window()->IsActive()) {
-        return browser->tab_strip_model()->GetActiveWebContents() == it->first
-                   ? ash::STATUS_ACTIVE
-                   : ash::STATUS_RUNNING;
-      } else {
-        status = ash::STATUS_RUNNING;
-      }
+      return ash::STATUS_RUNNING;
     }
   }
-  return status;
+  return ash::STATUS_CLOSED;
 }
 
 ash::ShelfID ChromeLauncherController::InsertAppLauncherItem(
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
index c7385191..8a369d64 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -316,8 +316,7 @@
   void SetVirtualKeyboardBehaviorFromPrefs();
 
   // Returns the shelf item status for the given |app_id|, which can be either
-  // STATUS_ACTIVE (if the app is active), STATUS_RUNNING (if there is such an
-  // app) or STATUS_CLOSED.
+  // STATUS_RUNNING (if there is such an app) or STATUS_CLOSED.
   ash::ShelfItemStatus GetAppState(const std::string& app_id);
 
   // Creates an app launcher to insert at |index|. Note that |index| may be
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
index 8ac8f15c..d0f3230 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -368,7 +368,7 @@
   ASSERT_EQ(item_count, shelf_model()->item_count());
   const ash::ShelfItem& item = GetLastLauncherItem();
   EXPECT_EQ(ash::TYPE_APP, item.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
   CloseAppWindow(window);
   --item_count;
   EXPECT_EQ(item_count, shelf_model()->item_count());
@@ -397,7 +397,7 @@
   ASSERT_EQ(item_count, shelf_model()->item_count());
   item = *shelf_model()->ItemByID(shortcut_id);
   EXPECT_EQ(ash::TYPE_PINNED_APP, item.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
 
   // Then close it, make sure there's still an item.
   CloseAppWindow(window);
@@ -417,7 +417,7 @@
   const ash::ShelfItem& item1 = GetLastLauncherItem();
   ash::ShelfID id = item1.id;
   EXPECT_EQ(ash::TYPE_APP, item1.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
 
   // Create a shortcut. The app item should be after it.
   ash::ShelfID foo_id = CreateAppShortcutLauncherItem(
@@ -432,7 +432,7 @@
   ASSERT_EQ(item_count, shelf_model()->item_count());
   const ash::ShelfItem& item2 = *shelf_model()->ItemByID(id);
   EXPECT_EQ(ash::TYPE_PINNED_APP, item2.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item2.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item2.status);
 
   // New shortcuts should come after the item.
   ash::ShelfID bar_id = CreateAppShortcutLauncherItem(
@@ -478,14 +478,14 @@
   ASSERT_EQ(item_count, shelf_model()->item_count());
   item = *shelf_model()->ItemByID(shortcut_id);
   EXPECT_EQ(ash::TYPE_PINNED_APP, item.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
 
   // Unpin the app. The item should remain.
   controller_->UnpinAppWithID(app_id);
   ASSERT_EQ(item_count, shelf_model()->item_count());
   item = *shelf_model()->ItemByID(shortcut_id);
   EXPECT_EQ(ash::TYPE_APP, item.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
   // The item should have moved after the other shortcuts.
   EXPECT_GT(shelf_model()->ItemIndexByID(shortcut_id),
             shelf_model()->ItemIndexByID(foo_id));
@@ -507,21 +507,21 @@
   const ash::ShelfItem& item1 = GetLastLauncherItem();
   ash::ShelfID item_id = item1.id;
   EXPECT_EQ(ash::TYPE_APP, item1.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
   EXPECT_EQ(1u, controller_->GetAppMenuItemsForTesting(item1).size());
 
   // Add a second window; confirm the shelf item stays; check the app menu.
   AppWindow* window2 = CreateAppWindow(browser()->profile(), extension);
   ASSERT_EQ(item_count + 1, shelf_model()->item_count());
   const ash::ShelfItem& item2 = *shelf_model()->ItemByID(item_id);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item2.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item2.status);
   EXPECT_EQ(2u, controller_->GetAppMenuItemsForTesting(item2).size());
 
   // Close the second window; confirm the shelf item stays; check the app menu.
   CloseAppWindow(window2);
   ASSERT_EQ(item_count + 1, shelf_model()->item_count());
   const ash::ShelfItem& item3 = *shelf_model()->ItemByID(item_id);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item3.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item3.status);
   EXPECT_EQ(1u, controller_->GetAppMenuItemsForTesting(item3).size());
 
   // Close the first window; the shelf item should be removed.
@@ -540,7 +540,7 @@
   const ash::ShelfItem& item1 = GetLastLauncherItem();
   ash::ShelfID item_id1 = item1.id;
   EXPECT_EQ(ash::TYPE_APP, item1.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
 
   // Then run second app.
   const Extension* extension2 =
@@ -551,7 +551,7 @@
   const ash::ShelfItem& item2 = GetLastLauncherItem();
   ash::ShelfID item_id2 = item2.id;
   EXPECT_EQ(ash::TYPE_APP, item2.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item2.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item2.status);
 
   EXPECT_NE(item_id1, item_id2);
   EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(item_id1)->status);
@@ -560,8 +560,8 @@
   CloseAppWindow(window2);
   --item_count;
   ASSERT_EQ(item_count, shelf_model()->item_count());
-  // First app should be active again.
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(item_id1)->status);
+  // First app should still be running.
+  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(item_id1)->status);
 
   // Close first app.
   CloseAppWindow(window1);
@@ -582,7 +582,7 @@
   const ash::ShelfItem& item1 = GetLastLauncherItem();
   ash::ShelfID item_id1 = item1.id;
   EXPECT_EQ(ash::TYPE_APP, item1.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
 
   // Then run second app.
   const Extension* extension2 =
@@ -593,22 +593,18 @@
   const ash::ShelfItem& item2 = GetLastLauncherItem();
   ash::ShelfID item_id2 = item2.id;
   EXPECT_EQ(ash::TYPE_APP, item2.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item2.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item2.status);
 
   EXPECT_NE(item_id1, item_id2);
   EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(item_id1)->status);
 
   // Activate first one.
   SelectItem(item_id1);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(item_id1)->status);
-  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(item_id2)->status);
   EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
   EXPECT_FALSE(window2->GetBaseWindow()->IsActive());
 
   // Activate second one.
   SelectItem(item_id2);
-  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(item_id1)->status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(item_id2)->status);
   EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
   EXPECT_TRUE(window2->GetBaseWindow()->IsActive());
 
@@ -643,8 +639,8 @@
   CloseAppWindow(window2);
   --item_count;
   EXPECT_EQ(item_count, shelf_model()->item_count());
-  // First app should be active again.
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(item_id1)->status);
+  // First app is still running.
+  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(item_id1)->status);
 
   // Close first app.
   CloseAppWindow(window1b);
@@ -665,18 +661,16 @@
   // Confirm that a controller item was created and is the correct state.
   const ash::ShelfItem& item = GetLastLauncherItem();
   EXPECT_EQ(ash::TYPE_APP, item.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
   // Since it is already active, clicking it should minimize.
   SelectItem(item.id);
   EXPECT_FALSE(window1->GetNativeWindow()->IsVisible());
   EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
   EXPECT_TRUE(window1->GetBaseWindow()->IsMinimized());
-  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
   // Clicking the item again should activate the window again.
   SelectItem(item.id);
   EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
   EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
   // Maximizing a window should preserve state after minimize + click.
   window1->GetBaseWindow()->Maximize();
   window1->GetBaseWindow()->Minimize();
@@ -742,7 +736,7 @@
   // Click the item and confirm that the panel is activated.
   EXPECT_EQ(ash::SHELF_ACTION_WINDOW_ACTIVATED, SelectItem(item.id));
   EXPECT_TRUE(panel->GetBaseWindow()->IsActive());
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
   // Click the item again and confirm that the panel is minimized.
   EXPECT_EQ(ash::SHELF_ACTION_WINDOW_MINIMIZED, SelectItem(item.id));
   EXPECT_TRUE(panel->GetBaseWindow()->IsMinimized());
@@ -752,7 +746,7 @@
   EXPECT_TRUE(panel->GetNativeWindow()->IsVisible());
   EXPECT_TRUE(panel->GetBaseWindow()->IsActive());
   EXPECT_FALSE(panel->GetBaseWindow()->IsMinimized());
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
 }
 
 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, BrowserActivation) {
@@ -766,7 +760,7 @@
   const ash::ShelfItem& item = GetLastLauncherItem();
   ash::ShelfID item_id1 = item.id;
   EXPECT_EQ(ash::TYPE_APP, item.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
 
   browser()->window()->Activate();
   EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(item_id1)->status);
@@ -872,7 +866,7 @@
   EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
   SelectItem(shortcut_id);
   EXPECT_EQ(++tab_count, tab_strip->count());
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
+  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
   WebContents* tab = tab_strip->GetActiveWebContents();
   content::WebContentsDestroyedWatcher destroyed_watcher(tab);
   browser()->tab_strip_model()->CloseSelectedTabs();
@@ -978,7 +972,7 @@
                          WindowOpenDisposition::NEW_FOREGROUND_TAB);
   EXPECT_EQ(++tab_count, tab_strip->count());
   ash::ShelfID shortcut_id = CreateShortcut("app1");
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
+  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
   WebContents* tab = tab_strip->GetActiveWebContents();
   content::WebContentsDestroyedWatcher destroyed_watcher(tab);
   browser()->tab_strip_model()->CloseSelectedTabs();
@@ -1017,13 +1011,15 @@
   ash::ShelfID shortcut_id = CreateShortcut("app1");
   SelectItem(shortcut_id);
   EXPECT_EQ(++tab_count, tab_strip->count());
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
-
-  browser()->window()->Activate();
   EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
 
+  // Activate the first browser window.
+  browser()->window()->Activate();
+  EXPECT_FALSE(browser2->window()->IsActive());
+
+  // Selecting the shortcut activates the second window.
   SelectItem(shortcut_id);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
+  EXPECT_TRUE(browser2->window()->IsActive());
 }
 
 // Activating the same app multiple times should launch only a single copy.
@@ -1052,67 +1048,13 @@
   EXPECT_EQ(++tab_count, tab_strip->count());
 }
 
-// Launch 2 apps and toggle which is active.
-IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, MultipleApps) {
-  int item_count = shelf_model()->item_count();
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  int tab_count = tab_strip->count();
-  ash::ShelfID shortcut1 = CreateShortcut("app1");
-  EXPECT_EQ(++item_count, shelf_model()->item_count());
-  ash::ShelfID shortcut2 = CreateShortcut("app2");
-  EXPECT_EQ(++item_count, shelf_model()->item_count());
-
-  // Launch first app.
-  SelectItem(shortcut1);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  WebContents* tab1 = tab_strip->GetActiveWebContents();
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut1)->status);
-
-  // Launch second app.
-  SelectItem(shortcut2);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  WebContents* tab2 = tab_strip->GetActiveWebContents();
-  ASSERT_NE(tab1, tab2);
-  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut1)->status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut2)->status);
-
-  // Reactivate first app.
-  SelectItem(shortcut1);
-  EXPECT_EQ(tab_count, tab_strip->count());
-  EXPECT_EQ(tab_strip->GetActiveWebContents(), tab1);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut1)->status);
-  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut2)->status);
-
-  // Open second tab for second app. This should activate it.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), GURL("http://www.example.com/path3/foo.html"),
-      WindowOpenDisposition::NEW_FOREGROUND_TAB, 0);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut1)->status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut2)->status);
-
-  // Reactivate first app.
-  SelectItem(shortcut1);
-  EXPECT_EQ(tab_count, tab_strip->count());
-  EXPECT_EQ(tab_strip->GetActiveWebContents(), tab1);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut1)->status);
-  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut2)->status);
-
-  // And second again. This time the second tab should become active.
-  SelectItem(shortcut2);
-  EXPECT_EQ(tab_count, tab_strip->count());
-  EXPECT_EQ(tab_strip->GetActiveWebContents(), tab2);
-  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut1)->status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut2)->status);
-}
-
 // Confirm that a page can be navigated from and to while maintaining the
 // correct running state.
 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, Navigation) {
   ash::ShelfID shortcut_id = CreateShortcut("app1");
   EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
   SelectItem(shortcut_id);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
+  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
 
   // Navigate away.
   ui_test_utils::NavigateToURL(browser(),
@@ -1122,7 +1064,7 @@
   // Navigate back.
   ui_test_utils::NavigateToURL(browser(),
                                GURL("http://www.example.com/path1/foo.html"));
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
+  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
 }
 
 // Confirm that a tab can be moved between browsers while maintaining the
@@ -1136,21 +1078,21 @@
 
   // Create a shortcut for app1.
   ash::ShelfID shortcut_id = CreateShortcut("app1");
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->items()[browser_index].status);
+  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->items()[browser_index].status);
   EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
 
   // Activate app1 and check its item status.
   SelectItem(shortcut_id);
   EXPECT_EQ(2, tab_strip_model1->count());
   EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->items()[browser_index].status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
+  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
 
   // Create a new browser with blank tab.
   Browser* browser2 = CreateBrowser(profile());
   EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
   TabStripModel* tab_strip_model2 = browser2->tab_strip_model();
   EXPECT_EQ(1, tab_strip_model2->count());
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->items()[browser_index].status);
+  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->items()[browser_index].status);
   EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
 
   // Detach a tab at index 1 (app1) from |tab_strip_model1| and insert it as an
@@ -1161,79 +1103,12 @@
   EXPECT_EQ(1, tab_strip_model1->count());
   EXPECT_EQ(2, tab_strip_model2->count());
   EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->items()[browser_index].status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
+  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
 
   tab_strip_model1->CloseAllTabs();
   tab_strip_model2->CloseAllTabs();
 }
 
-IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, MultipleOwnedTabs) {
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  int tab_count = tab_strip->count();
-  ash::ShelfID shortcut_id = CreateShortcut("app1");
-  SelectItem(shortcut_id);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
-  WebContents* first_tab = tab_strip->GetActiveWebContents();
-
-  // Create new tab owned by app.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), GURL("http://www.example.com/path2/bar.html"),
-      WindowOpenDisposition::NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  // Confirm app is still active.
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
-
-  // Create new tab not owned by app.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), GURL("http://www.example.com/path3/foo.html"),
-      WindowOpenDisposition::NEW_FOREGROUND_TAB, 0);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  // No longer active.
-  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
-
-  // Activating app makes first tab active again.
-  SelectItem(shortcut_id);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(tab_strip->GetActiveWebContents(), first_tab);
-}
-
-IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, RefocusFilter) {
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  int tab_count = tab_strip->count();
-  ash::ShelfID shortcut_id = CreateShortcut("app1");
-  SelectItem(shortcut_id);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
-  WebContents* first_tab = tab_strip->GetActiveWebContents();
-
-  controller_->SetRefocusURLPatternForTest(
-      shortcut_id, GURL("http://www.example.com/path1/*"));
-  // Create new tab owned by app.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), GURL("http://www.example.com/path2/bar.html"),
-      WindowOpenDisposition::NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  // Confirm app is still active.
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
-
-  // Create new tab not owned by app.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), GURL("http://www.example.com/path3/foo.html"),
-      WindowOpenDisposition::NEW_FOREGROUND_TAB, 0);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  // No longer active.
-  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
-
-  // Activating app makes first tab active again, because second tab isn't
-  // in its refocus url path.
-  SelectItem(shortcut_id);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(tab_strip->GetActiveWebContents(), first_tab);
-}
-
 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, RefocusFilterLaunch) {
   TabStripModel* tab_strip = browser()->tab_strip_model();
   int tab_count = tab_strip->count();
@@ -1256,51 +1131,11 @@
   SelectItem(shortcut_id);
   EXPECT_EQ(++tab_count, tab_strip->count());
   WebContents* second_tab = tab_strip->GetActiveWebContents();
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
+  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
   EXPECT_NE(first_tab, second_tab);
   EXPECT_EQ(tab_strip->GetActiveWebContents(), second_tab);
 }
 
-// Check the launcher activation state for applications and browser.
-IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, ActivationStateCheck) {
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  // Get the browser item index
-  int browser_index = GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT);
-  EXPECT_TRUE(browser_index >= 0);
-
-  // Even though we are just comming up, the browser should be active.
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->items()[browser_index].status);
-
-  ash::ShelfID shortcut_id = CreateShortcut("app1");
-  controller_->SetRefocusURLPatternForTest(
-      shortcut_id, GURL("http://www.example.com/path1/*"));
-
-  EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->items()[browser_index].status);
-
-  // Create new tab which would be the running app.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), GURL("http://www.example.com/path1/bar.html"),
-      WindowOpenDisposition::NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-
-  // There should never be two items active at the same time.
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->items()[browser_index].status);
-
-  tab_strip->ActivateTabAt(0, false);
-  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->items()[browser_index].status);
-
-  tab_strip->CloseWebContentsAt(1, TabStripModel::CLOSE_NONE);
-  EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->items()[browser_index].status);
-
-  browser()->window()->Deactivate();
-  EXPECT_EQ(ash::STATUS_CLOSED, shelf_model()->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->items()[browser_index].status);
-}
-
 // Check that the launcher activation state for a V1 application stays closed
 // even after an asynchronous browser event comes in after the tab got
 // destroyed.
@@ -1319,7 +1154,7 @@
       WindowOpenDisposition::NEW_FOREGROUND_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
 
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(shortcut_id)->status);
+  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
   // To address the issue of crbug.com/174050, the tab we are about to close
   // has to be active.
   tab_strip->ActivateTabAt(1, false);
@@ -1475,7 +1310,7 @@
   const ash::ShelfItem& item = GetLastLauncherItem();
 
   EXPECT_EQ(ash::TYPE_APP, item.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
 
   const Extension* extension2 =
       LoadAndLaunchPlatformApp("launch_2", "Launched");
@@ -1585,11 +1420,10 @@
   // Click the item and confirm that the window is activated.
   EXPECT_EQ(ash::SHELF_ACTION_WINDOW_ACTIVATED, SelectItem(item.id));
   EXPECT_TRUE(window->GetBaseWindow()->IsActive());
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
 
   // Active windows don't show attention.
   window->GetNativeWindow()->SetProperty(aura::client::kDrawAttentionKey, true);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
 }
 
 // Test attention states of panels.
@@ -1620,13 +1454,12 @@
   // Ash updates panel shelf items; spin a run loop to sync Chrome's ShelfModel.
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(panel->GetBaseWindow()->IsActive());
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
 
   // Active windows don't show attention.
   panel->GetNativeWindow()->SetProperty(aura::client::kDrawAttentionKey, true);
   // Ash updates panel shelf items; spin a run loop to sync Chrome's ShelfModel.
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
+  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
 }
 
 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,
@@ -2285,7 +2118,7 @@
       WindowOpenDisposition::NEW_FOREGROUND_TAB, extensions::SOURCE_TEST);
   params.container = extensions::LAUNCH_CONTAINER_WINDOW;
   OpenApplication(params);
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(id)->status);
+  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(id)->status);
 
   // Find the browser which holds our app.
   Browser* app_browser = NULL;
@@ -2305,7 +2138,7 @@
                                GURL("http://www.foo.com/bar.html"));
   // Make sure the navigation was entirely performed.
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(ash::STATUS_ACTIVE, shelf_model()->ItemByID(id)->status);
+  EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(id)->status);
   app_browser->tab_strip_model()->CloseWebContentsAt(0,
                                                      TabStripModel::CLOSE_NONE);
   // Make sure that the app is really gone.
@@ -2379,10 +2212,10 @@
       browser(), extensions::AppLaunchInfo::GetLaunchWebURL(bookmark_app),
       WindowOpenDisposition::NEW_FOREGROUND_TAB, 0);
 
-  // The apps should now be running, with the last opened app active.
+  // The apps should now be running.
   EXPECT_EQ(ash::STATUS_RUNNING,
             shelf_model()->ItemByID(hosted_app_shelf_id)->status);
-  EXPECT_EQ(ash::STATUS_ACTIVE,
+  EXPECT_EQ(ash::STATUS_RUNNING,
             shelf_model()->ItemByID(bookmark_app_shelf_id)->status);
 
   // Now use the launcher controller to activate the apps.
@@ -2443,10 +2276,10 @@
   // There should be two new browsers.
   EXPECT_EQ(3u, chrome::GetBrowserCount(browser()->profile()));
 
-  // The apps should now be running, with the last opened app active.
+  // The apps should now be running.
   EXPECT_EQ(ash::STATUS_RUNNING,
             shelf_model()->ItemByID(hosted_app_shelf_id)->status);
-  EXPECT_EQ(ash::STATUS_ACTIVE,
+  EXPECT_EQ(ash::STATUS_RUNNING,
             shelf_model()->ItemByID(bookmark_app_shelf_id)->status);
 }
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index 0a016df2..d4d85ef 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -1679,10 +1679,10 @@
   EXPECT_NE(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
-  // Reporting an active status should just update the existing item.
-  launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_ACTIVE);
+  // Reporting that the app is running again should have no effect.
+  launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
   EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[2].status);
+  EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[2].status);
 
   // Reporting that the app is closed should remove its shelf item.
   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
diff --git a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc
index 42c81fd..d1da6c74 100644
--- a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc
@@ -143,12 +143,8 @@
   window->AddObserver(this);
 
   // Find or create an item controller and launcher item.
-  ash::ShelfItemStatus status = app_window->GetBaseWindow()->IsActive()
-                                    ? ash::STATUS_ACTIVE
-                                    : ash::STATUS_RUNNING;
   AppControllerMap::iterator app_controller_iter =
       app_controller_map_.find(shelf_id);
-
   if (app_controller_iter != app_controller_map_.end()) {
     ExtensionAppWindowLauncherItemController* controller =
         app_controller_iter->second;
@@ -161,7 +157,8 @@
 
     // Check for any existing pinned shelf item with a matching |shelf_id|.
     if (!owner()->GetItem(shelf_id)) {
-      owner()->CreateAppLauncherItem(std::move(controller), status);
+      owner()->CreateAppLauncherItem(std::move(controller),
+                                     ash::STATUS_RUNNING);
     } else {
       owner()->shelf_model()->SetShelfItemDelegate(shelf_id,
                                                    std::move(controller));
@@ -172,7 +169,7 @@
     app_controller_map_[shelf_id]->AddAppWindow(app_window);
   }
 
-  owner()->SetItemStatus(shelf_id, status);
+  owner()->SetItemStatus(shelf_id, ash::STATUS_RUNNING);
 }
 
 void ExtensionAppWindowLauncherController::UnregisterApp(aura::Window* window) {
diff --git a/chrome/browser/ui/ash/system_tray_client.cc b/chrome/browser/ui/ash/system_tray_client.cc
index aef0b0b0..85ca935 100644
--- a/chrome/browser/ui/ash/system_tray_client.cc
+++ b/chrome/browser/ui/ash/system_tray_client.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/chromeos/system/system_clock.h"
 #include "chrome/browser/lifetime/termination_notification.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
@@ -56,6 +57,7 @@
 #include "services/ui/public/cpp/property_type_converters.h"
 #include "services/ui/public/interfaces/window_manager.mojom.h"
 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
+#include "ui/events/event_constants.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_delegate.h"
 
@@ -377,13 +379,8 @@
 
 void SystemTrayClient::ShowThirdPartyVpnCreate(
     const std::string& extension_id) {
-  const user_manager::User* primary_user =
-      user_manager::UserManager::Get()->GetPrimaryUser();
-  if (!primary_user)
-    return;
+  Profile* profile = ProfileManager::GetPrimaryUserProfile();
 
-  Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user);
   if (!profile)
     return;
 
@@ -392,6 +389,15 @@
       ->SendShowAddDialogToExtension(extension_id);
 }
 
+void SystemTrayClient::ShowArcVpnCreate(const std::string& app_id) {
+  Profile* profile = ProfileManager::GetPrimaryUserProfile();
+
+  if (!profile)
+    return;
+
+  arc::LaunchApp(profile, app_id, ui::EF_NONE);
+}
+
 void SystemTrayClient::ShowNetworkSettings(const std::string& network_id) {
   ShowNetworkSettingsHelper(network_id, false /* show_configure */);
 }
diff --git a/chrome/browser/ui/ash/system_tray_client.h b/chrome/browser/ui/ash/system_tray_client.h
index 7713cfd2..0521b73 100644
--- a/chrome/browser/ui/ash/system_tray_client.h
+++ b/chrome/browser/ui/ash/system_tray_client.h
@@ -77,6 +77,7 @@
   void ShowNetworkConfigure(const std::string& network_id) override;
   void ShowNetworkCreate(const std::string& type) override;
   void ShowThirdPartyVpnCreate(const std::string& extension_id) override;
+  void ShowArcVpnCreate(const std::string& app_id) override;
   void ShowNetworkSettings(const std::string& network_id) override;
   void RequestRestartForUpdate() override;
 
diff --git a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h
index 3939d11..66b2aaa 100644
--- a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h
@@ -33,6 +33,7 @@
   CGFloat GetWidthForSpace(CGFloat width) override;
   NSRect GetBackgroundFrame(NSRect frame) override;
   void DrawInFrame(NSRect frame, NSView* control_view) override;
+  NSRect GetTrackingFrame(NSRect frame) override;
   NSFont* GetFont() const override;
 
  protected:
diff --git a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm
index edfc6df..c75054e 100644
--- a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm
@@ -160,6 +160,18 @@
   }
 }
 
+NSRect BubbleDecoration::GetTrackingFrame(NSRect frame) {
+  NSRect tracking_frame = GetBackgroundFrame(frame);
+
+  // Include the divider width in the frame.
+  if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout())
+    tracking_frame.origin.x -= 1;
+  else
+    tracking_frame.size.width += 1;
+
+  return tracking_frame;
+}
+
 NSFont* BubbleDecoration::GetFont() const {
   return [attributes_ objectForKey:NSFontAttributeName];
 }
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h
index 0f7610f..809d6687 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h
@@ -71,6 +71,9 @@
   // the result of |GetTooltip()| as a fallback.
   virtual NSString* GetAccessibilityLabel();
 
+  // Returns a NSRect derived from |frame| to set up the tracking area.
+  virtual NSRect GetTrackingFrame(NSRect frame);
+
   // Methods to set up and remove the tracking area from the |control_view|.
   CrTrackingArea* SetupTrackingArea(NSRect frame, NSView* control_view);
   void RemoveTrackingArea();
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm
index 6fc753f9..fd50191 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm
@@ -235,13 +235,18 @@
   return nil;
 }
 
+NSRect LocationBarDecoration::GetTrackingFrame(NSRect frame) {
+  return frame;
+}
+
 CrTrackingArea* LocationBarDecoration::SetupTrackingArea(NSRect frame,
                                                          NSView* control_view) {
   if (!AcceptsMousePress() || !control_view)
     return nil;
 
+  NSRect tracking_frame = GetTrackingFrame(frame);
   if (control_view == tracking_area_owner_ && tracking_area_.get() &&
-      NSEqualRects([tracking_area_ rect], frame)) {
+      NSEqualRects([tracking_area_ rect], tracking_frame)) {
     return tracking_area_.get();
   }
 
@@ -254,7 +259,7 @@
   }
 
   tracking_area_.reset([[CrTrackingArea alloc]
-      initWithRect:frame
+      initWithRect:tracking_frame
            options:NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow
              owner:tracking_delegate_.get()
           userInfo:nil]);
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index 857a014..5323535 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/language/chrome_language_detection_client.h"
 #include "chrome/browser/media/media_engagement_service.h"
 #include "chrome/browser/metrics/desktop_session_duration/desktop_session_duration_observer.h"
+#include "chrome/browser/metrics/oom/out_of_memory_reporter.h"
 #include "chrome/browser/metrics/renderer_uptime_web_contents_observer.h"
 #include "chrome/browser/net/net_error_tab_helper.h"
 #include "chrome/browser/net/predictor_tab_helper.h"
@@ -223,6 +224,7 @@
     MixedContentSettingsTabHelper::CreateForWebContents(web_contents);
   NavigationCorrectionTabObserver::CreateForWebContents(web_contents);
   NavigationMetricsRecorder::CreateForWebContents(web_contents);
+  OutOfMemoryReporter::CreateForWebContents(web_contents);
   chrome::InitializePageLoadMetricsForWebContents(web_contents);
   PDFPluginPlaceholderObserver::CreateForWebContents(web_contents);
   PermissionRequestManager::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/views/collected_cookies_views.cc b/chrome/browser/ui/views/collected_cookies_views.cc
index baac28e7..8622fa3 100644
--- a/chrome/browser/ui/views/collected_cookies_views.cc
+++ b/chrome/browser/ui/views/collected_cookies_views.cc
@@ -49,6 +49,7 @@
 #include "ui/views/controls/tabbed_pane/tabbed_pane.h"
 #include "ui/views/controls/tree/tree_view.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/fill_layout.h"
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/widget/widget.h"
 
@@ -77,7 +78,6 @@
       provider->GetDistanceMetric(views::DISTANCE_BUTTON_MAX_LINKABLE_WIDTH);
 
   views::ColumnSet* column_set = layout->AddColumnSet(column_layout_id);
-  column_set->AddPaddingColumn(100.0, 0);
   column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER, 0,
                         views::GridLayout::USE_PREF, 0, 0);
   column_set->AddPaddingColumn(0, button_padding);
@@ -260,13 +260,6 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// CollectedCookiesViews, views::WidgetDelegate implementation:
-
-bool CollectedCookiesViews::ShouldShowCloseButton() const {
-  return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // CollectedCookiesViews, views::DialogDelegate implementation:
 
 base::string16 CollectedCookiesViews::GetWindowTitle() const {
@@ -300,6 +293,17 @@
   return ui::MODAL_TYPE_CHILD;
 }
 
+bool CollectedCookiesViews::ShouldShowCloseButton() const {
+  return false;
+}
+
+views::View* CollectedCookiesViews::CreateExtraView() {
+  // The code in |Init|, which runs before this does, needs the button pane to
+  // already exist, so it is created there and this class holds ownership until
+  // this method is called.
+  return buttons_pane_.release();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // CollectedCookiesViews, views::ButtonListener implementation:
 
@@ -323,6 +327,9 @@
 void CollectedCookiesViews::TabSelectedAt(int index) {
   EnableControls();
   ShowCookieInfo();
+
+  allowed_buttons_pane_->SetVisible(index == 0);
+  blocked_buttons_pane_->SetVisible(index == 1);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -400,6 +407,8 @@
   infobar_ = new InfobarView();
   layout->AddView(infobar_);
 
+  buttons_pane_ = CreateButtonsPane();
+
   EnableControls();
   ShowCookieInfo();
 }
@@ -429,12 +438,6 @@
   allowed_cookies_tree_->set_auto_expand_children(true);
   allowed_cookies_tree_->SetController(this);
 
-  block_allowed_button_ = views::MdTextButton::CreateSecondaryUiButton(this,
-      l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_BLOCK_BUTTON));
-
-  delete_allowed_button_ = views::MdTextButton::CreateSecondaryUiButton(this,
-      l10n_util::GetStringUTF16(IDS_COOKIES_REMOVE_LABEL));
-
   // Create the view that holds all the controls together.  This will be the
   // pane added to the tabbed pane.
   using views::GridLayout;
@@ -463,10 +466,6 @@
                   kTreeViewHeight);
   layout->AddPaddingRow(0, unrelated_vertical_distance);
 
-  StartNewButtonColumnSet(layout, single_column_layout_id + 1);
-  layout->AddView(block_allowed_button_);
-  layout->AddView(delete_allowed_button_);
-
   return pane;
 }
 
@@ -503,12 +502,6 @@
   blocked_cookies_tree_->set_auto_expand_children(true);
   blocked_cookies_tree_->SetController(this);
 
-  allow_blocked_button_ = views::MdTextButton::CreateSecondaryUiButton(
-      this, l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_ALLOW_BUTTON));
-  for_session_blocked_button_ = views::MdTextButton::CreateSecondaryUiButton(
-      this,
-      l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_SESSION_ONLY_BUTTON));
-
   // Create the view that holds all the controls together.  This will be the
   // pane added to the tabbed pane.
   using views::GridLayout;
@@ -537,13 +530,52 @@
       GridLayout::FILL, GridLayout::FILL, kTreeViewWidth, kTreeViewHeight);
   layout->AddPaddingRow(0, unrelated_vertical_distance);
 
-  StartNewButtonColumnSet(layout, single_column_layout_id + 1);
-  layout->AddView(allow_blocked_button_);
-  layout->AddView(for_session_blocked_button_);
-
   return pane;
 }
 
+std::unique_ptr<views::View> CollectedCookiesViews::CreateButtonsPane() {
+  auto view = std::make_unique<views::View>();
+  view->SetLayoutManager(new views::FillLayout);
+
+  {
+    auto allowed = std::make_unique<views::View>();
+    views::GridLayout* layout =
+        views::GridLayout::CreateAndInstall(allowed.get());
+
+    block_allowed_button_ = views::MdTextButton::CreateSecondaryUiButton(
+        this, l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_BLOCK_BUTTON));
+    delete_allowed_button_ = views::MdTextButton::CreateSecondaryUiButton(
+        this, l10n_util::GetStringUTF16(IDS_COOKIES_REMOVE_LABEL));
+    StartNewButtonColumnSet(layout, 0);
+    layout->AddView(block_allowed_button_);
+    layout->AddView(delete_allowed_button_);
+
+    allowed_buttons_pane_ = allowed.get();
+    view->AddChildView(allowed.release());
+  }
+
+  {
+    auto blocked = std::make_unique<views::View>();
+    views::GridLayout* layout =
+        views::GridLayout::CreateAndInstall(blocked.get());
+    blocked->SetVisible(false);
+
+    allow_blocked_button_ = views::MdTextButton::CreateSecondaryUiButton(
+        this, l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_ALLOW_BUTTON));
+    for_session_blocked_button_ = views::MdTextButton::CreateSecondaryUiButton(
+        this,
+        l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_SESSION_ONLY_BUTTON));
+    StartNewButtonColumnSet(layout, 0);
+    layout->AddView(allow_blocked_button_);
+    layout->AddView(for_session_blocked_button_);
+
+    blocked_buttons_pane_ = blocked.get();
+    view->AddChildView(blocked.release());
+  }
+
+  return view;
+}
+
 views::View* CollectedCookiesViews::CreateScrollView(views::TreeView* pane) {
   views::ScrollView* scroll_view =
       views::ScrollView::CreateScrollViewWithBorder();
diff --git a/chrome/browser/ui/views/collected_cookies_views.h b/chrome/browser/ui/views/collected_cookies_views.h
index 500f4b1..ebd370d 100644
--- a/chrome/browser/ui/views/collected_cookies_views.h
+++ b/chrome/browser/ui/views/collected_cookies_views.h
@@ -52,6 +52,7 @@
   bool Accept() override;
   ui::ModalType GetModalType() const override;
   bool ShouldShowCloseButton() const override;
+  views::View* CreateExtraView() override;
 
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
@@ -78,6 +79,11 @@
 
   views::View* CreateBlockedPane();
 
+  // Creates and returns the "buttons pane", which is the view in the
+  // bottom-leading edge of this dialog containing the action buttons for the
+  // currently selected host or cookie.
+  std::unique_ptr<views::View> CreateButtonsPane();
+
   // Creates and returns a containing ScrollView around the given tree view.
   views::View* CreateScrollView(views::TreeView* pane);
 
@@ -119,6 +125,16 @@
 
   InfobarView* infobar_;
 
+  // The buttons pane is owned by this class until the containing
+  // DialogClientView requests it via |CreateExtraView|, at which point
+  // ownership is handed off and this pointer becomes null.
+  std::unique_ptr<views::View> buttons_pane_;
+
+  // Weak pointers to the allowed and blocked panes so that they can be
+  // shown/hidden as needed.
+  views::View* allowed_buttons_pane_;
+  views::View* blocked_buttons_pane_;
+
   bool status_changed_;
 
   DISALLOW_COPY_AND_ASSIGN(CollectedCookiesViews);
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.cc b/chrome/browser/ui/views/toolbar/app_menu_button.cc
index 70f6884..43cd707 100644
--- a/chrome/browser/ui/views/toolbar/app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu_button.cc
@@ -6,6 +6,7 @@
 
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -40,6 +41,8 @@
 
 constexpr float kIconSize = 16;
 
+constexpr base::TimeDelta kDelayTime = base::TimeDelta::FromMilliseconds(1500);
+
 }  // namespace
 
 // static
@@ -47,13 +50,21 @@
 
 AppMenuButton::AppMenuButton(ToolbarView* toolbar_view)
     : views::MenuButton(base::string16(), toolbar_view, false),
-      toolbar_view_(toolbar_view) {
+      toolbar_view_(toolbar_view),
+      animation_delay_timer_(FROM_HERE,
+                             kDelayTime,
+                             base::Bind(&AppMenuButton::AnimateIconIfPossible,
+                                        base::Unretained(this),
+                                        false),
+                             false) {
   SetInkDropMode(InkDropMode::ON);
   SetFocusPainter(nullptr);
 
   if (base::FeatureList::IsEnabled(features::kAnimatedAppMenuIcon)) {
     toolbar_view_->browser()->tab_strip_model()->AddObserver(this);
     should_use_new_icon_ = true;
+    should_delay_animation_ = base::GetFieldTrialParamByFeatureAsBool(
+        features::kAnimatedAppMenuIcon, "HasDelay", false);
   }
 }
 
@@ -111,7 +122,7 @@
                         base::TimeTicks::Now() - menu_open_time);
   }
 
-  AnimateIconIfPossible();
+  AnimateIconIfPossible(false);
 }
 
 void AppMenuButton::CloseMenu() {
@@ -157,7 +168,7 @@
                                   content::WebContents* contents,
                                   int index,
                                   bool foreground) {
-  AnimateIconIfPossible();
+  AnimateIconIfPossible(true);
 }
 
 void AppMenuButton::UpdateIcon(bool should_animate) {
@@ -201,7 +212,7 @@
                             : toolbar_icon_color);
 
     if (should_animate)
-      AnimateIconIfPossible();
+      AnimateIconIfPossible(true);
 
     return;
   }
@@ -231,13 +242,20 @@
   InvalidateLayout();
 }
 
-void AppMenuButton::AnimateIconIfPossible() {
+void AppMenuButton::AnimateIconIfPossible(bool with_delay) {
   if (!new_icon_ || !should_use_new_icon_ ||
       severity_ == AppMenuIconController::Severity::NONE) {
     return;
   }
 
-  new_icon_->Animate(views::AnimatedIconView::END);
+  if (!should_delay_animation_ || !with_delay || new_icon_->IsAnimating()) {
+    animation_delay_timer_.Stop();
+    new_icon_->Animate(views::AnimatedIconView::END);
+    return;
+  }
+
+  if (!animation_delay_timer_.IsRunning())
+    animation_delay_timer_.Reset();
 }
 
 const char* AppMenuButton::GetClassName() const {
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.h b/chrome/browser/ui/views/toolbar/app_menu_button.h
index 763e1a8..52a5ba01 100644
--- a/chrome/browser/ui/views/toolbar/app_menu_button.h
+++ b/chrome/browser/ui/views/toolbar/app_menu_button.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/toolbar/app_menu_icon_controller.h"
 #include "ui/views/controls/animated_icon_view.h"
@@ -82,15 +83,17 @@
   // to make the focus rectangle centered.
   void SetTrailingMargin(int margin);
 
-  // Animates the icon if possible. The icon will not animate if the severity
-  // level is none, |animation_| is nullptr or |should_use_new_icon_| is false.
-  void AnimateIconIfPossible();
-
   // Opens the app menu immediately during a drag-and-drop operation.
   // Used only in testing.
   static bool g_open_app_immediately_for_testing;
 
  private:
+  // Animates the icon if possible. The icon will not animate if the severity
+  // level is none, |animation_| is nullptr or |should_use_new_icon_| is false.
+  // If |should_delay_animation_| and |with_delay| is true, then delay the
+  // animation.
+  void AnimateIconIfPossible(bool with_delay);
+
   // views::MenuButton:
   const char* GetClassName() const override;
   std::unique_ptr<views::LabelButtonBorder> CreateDefaultBorder()
@@ -127,9 +130,16 @@
   // removed.
   views::AnimatedIconView* new_icon_ = nullptr;
 
+  // Used to delay the animation. Not used if |should_delay_animation_| is
+  // false.
+  base::Timer animation_delay_timer_;
+
   // True if the app menu should use the new animated icon.
   bool should_use_new_icon_ = false;
 
+  // True if the kAnimatedAppMenuIcon feature's "HasDelay" param is true.
+  bool should_delay_animation_ = false;
+
   // Any trailing margin to be applied. Used when the browser is in
   // a maximized state to extend to the full window width.
   int margin_trailing_ = 0;
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 2c0598ad..398d1efc 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -702,14 +702,17 @@
   }
 
   scoped_refptr<base::RefCountedBytes> data;
-  base::string16 title;
-  if (!GetPreviewDataAndTitle(&data, &title)) {
+  print_preview_ui()->GetPrintPreviewDataForIndex(
+      printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &data);
+  if (!data) {
     // Nothing to print, no preview available.
     RejectJavascriptCallback(
         base::Value(callback_id),
         print_with_privet ? base::Value(-1) : base::Value("NO_DATA"));
     return;
   }
+  DCHECK(data->size());
+  DCHECK(data->front());
 
   if (print_with_privet || print_with_extension || print_to_pdf) {
     std::string destination_id;
@@ -738,8 +741,8 @@
       type = PrinterType::kPrivetPrinter;
     PrinterHandler* handler = GetPrinterHandler(type);
     handler->StartPrint(
-        destination_id, capabilities, title, print_ticket,
-        gfx::Size(width, height), data,
+        destination_id, capabilities, print_preview_ui()->initiator_title(),
+        print_ticket, gfx::Size(width, height), data,
         base::BindOnce(&PrintPreviewHandler::OnPrintResult,
                        weak_factory_.GetWeakPtr(), callback_id));
     return;
@@ -749,6 +752,8 @@
     UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
                          page_count);
     ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT);
+    // Does not send the title like the printer handler types above, because JS
+    // already has the document title from the initial settings.
     SendCloudPrintJob(callback_id, data.get());
     return;
   }
@@ -1250,25 +1255,6 @@
     dialog_controller->EraseInitiatorInfo(preview_web_contents());
 }
 
-bool PrintPreviewHandler::GetPreviewDataAndTitle(
-    scoped_refptr<base::RefCountedBytes>* data,
-    base::string16* title) const {
-  scoped_refptr<base::RefCountedBytes> tmp_data;
-  print_preview_ui()->GetPrintPreviewDataForIndex(
-      printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &tmp_data);
-
-  if (!tmp_data.get()) {
-    // Nothing to print, no preview available.
-    return false;
-  }
-  DCHECK(tmp_data->size());
-  DCHECK(tmp_data->front());
-
-  *data = tmp_data;
-  *title = print_preview_ui()->initiator_title();
-  return true;
-}
-
 PrinterHandler* PrintPreviewHandler::GetPrinterHandler(
     PrinterType printer_type) {
   if (printer_type == PrinterType::kExtensionPrinter) {
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.h b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
index 8d957852..6d8ad3f 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
@@ -264,9 +264,6 @@
   // Populates |settings| according to the current locale.
   void GetNumberFormatAndMeasurementSystem(base::DictionaryValue* settings);
 
-  bool GetPreviewDataAndTitle(scoped_refptr<base::RefCountedBytes>* data,
-                              base::string16* title) const;
-
   PdfPrinterHandler* GetPdfPrinterHandler();
 
   // Called when printers are detected.
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 0280c83..5819a68 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -667,7 +667,6 @@
     "cache_stats_recorder.mojom",
     "chrome_render_frame.mojom",
     "constants.mojom",
-    "file_patcher.mojom",
     "insecure_content_renderer.mojom",
     "navigation_corrector.mojom",
     "net_benchmarking.mojom",
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
index c52a2a8..a8fad63d 100644
--- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -2281,6 +2281,37 @@
   ExpectFormSubmittedWithUsernameAndPasswords(kAliceUsername, "NewPass22", "");
 }
 
+TEST_F(PasswordAutofillAgentTest,
+       ResetPasswordGenerationWhenFieldIsAutofilled) {
+  // A user generates password.
+  SetNotBlacklistedMessage(password_generation_, kFormHTML);
+  SetAccountCreationFormsDetectedMessage(password_generation_,
+                                         GetMainFrame()->GetDocument(), 0, 2);
+  base::string16 password = base::ASCIIToUTF16("NewPass22");
+  password_generation_->GeneratedPasswordAccepted(password);
+
+  // A user fills username and password, the generated value is gone.
+  SimulateOnFillPasswordForm(fill_data_);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(fake_driver_.called_password_no_longer_generated());
+
+  // The password field shoudln't reveal the value on focusing.
+  WebDocument document = GetMainFrame()->GetDocument();
+  WebElement element = document.GetElementById(WebString::FromUTF8("password"));
+  ASSERT_FALSE(element.IsNull());
+  WebInputElement password_element = element.To<WebInputElement>();
+  EXPECT_FALSE(password_element.ShouldRevealPassword());
+  EXPECT_TRUE(password_element.IsAutofilled());
+
+  // Make a submission to be sure the autofilled values will be saved.
+  static_cast<content::RenderFrameObserver*>(password_autofill_agent_)
+      ->WillSendSubmitEvent(username_element_.Form());
+  static_cast<content::RenderFrameObserver*>(password_autofill_agent_)
+      ->WillSubmitForm(username_element_.Form());
+  ExpectFormSubmittedWithUsernameAndPasswords(kAliceUsername, kAlicePassword,
+                                              "");
+}
+
 // If password generation is enabled for a field, password autofill should not
 // show UI.
 TEST_F(PasswordAutofillAgentTest, PasswordGenerationSupersedesAutofill) {
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index c7e6f728..e447c4b 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1224,7 +1224,7 @@
       "../browser/chrome_service_worker_browsertest.cc",
       "../browser/chrome_site_per_process_browsertest.cc",
       "../browser/client_hints/client_hints_browsertest.cc",
-      "../browser/component_updater/component_patcher_operation_out_of_process_browsertest.cc",
+      "../browser/component_updater/component_patcher_operation_browsertest.cc",
       "../browser/content_settings/content_settings_browsertest.cc",
       "../browser/crash_recovery_browsertest.cc",
       "../browser/custom_handlers/protocol_handler_registry_browsertest.cc",
@@ -1318,6 +1318,7 @@
       "../browser/media_galleries/media_galleries_dialog_controller_mock.h",
       "../browser/metrics/metrics_memory_details_browsertest.cc",
       "../browser/metrics/metrics_service_browsertest.cc",
+      "../browser/metrics/oom/out_of_memory_reporter_browsertest.cc",
       "../browser/metrics/process_memory_metrics_emitter_browsertest.cc",
       "../browser/metrics/startup_metrics_browsertest.cc",
       "../browser/metrics/tab_reactivation_tracker_browsertest.cc",
@@ -3245,6 +3246,7 @@
     "../browser/metrics/chrome_browser_main_extra_parts_metrics_unittest.cc",
     "../browser/metrics/chrome_metrics_service_accessor_unittest.cc",
     "../browser/metrics/chrome_metrics_service_client_unittest.cc",
+    "../browser/metrics/oom/out_of_memory_reporter_unittest.cc",
     "../browser/metrics/perf/perf_provider_chromeos_unittest.cc",
     "../browser/metrics/process_memory_metrics_emitter_unittest.cc",
     "../browser/metrics/subprocess_metrics_provider_unittest.cc",
diff --git a/chrome/test/base/js2gtest.js b/chrome/test/base/js2gtest.js
index 5930868..2566abd 100644
--- a/chrome/test/base/js2gtest.js
+++ b/chrome/test/base/js2gtest.js
@@ -173,6 +173,8 @@
       this[testFixture].prototype.testGenCppIncludes();
     if (this[testFixture].prototype.commandLineSwitches)
       output('#include "base/command_line.h"');
+    if (this[testFixture].prototype.featureList)
+      output('#include "base/test/scoped_feature_list.h"');
   }
   output();
 }
@@ -391,7 +393,9 @@
 
   if (typedefCppFixture && !(testFixture in typedeffedCppFixtures)) {
     var switches = this[testFixture].prototype.commandLineSwitches;
-    if (!switches || !switches.length || typedefCppFixture == 'V8UnitTest') {
+    var hasSwitches = switches && switches.length;
+    var featureList = this[testFixture].prototype.featureList;
+    if ((!hasSwitches && !featureList) || typedefCppFixture == 'V8UnitTest') {
       output(`
 typedef ${typedefCppFixture} ${testFixture};
 `);
@@ -399,7 +403,21 @@
       // Make the testFixture a class inheriting from the base fixture.
       output(`
 class ${testFixture} : public ${typedefCppFixture} {
+ protected:`);
+      if (featureList) {
+        output(`
+  ${testFixture}() {
+    scoped_feature_list_.InitWithFeatures({${featureList[0]}},
+                                          {${featureList[1]}});
+  }`);
+      } else {
+        output(`
+  ${testFixture}() {}`);
+      }
+      output(`
+  ~${testFixture}() override {}
  private:`);
+      if (hasSwitches) {
       // Override SetUpCommandLine and add each switch.
       output(`
   void SetUpCommandLine(base::CommandLine* command_line) override {`);
@@ -410,7 +428,13 @@
         "${(switches[i].switchValue || '')}");`);
       }
       output(`
-  }
+  }`);
+      }
+      if (featureList) {
+        output(`
+  base::test::ScopedFeatureList scoped_feature_list_;`);
+      }
+      output(`
 };
 `);
     }
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index b85c9d01..14321034 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -36,6 +36,7 @@
 from webelement import WebElement
 import webserver
 
+
 _TEST_DATA_DIR = os.path.join(chrome_paths.GetTestData(), 'chromedriver')
 
 if util.IsLinux():
@@ -994,7 +995,8 @@
   def testPendingConsoleLog(self):
     new_logs = [""]
     def GetPendingLogs(driver):
-      new_logs[0] = driver.GetLog('browser')
+      response = driver.GetLog('browser')
+      new_logs[0] = [x for x in response if x['source'] == 'console-api']
       return new_logs[0]
 
     self._driver.Load(self.GetHttpUrlForFile(
diff --git a/chrome/test/data/webui/cr_components/network_config_test.js b/chrome/test/data/webui/cr_components/network_config_test.js
index 79b010f..277710e 100644
--- a/chrome/test/data/webui/cr_components/network_config_test.js
+++ b/chrome/test/data/webui/cr_components/network_config_test.js
@@ -204,6 +204,55 @@
       });
     });
 
+    test('Ethernet', function() {
+      var ethernet = {
+        GUID: 'ethernetguid',
+        Name: 'Ethernet',
+        Type: 'Ethernet',
+        Ethernet: {Authentication: 'None'}
+      };
+      api_.addNetworksForTest([ethernet]);
+      setNetworkConfig({GUID: 'ethernetguid', Name: '', Type: 'Ethernet'});
+      return flushAsync().then(() => {
+        assertEquals('ethernetguid', networkConfig.guid);
+        assertEquals('None', networkConfig.security_);
+        let outer = networkConfig.$$('#outer');
+        assertFalse(!!outer);
+      });
+    });
+
+    test('Ethernet EAP', function() {
+      var ethernet = {
+        GUID: 'ethernetguid',
+        Name: 'Ethernet',
+        Type: 'Ethernet',
+        Ethernet: {Authentication: 'None'}
+      };
+      var ethernetEap = {
+        GUID: 'eapguid',
+        Name: 'EthernetEap',
+        Type: 'Ethernet',
+        Ethernet: {
+          Authentication: '8021X',
+          EAP: {Outer: 'PEAP'},
+        }
+      };
+      api_.addNetworksForTest([ethernet, ethernetEap]);
+      setNetworkConfig({GUID: 'ethernetguid', Name: '', Type: 'Ethernet'});
+      return flushAsync().then(() => {
+        assertEquals('eapguid', networkConfig.guid);
+        assertEquals('WPA-EAP', networkConfig.security_);
+        assertEquals(
+            'PEAP',
+            networkConfig.get(
+                'Ethernet.EAP.Outer', networkConfig.networkProperties));
+        let outer = networkConfig.$$('#outer');
+        assertTrue(!!outer);
+        assertTrue(!outer.disabled);
+        assertEquals('PEAP', outer.value);
+      });
+    });
+
   });
 
 });
diff --git a/chrome/test/data/webui/extensions/a11y/extensions_a11y_test_fixture.js b/chrome/test/data/webui/extensions/a11y/extensions_a11y_test_fixture.js
index 9bd3ed1..14ece02 100644
--- a/chrome/test/data/webui/extensions/a11y/extensions_a11y_test_fixture.js
+++ b/chrome/test/data/webui/extensions/a11y/extensions_a11y_test_fixture.js
@@ -12,6 +12,7 @@
   ROOT_PATH + 'chrome/test/data/webui/a11y/accessibility_test.js',
   ROOT_PATH + 'chrome/test/data/webui/polymer_browser_test_base.js',
 ]);
+GEN('#include "chrome/common/chrome_features.h"');
 
 /**
  * Test fixture for Accessibility of Chrome Extensions.
@@ -25,11 +26,8 @@
   }
 
   /** @override */
-  get commandLineSwitches() {
-    return [{
-      switchName: 'enable-features',
-      switchValue: 'MaterialDesignExtensions',
-    }];
+  get featureList() {
+    return ['features::kMaterialDesignExtensions', ''];
   }
 
   // Include files that define the mocha tests.
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
index affa92f..7c5d046 100644
--- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
+++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -10,9 +10,9 @@
 // Polymer BrowserTest fixture.
 GEN_INCLUDE([
     ROOT_PATH + 'chrome/test/data/webui/polymer_browser_test_base.js']);
-GEN('#include "base/command_line.h"');
 GEN('#include "chrome/browser/ui/webui/extensions/' +
     'extension_settings_browsertest.h"');
+GEN('#include "chrome/common/chrome_features.h"');
 
 /**
  * Basic test fixture for the MD chrome://extensions page. Installs no
@@ -25,11 +25,8 @@
   }
 
   /** @override */
-  get commandLineSwitches() {
-    return [{
-      switchName: 'enable-features',
-      switchValue: 'MaterialDesignExtensions',
-    }];
+  get featureList() {
+    return ['features::kMaterialDesignExtensions', ''];
   }
 
   /** @override */
diff --git a/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js b/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js
index c9a6c4e..5a5d81c 100644
--- a/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js
+++ b/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js
@@ -9,9 +9,9 @@
 
 GEN_INCLUDE(
     [ROOT_PATH + 'chrome/test/data/webui/polymer_browser_test_base.js']);
-GEN('#include "base/command_line.h"');
 GEN('#include "chrome/browser/prefs/incognito_mode_prefs.h"');
 GEN('#include "chrome/browser/ui/webui/md_bookmarks/md_bookmarks_browsertest.h"');
+GEN('#include "chrome/common/chrome_features.h"');
 
 function MaterialBookmarksBrowserTest() {}
 
@@ -20,8 +20,7 @@
 
   browsePreload: 'chrome://bookmarks',
 
-  commandLineSwitches: [{switchName: 'enable-features',
-                         switchValue: 'MaterialDesignBookmarks'}],
+  featureList: ['features::kMaterialDesignBookmarks', ''],
 
   typedefCppFixture: 'MdBookmarksBrowserTest',
 
diff --git a/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js b/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
index 0166228..557a90a 100644
--- a/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
+++ b/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
@@ -11,7 +11,7 @@
 
 GEN_INCLUDE(
     [ROOT_PATH + 'chrome/test/data/webui/polymer_interactive_ui_test.js']);
-GEN('#include "base/command_line.h"');
+GEN('#include "chrome/common/chrome_features.h"');
 
 function MaterialBookmarksFocusTest() {}
 
@@ -20,8 +20,7 @@
 
   browsePreload: 'chrome://bookmarks',
 
-  commandLineSwitches:
-      [{switchName: 'enable-features', switchValue: 'MaterialDesignBookmarks'}],
+  featureList: ['features::kMaterialDesignBookmarks', ''],
 
   extraLibraries: PolymerTest.getLibraries(ROOT_PATH).concat([
     'test_command_manager.js',
diff --git a/chrome/test/data/webui/md_user_manager/user_manager_browsertest.js b/chrome/test/data/webui/md_user_manager/user_manager_browsertest.js
index 503f95a2..d3522a82 100644
--- a/chrome/test/data/webui/md_user_manager/user_manager_browsertest.js
+++ b/chrome/test/data/webui/md_user_manager/user_manager_browsertest.js
@@ -10,7 +10,7 @@
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(
     [ROOT_PATH + 'chrome/test/data/webui/polymer_browser_test_base.js']);
-GEN('#include "base/command_line.h"');
+GEN('#include "chrome/common/chrome_features.h"');
 
 /**
  * @constructor
@@ -25,8 +25,7 @@
   browsePreload: 'chrome://md-user-manager/',
 
   /** @override */
-  commandLineSwitches: [{switchName: 'enable-features',
-                         switchValue: 'SupervisedUserCreation'}],
+  featureList: ['features::kSupervisedUserCreation', ''],
 
   /** @override */
   extraLibraries: PolymerTest.getLibraries(ROOT_PATH).concat([
diff --git a/chrome/test/data/webui/media/media_engagement_browsertest.js b/chrome/test/data/webui/media/media_engagement_browsertest.js
index 440ee70..4774159 100644
--- a/chrome/test/data/webui/media/media_engagement_browsertest.js
+++ b/chrome/test/data/webui/media/media_engagement_browsertest.js
@@ -9,10 +9,10 @@
 var EXAMPLE_URL_1 = 'http://example.com/';
 var EXAMPLE_URL_2 = 'http://shmlexample.com/';
 
-GEN('#include "base/command_line.h"');
 GEN('#include "chrome/browser/media/media_engagement_service.h"');
 GEN('#include "chrome/browser/media/media_engagement_service_factory.h"');
 GEN('#include "chrome/browser/ui/browser.h"');
+GEN('#include "media/base/media_switches.h"')
 
 function MediaEngagementWebUIBrowserTest() {}
 
@@ -21,10 +21,7 @@
 
   browsePreload: 'chrome://media-engagement',
 
-  commandLineSwitches: [{
-    switchName: 'enable-features',
-    switchValue: 'RecordMediaEngagementScores'
-  }],
+  featureList: ['media::kRecordMediaEngagementScores', ''],
 
   runAccessibilityChecks: false,
 
diff --git a/chrome/test/data/webui/sys_internals/sys_internals_browsertest.js b/chrome/test/data/webui/sys_internals/sys_internals_browsertest.js
index bd66c4f..b12cc7e1 100644
--- a/chrome/test/data/webui/sys_internals/sys_internals_browsertest.js
+++ b/chrome/test/data/webui/sys_internals/sys_internals_browsertest.js
@@ -6,6 +6,7 @@
  * @fileoverview Test suite for the SysInternals WebUI. (CrOS only)
  */
 const ROOT_PATH = '../../../../../';
+GEN('#include "chrome/common/chrome_features.h"');
 
 /* Set up this global variable to disable sending the update request. */
 DONT_SEND_UPDATE_REQUEST = true;
@@ -21,8 +22,8 @@
 
   isAsync: true,
 
-  commandLineSwitches:
-      [{switchName: 'enable-features', switchValue: 'SysInternals'}],
+  featureList:
+      ['features::kSysInternals', ''],
 
   extraLibraries: [
     'api_test.js',
diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn
index 236a1ff..271df98c 100644
--- a/chrome/utility/BUILD.gn
+++ b/chrome/utility/BUILD.gn
@@ -37,6 +37,7 @@
     "//chrome/common/printing:interfaces",
     "//chrome/common/profiling",
     "//chrome/profiling",
+    "//components/patch_service:lib",
     "//components/search_engines",
     "//components/strings",
     "//components/url_formatter",
@@ -44,7 +45,6 @@
     "//content/public/common",
     "//content/public/network",
     "//content/public/utility",
-    "//courgette:courgette_lib",
     "//extensions/features",
     "//ipc",
     "//media",
diff --git a/chrome/utility/DEPS b/chrome/utility/DEPS
index c2f65e8..5d0766d3 100644
--- a/chrome/utility/DEPS
+++ b/chrome/utility/DEPS
@@ -7,6 +7,7 @@
   "+chrome/services/util_win/util_win_service.h",
   "+chrome/services/util_win/public/interfaces",
   "+components/font_service/font_service_app.h",
+  "+components/patch_service",
   "+components/payments/content/utility",
   "+components/printing/service/public/cpp",
   "+components/printing/service/public/interfaces",
@@ -14,7 +15,6 @@
   "+content/public/child",
   "+content/public/network",
   "+content/public/utility",
-  "+courgette",
   "+extensions/common",
   "+extensions/features",
   "+media",
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc
index 6e073453..2b7c726 100644
--- a/chrome/utility/chrome_content_utility_client.cc
+++ b/chrome/utility/chrome_content_utility_client.cc
@@ -16,17 +16,16 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/common/features.h"
-#include "chrome/common/file_patcher.mojom.h"
 #include "chrome/common/profiling/constants.mojom.h"
 #include "chrome/profiling/profiling_service.h"
 #include "chrome/utility/printing/pdf_to_pwg_raster_converter_impl.h"
 #include "chrome/utility/utility_message_handler.h"
+#include "components/patch_service/patch_service.h"
+#include "components/patch_service/public/interfaces/constants.mojom.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/simple_connection_filter.h"
 #include "content/public/utility/utility_thread.h"
-#include "courgette/courgette.h"
-#include "courgette/third_party/bsdiff/bsdiff.h"
 #include "extensions/features/features.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "printing/features/features.h"
@@ -91,47 +90,6 @@
 
 namespace {
 
-class FilePatcherImpl : public chrome::mojom::FilePatcher {
- public:
-  FilePatcherImpl() = default;
-  ~FilePatcherImpl() override = default;
-
-  static void Create(chrome::mojom::FilePatcherRequest request) {
-    mojo::MakeStrongBinding(base::MakeUnique<FilePatcherImpl>(),
-                            std::move(request));
-  }
-
- private:
-  // chrome::mojom::FilePatcher:
-  void PatchFileBsdiff(base::File input_file,
-                       base::File patch_file,
-                       base::File output_file,
-                       const PatchFileBsdiffCallback& callback) override {
-    DCHECK(input_file.IsValid());
-    DCHECK(patch_file.IsValid());
-    DCHECK(output_file.IsValid());
-
-    const int patch_result_status = bsdiff::ApplyBinaryPatch(
-        std::move(input_file), std::move(patch_file), std::move(output_file));
-    callback.Run(patch_result_status);
-  }
-
-  void PatchFileCourgette(base::File input_file,
-                          base::File patch_file,
-                          base::File output_file,
-                          const PatchFileCourgetteCallback& callback) override {
-    DCHECK(input_file.IsValid());
-    DCHECK(patch_file.IsValid());
-    DCHECK(output_file.IsValid());
-
-    const int patch_result_status = courgette::ApplyEnsemblePatch(
-        std::move(input_file), std::move(patch_file), std::move(output_file));
-    callback.Run(patch_result_status);
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(FilePatcherImpl);
-};
-
 #if defined(FULL_SAFE_BROWSING)
 class SafeArchiveAnalyzerImpl : public chrome::mojom::SafeArchiveAnalyzer {
  public:
@@ -250,9 +208,6 @@
   // If our process runs with elevated privileges, only add elevated Mojo
   // interfaces to the interface registry.
   if (!utility_process_running_elevated_) {
-    registry->AddInterface(base::Bind(&FilePatcherImpl::Create),
-                           base::ThreadTaskRunnerHandle::Get());
-
 #if !defined(OS_ANDROID)
     registry->AddInterface(base::Bind(CreateResourceUsageReporter),
                            base::ThreadTaskRunnerHandle::Get());
@@ -339,6 +294,12 @@
   }
 #endif
 
+  if (!utility_process_running_elevated_) {
+    service_manager::EmbeddedServiceInfo service_info;
+    service_info.factory = base::Bind(&patch::PatchService::CreateService);
+    services->emplace(patch::mojom::kServiceName, service_info);
+  }
+
 #if BUILDFLAG(ENABLE_MUS)
   RegisterMashServices(services);
 #endif
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index eb0e7b5..193f045 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-10105.0.0
+10108.0.0
\ No newline at end of file
diff --git a/chromeos/network/network_configuration_handler.cc b/chromeos/network/network_configuration_handler.cc
index 2f9140d7..df2c71b 100644
--- a/chromeos/network/network_configuration_handler.cc
+++ b/chromeos/network/network_configuration_handler.cc
@@ -350,7 +350,7 @@
   properties_to_set->GetStringWithoutPathExpansion(shill::kGuidProperty, &guid);
   if (guid.empty()) {
     guid = base::GenerateGUID();
-    properties_to_set->SetKey(::onc::network_config::kGUID, base::Value(guid));
+    properties_to_set->SetKey(shill::kGuidProperty, base::Value(guid));
   }
 
   LogConfigProperties("Configure", type, *properties_to_set);
diff --git a/chromeos/network/network_type_pattern.cc b/chromeos/network/network_type_pattern.cc
index e926825..995d8c0 100644
--- a/chromeos/network/network_type_pattern.cc
+++ b/chromeos/network/network_type_pattern.cc
@@ -82,6 +82,11 @@
 }
 
 // static
+NetworkTypePattern NetworkTypePattern::EthernetOrEthernetEAP() {
+  return NetworkTypePattern(kNetworkTypeEthernet | kNetworkTypeEthernetEap);
+}
+
+// static
 NetworkTypePattern NetworkTypePattern::WiFi() {
   return NetworkTypePattern(kNetworkTypeWifi);
 }
diff --git a/chromeos/network/network_type_pattern.h b/chromeos/network/network_type_pattern.h
index 1fde992b..2995b6b 100644
--- a/chromeos/network/network_type_pattern.h
+++ b/chromeos/network/network_type_pattern.h
@@ -26,9 +26,12 @@
   // Matches non virtual networks.
   static NetworkTypePattern NonVirtual();
 
-  // Matches ethernet networks (with or without EAP).
+  // Matches ethernet networks.
   static NetworkTypePattern Ethernet();
 
+  // Matches ethernet or ethernet EAP networks.
+  static NetworkTypePattern EthernetOrEthernetEAP();
+
   static NetworkTypePattern WiFi();
   static NetworkTypePattern Cellular();
   static NetworkTypePattern VPN();
diff --git a/chromeos/network/onc/onc_translator_shill_to_onc.cc b/chromeos/network/onc/onc_translator_shill_to_onc.cc
index fee36e0..4062454 100644
--- a/chromeos/network/onc/onc_translator_shill_to_onc.cc
+++ b/chromeos/network/onc/onc_translator_shill_to_onc.cc
@@ -229,6 +229,9 @@
   if (shill_network_type == shill::kTypeEthernetEap)
     onc_auth = ::onc::ethernet::k8021X;
   onc_object_->SetKey(::onc::ethernet::kAuthentication, base::Value(onc_auth));
+
+  if (shill_network_type == shill::kTypeEthernetEap)
+    TranslateAndAddNestedObject(::onc::ethernet::kEAP);
 }
 
 void ShillToONCTranslator::TranslateOpenVPN() {
diff --git a/chromeos/test/data/network/translation_of_shill_ethernet_with_eap.onc b/chromeos/test/data/network/translation_of_shill_ethernet_with_eap.onc
index bfb1a29..888d3c8 100644
--- a/chromeos/test/data/network/translation_of_shill_ethernet_with_eap.onc
+++ b/chromeos/test/data/network/translation_of_shill_ethernet_with_eap.onc
@@ -1,6 +1,12 @@
 {
   "Ethernet":{
-    "Authentication":"8021X"
+    "Authentication":"8021X",
+    "EAP": {
+      "Identity": "abc ${LOGIN_ID}@my.domain.com",
+      "Outer": "EAP-TLS",
+      "SaveCredentials": true,
+      "UseSystemCAs": true
+    }
   },
   "GUID":"guid",
   "Name":"",
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index c093067..55a6bd4 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -25,6 +25,7 @@
 #include "build/build_config.h"
 #include "components/autofill/content/renderer/form_autofill_util.h"
 #include "components/autofill/content/renderer/password_form_conversion_utils.h"
+#include "components/autofill/content/renderer/password_generation_agent.h"
 #include "components/autofill/content/renderer/renderer_save_password_progress_logger.h"
 #include "components/autofill/core/common/autofill_constants.h"
 #include "components/autofill/core/common/autofill_util.h"
@@ -618,6 +619,11 @@
   autofill_agent_ = autofill_agent;
 }
 
+void PasswordAutofillAgent::SetPasswordGenerationAgent(
+    PasswordGenerationAgent* generation_agent) {
+  password_generation_agent_ = generation_agent;
+}
+
 PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper()
     : was_user_gesture_seen_(false) {
 }
@@ -725,6 +731,11 @@
     password_info->password_field = password_element;
   }
 
+  // Call OnFieldAutofilled before WebInputElement::SetAutofilled which may
+  // cause frame closing.
+  if (password_generation_agent_)
+    password_generation_agent_->OnFieldAutofilled(password_element);
+
   if (IsUsernameAmendable(username_element, element->IsPasswordField())) {
     username_element.SetAutofillValue(blink::WebString::FromUTF16(username));
     username_element.SetAutofilled(true);
@@ -1794,6 +1805,11 @@
   // TODO(tkent): Check maxlength and pattern for both username and password
   // fields.
 
+  // Call OnFieldAutofilled before WebInputElement::SetAutofilled which may
+  // cause frame closing.
+  if (password_generation_agent_)
+    password_generation_agent_->OnFieldAutofilled(*password_element);
+
   // Input matches the username, fill in required values.
   if (!username_element->IsNull() &&
       IsElementAutocompletable(*username_element)) {
@@ -1821,8 +1837,8 @@
   ProvisionallySavePassword(password_element->Form(), *password_element,
                             RESTRICTION_NONE);
   registration_callback.Run(password_element);
-
   password_element->SetAutofilled(true);
+
   if (logger)
     logger->LogElementName(Logger::STRING_PASSWORD_FILLED, *password_element);
   return true;
diff --git a/components/autofill/content/renderer/password_autofill_agent.h b/components/autofill/content/renderer/password_autofill_agent.h
index e7d2f77..a94771a6 100644
--- a/components/autofill/content/renderer/password_autofill_agent.h
+++ b/components/autofill/content/renderer/password_autofill_agent.h
@@ -42,6 +42,7 @@
 const char kDebugAttributeForFieldSignature[] = "field_signature";
 
 class RendererSavePasswordProgressLogger;
+class PasswordGenerationAgent;
 
 // This class is responsible for filling password forms.
 class PasswordAutofillAgent : public content::RenderFrameObserver,
@@ -55,6 +56,8 @@
 
   void SetAutofillAgent(AutofillAgent* autofill_agent);
 
+  void SetPasswordGenerationAgent(PasswordGenerationAgent* generation_agent);
+
   const mojom::PasswordManagerDriverPtr& GetPasswordManagerDriver();
 
   // mojom::PasswordAutofillAgent:
@@ -351,6 +354,7 @@
   FormsPredictionsMap form_predictions_;
 
   AutofillAgent* autofill_agent_;  // Weak reference.
+  PasswordGenerationAgent* password_generation_agent_;  // Weak reference.
 
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
   PagePasswordsAnalyser page_passwords_analyser_;
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc
index 22f11c6..0d78a60c 100644
--- a/components/autofill/content/renderer/password_generation_agent.cc
+++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -169,6 +169,7 @@
   LogBoolean(Logger::STRING_GENERATION_RENDERER_ENABLED, enabled_);
   registry->AddInterface(base::Bind(&PasswordGenerationAgent::BindRequest,
                                     base::Unretained(this)));
+  password_agent_->SetPasswordGenerationAgent(this);
 }
 PasswordGenerationAgent::~PasswordGenerationAgent() {}
 
@@ -242,6 +243,12 @@
   FindPossibleGenerationForm();
 }
 
+void PasswordGenerationAgent::OnFieldAutofilled(
+    const blink::WebInputElement& password_element) {
+  if (generation_element_ == password_element)
+    PasswordNoLongerGenerated();
+}
+
 void PasswordGenerationAgent::AllowToRunFormClassifier() {
   form_classifier_enabled_ = true;
 }
diff --git a/components/autofill/content/renderer/password_generation_agent.h b/components/autofill/content/renderer/password_generation_agent.h
index 34a380e..edfd5d9 100644
--- a/components/autofill/content/renderer/password_generation_agent.h
+++ b/components/autofill/content/renderer/password_generation_agent.h
@@ -65,6 +65,9 @@
   // Called when new form controls are inserted.
   void OnDynamicFormsSeen();
 
+  // Called right before PasswordAutofillAgent filled |password_element|.
+  void OnFieldAutofilled(const blink::WebInputElement& password_element);
+
   // The length that a password can be before the UI is hidden.
   static const size_t kMaximumOfferSize = 5;
 
diff --git a/components/bookmarks/browser/bookmark_model.cc b/components/bookmarks/browser/bookmark_model.cc
index 9aae417..99effbf 100644
--- a/components/bookmarks/browser/bookmark_model.cc
+++ b/components/bookmarks/browser/bookmark_model.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 #include <functional>
+#include <string>
 #include <utility>
 
 #include "base/bind.h"
@@ -1025,6 +1026,9 @@
     // Couldn't load the touch icon, fallback to the regular favicon.
     DCHECK(client_->PreferTouchIcon());
     LoadFavicon(node, favicon_base::IconType::kFavicon);
+  } else {
+    // No favicon available, but we still notify observers.
+    FaviconLoaded(node);
   }
 }
 
diff --git a/components/bookmarks/test/bookmark_test_helpers.cc b/components/bookmarks/test/bookmark_test_helpers.cc
index fa435d4..3379465 100644
--- a/components/bookmarks/test/bookmark_test_helpers.cc
+++ b/components/bookmarks/test/bookmark_test_helpers.cc
@@ -9,7 +9,6 @@
 #include "base/callback.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/bookmarks/browser/base_bookmark_model_observer.h"
@@ -100,9 +99,7 @@
 void WaitForBookmarkModelToLoad(BookmarkModel* model) {
   if (model->loaded())
     return;
-  base::RunLoop run_loop;
-  base::MessageLoop::ScopedNestableTaskAllower allow(
-      base::MessageLoop::current());
+  base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
 
   BookmarkLoadObserver observer(run_loop.QuitClosure());
   model->AddObserver(&observer);
diff --git a/components/component_updater/BUILD.gn b/components/component_updater/BUILD.gn
index 6bb14ef..be691cd 100644
--- a/components/component_updater/BUILD.gn
+++ b/components/component_updater/BUILD.gn
@@ -71,6 +71,7 @@
     "//base",
     "//base/test:test_support",
     "//components/update_client:test_support",
+    "//services/service_manager/public/cpp",
     "//testing/gmock",
     "//testing/gtest",
   ]
diff --git a/components/component_updater/DEPS b/components/component_updater/DEPS
index 5e9b04a..ccc2185 100644
--- a/components/component_updater/DEPS
+++ b/components/component_updater/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+components/update_client",
   "+components/version_info",
+  "+services/service_manager/public",
   "+ui",
   "+url",
 ]
diff --git a/components/component_updater/component_installer.cc b/components/component_updater/component_installer.cc
index 71a6c84..33ad68b 100644
--- a/components/component_updater/component_installer.cc
+++ b/components/component_updater/component_installer.cc
@@ -377,6 +377,9 @@
     if (!base::DeleteFile(base_dir, false))
       DLOG(ERROR) << "Couldn't delete " << base_dir.value();
   }
+
+  // Customized operations for individual component.
+  installer_policy_->OnCustomUninstall();
 }
 
 void ComponentInstaller::FinishRegistration(
diff --git a/components/component_updater/component_installer.h b/components/component_updater/component_installer.h
index 87414d5..5da302a9 100644
--- a/components/component_updater/component_installer.h
+++ b/components/component_updater/component_installer.h
@@ -62,6 +62,11 @@
       const base::DictionaryValue& manifest,
       const base::FilePath& install_dir) = 0;
 
+  // OnCustomUninstall is called during the unregister (uninstall) process.
+  // Components that require custom uninstallation operations should implement
+  // them here.
+  virtual void OnCustomUninstall() = 0;
+
   // ComponentReady is called in two cases:
   //   1) After an installation is successfully completed.
   //   2) During component registration if the component is already installed.
diff --git a/components/component_updater/component_installer_unittest.cc b/components/component_updater/component_installer_unittest.cc
index 32a1886..c558149 100644
--- a/components/component_updater/component_installer_unittest.cc
+++ b/components/component_updater/component_installer_unittest.cc
@@ -30,6 +30,7 @@
 #include "components/update_client/test_configurator.h"
 #include "components/update_client/update_client.h"
 #include "components/update_client/update_client_errors.h"
+#include "services/service_manager/public/cpp/connector.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -134,6 +135,8 @@
     return update_client::CrxInstaller::Result(0);
   }
 
+  void OnCustomUninstall() override {}
+
   void ComponentReady(
       const base::Version& version,
       const base::FilePath& install_dir,
diff --git a/components/crash/content/browser/crash_dump_manager_android.h b/components/crash/content/browser/crash_dump_manager_android.h
index d2843a7..3813947 100644
--- a/components/crash/content/browser/crash_dump_manager_android.h
+++ b/components/crash/content/browser/crash_dump_manager_android.h
@@ -73,6 +73,10 @@
     CrashDumpStatus status = CrashDumpStatus::kNoDump;
   };
 
+  // Careful note: the CrashDumpManager observers are asynchronous, and are
+  // notified via PostTask. This could be problematic with a large number of
+  // observers. Consider using a middle-layer observer to fan out synchronously
+  // to leaf observers if you need many objects listening to these messages.
   class Observer {
    public:
     virtual void OnCrashDumpProcessed(const CrashDumpDetails& details) {}
diff --git a/components/favicon/ios/web_favicon_driver.h b/components/favicon/ios/web_favicon_driver.h
index a387ab1..14d0145 100644
--- a/components/favicon/ios/web_favicon_driver.h
+++ b/components/favicon/ios/web_favicon_driver.h
@@ -67,7 +67,6 @@
   void FaviconUrlUpdated(
       web::WebState* web_state,
       const std::vector<web::FaviconURL>& candidates) override;
-  void WebStateDestroyed(web::WebState* web_state) override;
 
   // Invoked when new favicon URL candidates are received.
   void FaviconUrlUpdatedInternal(
@@ -79,10 +78,6 @@
   // Caches the favicon URLs candidates for same-document navigations.
   std::vector<favicon::FaviconURL> candidates_;
 
-  // The WebState this instance is observing. Will be null after
-  // WebStateDestroyed has been called.
-  web::WebState* web_state_ = nullptr;
-
   DISALLOW_COPY_AND_ASSIGN(WebFaviconDriver);
 };
 
diff --git a/components/favicon/ios/web_favicon_driver.mm b/components/favicon/ios/web_favicon_driver.mm
index cff4de6..10fd0f8 100644
--- a/components/favicon/ios/web_favicon_driver.mm
+++ b/components/favicon/ios/web_favicon_driver.mm
@@ -51,19 +51,19 @@
 
 gfx::Image WebFaviconDriver::GetFavicon() const {
   web::NavigationItem* item =
-      web_state_->GetNavigationManager()->GetLastCommittedItem();
+      web_state()->GetNavigationManager()->GetLastCommittedItem();
   return item ? item->GetFavicon().image : gfx::Image();
 }
 
 bool WebFaviconDriver::FaviconIsValid() const {
   web::NavigationItem* item =
-      web_state_->GetNavigationManager()->GetLastCommittedItem();
+      web_state()->GetNavigationManager()->GetLastCommittedItem();
   return item ? item->GetFavicon().valid : false;
 }
 
 GURL WebFaviconDriver::GetActiveURL() {
   web::NavigationItem* item =
-      web_state_->GetNavigationManager()->GetVisibleItem();
+      web_state()->GetNavigationManager()->GetVisibleItem();
   return item ? item->GetURL() : GURL();
 }
 
@@ -103,8 +103,8 @@
 }
 
 bool WebFaviconDriver::IsOffTheRecord() {
-  DCHECK(web_state_);
-  return web_state_->GetBrowserState()->IsOffTheRecord();
+  DCHECK(web_state());
+  return web_state()->GetBrowserState()->IsOffTheRecord();
 }
 
 void WebFaviconDriver::OnFaviconUpdated(
@@ -122,7 +122,7 @@
   }
 
   web::NavigationItem* item =
-      web_state_->GetNavigationManager()->GetVisibleItem();
+      web_state()->GetNavigationManager()->GetVisibleItem();
   DCHECK(item);
 
   web::FaviconStatus& favicon_status = item->GetFavicon();
@@ -155,23 +155,16 @@
 WebFaviconDriver::WebFaviconDriver(web::WebState* web_state,
                                    FaviconService* favicon_service,
                                    history::HistoryService* history_service)
-    : FaviconDriverImpl(favicon_service, history_service),
-      image_fetcher_(web_state->GetBrowserState()->GetRequestContext()),
-      web_state_(web_state) {
-  web_state_->AddObserver(this);
-}
+    : web::WebStateObserver(web_state),
+      FaviconDriverImpl(favicon_service, history_service),
+      image_fetcher_(web_state->GetBrowserState()->GetRequestContext()) {}
 
 WebFaviconDriver::~WebFaviconDriver() {
-  // WebFaviconDriver is owned by WebState (as it is a WebStateUserData), so
-  // the WebStateDestroyed will be called before the destructor and the member
-  // field reset to null.
-  DCHECK(!web_state_);
 }
 
 void WebFaviconDriver::DidStartNavigation(
     web::WebState* web_state,
     web::NavigationContext* navigation_context) {
-  DCHECK_EQ(web_state_, web_state);
   SetFaviconOutOfDateForPage(navigation_context->GetUrl(),
                              /*force_reload=*/false);
 }
@@ -179,7 +172,6 @@
 void WebFaviconDriver::DidFinishNavigation(
     web::WebState* web_state,
     web::NavigationContext* navigation_context) {
-  DCHECK_EQ(web_state_, web_state);
   if (navigation_context->GetError())
     return;
 
@@ -199,18 +191,11 @@
 void WebFaviconDriver::FaviconUrlUpdated(
     web::WebState* web_state,
     const std::vector<web::FaviconURL>& candidates) {
-  DCHECK_EQ(web_state_, web_state);
   DCHECK(!candidates.empty());
   candidates_ = FaviconURLsFromWebFaviconURLs(candidates);
   FaviconUrlUpdatedInternal(candidates_);
 }
 
-void WebFaviconDriver::WebStateDestroyed(web::WebState* web_state) {
-  DCHECK_EQ(web_state_, web_state);
-  web_state_->RemoveObserver(this);
-  web_state_ = nullptr;
-}
-
 void WebFaviconDriver::FaviconUrlUpdatedInternal(
     const std::vector<favicon::FaviconURL>& candidates) {
   OnUpdateCandidates(GetActiveURL(), candidates, GURL());
diff --git a/components/gcm_driver/instance_id/android/java/src/org/chromium/components/gcm_driver/instance_id/InstanceIDWithSubtype.java b/components/gcm_driver/instance_id/android/java/src/org/chromium/components/gcm_driver/instance_id/InstanceIDWithSubtype.java
index d8e7cf5..8e79885 100644
--- a/components/gcm_driver/instance_id/android/java/src/org/chromium/components/gcm_driver/instance_id/InstanceIDWithSubtype.java
+++ b/components/gcm_driver/instance_id/android/java/src/org/chromium/components/gcm_driver/instance_id/InstanceIDWithSubtype.java
@@ -32,8 +32,8 @@
      */
     @VisibleForTesting
     @SuppressFBWarnings("MS_MUTABLE_COLLECTION_PKGPROTECT")
-    public static final Map<String, InstanceIDWithSubtype> sSubtypeInstances = new HashMap<>();
-    private static final Object sSubtypeInstancesLock = new Object();
+    protected static final Map<String, InstanceIDWithSubtype> sSubtypeInstances = new HashMap<>();
+    protected static final Object sSubtypeInstancesLock = new Object();
 
     /** Fake subclasses can set this so getInstance creates instances of them. */
     @VisibleForTesting
diff --git a/components/gcm_driver/instance_id/android/javatests/src/org/chromium/components/gcm_driver/instance_id/FakeInstanceIDWithSubtype.java b/components/gcm_driver/instance_id/android/javatests/src/org/chromium/components/gcm_driver/instance_id/FakeInstanceIDWithSubtype.java
index 030bf327..9376105 100644
--- a/components/gcm_driver/instance_id/android/javatests/src/org/chromium/components/gcm_driver/instance_id/FakeInstanceIDWithSubtype.java
+++ b/components/gcm_driver/instance_id/android/javatests/src/org/chromium/components/gcm_driver/instance_id/FakeInstanceIDWithSubtype.java
@@ -37,7 +37,7 @@
      */
     @CalledByNative
     public static boolean clearDataAndSetEnabled(boolean enable) {
-        synchronized (InstanceID.class) {
+        synchronized (sSubtypeInstancesLock) {
             sSubtypeInstances.clear();
             boolean wasEnabled = sFakeFactoryForTesting != null;
             if (enable) {
@@ -62,20 +62,20 @@
      * token). If a test fails with too many InstanceIDs/tokens, the test subscribed too many times.
      */
     public static Pair<String, String> getSubtypeAndAuthorizedEntityOfOnlyToken() {
-        if (InstanceIDWithSubtype.sSubtypeInstances.size() != 1) {
-            throw new IllegalStateException("Expected exactly one InstanceID, but there are "
-                    + InstanceIDWithSubtype.sSubtypeInstances.size());
+        synchronized (sSubtypeInstancesLock) {
+            if (sSubtypeInstances.size() != 1) {
+                throw new IllegalStateException("Expected exactly one InstanceID, but there are "
+                        + sSubtypeInstances.size());
+            }
+            FakeInstanceIDWithSubtype iid =
+                    (FakeInstanceIDWithSubtype) sSubtypeInstances.values().iterator().next();
+            if (iid.mTokens.size() != 1) {
+                throw new IllegalStateException(
+                        "Expected exactly one token, but there are " + iid.mTokens.size());
+            }
+            String authorizedEntity = iid.mTokens.keySet().iterator().next().split(",", 3)[1];
+            return Pair.create(iid.getSubtype(), authorizedEntity);
         }
-        FakeInstanceIDWithSubtype iid =
-                (FakeInstanceIDWithSubtype) InstanceIDWithSubtype.sSubtypeInstances.values()
-                        .iterator()
-                        .next();
-        if (iid.mTokens.size() != 1) {
-            throw new IllegalStateException(
-                    "Expected exactly one token, but there are " + iid.mTokens.size());
-        }
-        String authorizedEntity = iid.mTokens.keySet().iterator().next().split(",", 3)[1];
-        return Pair.create(iid.getSubtype(), authorizedEntity);
     }
 
     private FakeInstanceIDWithSubtype(String subtype) {
@@ -157,7 +157,7 @@
 
     @Override
     public void deleteInstanceID() throws IOException {
-        synchronized (InstanceID.class) {
+        synchronized (sSubtypeInstancesLock) {
             sSubtypeInstances.remove(getSubtype());
 
             // InstanceID.deleteInstanceID calls InstanceID.deleteToken which enforces this.
diff --git a/components/history/core/browser/typed_url_sync_bridge.cc b/components/history/core/browser/typed_url_sync_bridge.cc
index 1eb2e4c..159c4629 100644
--- a/components/history/core/browser/typed_url_sync_bridge.cc
+++ b/components/history/core/browser/typed_url_sync_bridge.cc
@@ -278,7 +278,8 @@
     }
 
     VisitVector visits_vector;
-    FixupURLAndGetVisits(&url_row, &visits_vector);
+    if (!FixupURLAndGetVisits(&url_row, &visits_vector))
+      continue;
     std::unique_ptr<syncer::EntityData> entity_data =
         CreateEntityData(url_row, visits_vector);
     if (!entity_data.get()) {
@@ -307,7 +308,8 @@
   auto batch = base::MakeUnique<MutableDataBatch>();
   for (URLRow& url : typed_urls) {
     VisitVector visits_vector;
-    FixupURLAndGetVisits(&url, &visits_vector);
+    if (!FixupURLAndGetVisits(&url, &visits_vector))
+      continue;
     std::unique_ptr<syncer::EntityData> entity_data =
         CreateEntityData(url, visits_vector);
     if (!entity_data.get()) {
diff --git a/components/history/core/browser/typed_url_sync_bridge_unittest.cc b/components/history/core/browser/typed_url_sync_bridge_unittest.cc
index 5b851c1..488a66c 100644
--- a/components/history/core/browser/typed_url_sync_bridge_unittest.cc
+++ b/components/history/core/browser/typed_url_sync_bridge_unittest.cc
@@ -470,18 +470,21 @@
 // Add two typed urls locally and verify bridge can get them from GetAllData.
 TEST_F(TypedURLSyncBridgeTest, GetAllData) {
   // Add two urls to backend.
-  VisitVector visits1, visits2;
+  VisitVector visits1, visits2, visits3;
   URLRow row1 = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits1);
   URLRow row2 = MakeTypedUrlRow(kURL2, kTitle2, 2, 4, false, &visits2);
+  URLRow expired_row = MakeTypedUrlRow("http://expired.com/", kTitle, 1,
+                                       kExpiredVisit, false, &visits3);
   fake_history_backend_->SetVisitsForUrl(row1, visits1);
   fake_history_backend_->SetVisitsForUrl(row2, visits2);
+  fake_history_backend_->SetVisitsForUrl(expired_row, visits3);
 
   // Create the same data in sync.
   TypedUrlSpecifics typed_url1, typed_url2;
   WriteToTypedUrlSpecifics(row1, visits1, &typed_url1);
   WriteToTypedUrlSpecifics(row2, visits2, &typed_url2);
 
-  // Check that the local cache is still correct.
+  // Check that the local cache is still correct, expired row is filtered out.
   VerifyAllLocalHistoryData({typed_url1, typed_url2});
 }
 
diff --git a/components/patch_service/BUILD.gn b/components/patch_service/BUILD.gn
new file mode 100644
index 0000000..ff82f4b
--- /dev/null
+++ b/components/patch_service/BUILD.gn
@@ -0,0 +1,32 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//services/service_manager/public/cpp/service.gni")
+import("//services/service_manager/public/service_manifest.gni")
+
+source_set("lib") {
+  sources = [
+    "file_patcher_impl.cc",
+    "file_patcher_impl.h",
+    "patch_service.cc",
+    "patch_service.h",
+  ]
+
+  deps = [
+    "//base",
+    "//components/filesystem/public/interfaces",
+    "//courgette:courgette_lib",
+    "//mojo/public/cpp/bindings",
+  ]
+
+  public_deps = [
+    "//components/patch_service/public/interfaces",
+    "//services/service_manager/public/cpp",
+  ]
+}
+
+service_manifest("manifest") {
+  name = "patch_service"
+  source = "manifest.json"
+}
diff --git a/components/patch_service/DEPS b/components/patch_service/DEPS
new file mode 100644
index 0000000..ea7209ad8
--- /dev/null
+++ b/components/patch_service/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+  "+components/update_client",
+  "+courgette",
+  "+mojo",  # By definition.
+  "+services/service_manager/public",  # Every service talks to Service Manager.
+]
diff --git a/components/patch_service/OWNERS b/components/patch_service/OWNERS
new file mode 100644
index 0000000..f232b6d
--- /dev/null
+++ b/components/patch_service/OWNERS
@@ -0,0 +1,5 @@
+sorin@chromium.org
+waffles@chromium.org
+
+per-file manifest.json=set noparent
+per-file manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/components/patch_service/README.md b/components/patch_service/README.md
new file mode 100644
index 0000000..4daf4f7e
--- /dev/null
+++ b/components/patch_service/README.md
@@ -0,0 +1,3 @@
+Mojo service that exposes an interface that can be used to patch files using the
+BSDiff or the Courgette algorithm.
+
diff --git a/components/patch_service/file_patcher_impl.cc b/components/patch_service/file_patcher_impl.cc
new file mode 100644
index 0000000..76989de4
--- /dev/null
+++ b/components/patch_service/file_patcher_impl.cc
@@ -0,0 +1,44 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/patch_service/file_patcher_impl.h"
+
+#include "courgette/courgette.h"
+#include "courgette/third_party/bsdiff/bsdiff.h"
+
+namespace patch {
+
+FilePatcherImpl::FilePatcherImpl(
+    std::unique_ptr<service_manager::ServiceContextRef> service_ref)
+    : service_ref_(std::move(service_ref)) {}
+
+FilePatcherImpl::~FilePatcherImpl() = default;
+
+void FilePatcherImpl::PatchFileBsdiff(base::File input_file,
+                                      base::File patch_file,
+                                      base::File output_file,
+                                      PatchFileBsdiffCallback callback) {
+  DCHECK(input_file.IsValid());
+  DCHECK(patch_file.IsValid());
+  DCHECK(output_file.IsValid());
+
+  const int patch_result_status = bsdiff::ApplyBinaryPatch(
+      std::move(input_file), std::move(patch_file), std::move(output_file));
+  std::move(callback).Run(patch_result_status);
+}
+
+void FilePatcherImpl::PatchFileCourgette(base::File input_file,
+                                         base::File patch_file,
+                                         base::File output_file,
+                                         PatchFileCourgetteCallback callback) {
+  DCHECK(input_file.IsValid());
+  DCHECK(patch_file.IsValid());
+  DCHECK(output_file.IsValid());
+
+  const int patch_result_status = courgette::ApplyEnsemblePatch(
+      std::move(input_file), std::move(patch_file), std::move(output_file));
+  std::move(callback).Run(patch_result_status);
+}
+
+}  // namespace patch
diff --git a/components/patch_service/file_patcher_impl.h b/components/patch_service/file_patcher_impl.h
new file mode 100644
index 0000000..73a1df7
--- /dev/null
+++ b/components/patch_service/file_patcher_impl.h
@@ -0,0 +1,41 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PATCH_SERVICE_FILE_PATCHER_IMPL_H_
+#define COMPONENTS_PATCH_SERVICE_FILE_PATCHER_IMPL_H_
+
+#include <memory>
+
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "components/patch_service/public/interfaces/file_patcher.mojom.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
+
+namespace patch {
+
+class FilePatcherImpl : public mojom::FilePatcher {
+ public:
+  explicit FilePatcherImpl(
+      std::unique_ptr<service_manager::ServiceContextRef> service_ref);
+  ~FilePatcherImpl() override;
+
+ private:
+  // patch::mojom::FilePatcher:
+  void PatchFileBsdiff(base::File input_file,
+                       base::File patch_file,
+                       base::File output_file,
+                       PatchFileBsdiffCallback callback) override;
+  void PatchFileCourgette(base::File input_file,
+                          base::File patch_file,
+                          base::File output_file,
+                          PatchFileCourgetteCallback callback) override;
+
+  const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePatcherImpl);
+};
+
+}  // namespace patch
+
+#endif  // COMPONENTS_PATCH_SERVICE_FILE_PATCHER_IMPL_H_
diff --git a/components/patch_service/manifest.json b/components/patch_service/manifest.json
new file mode 100644
index 0000000..5afcc109
--- /dev/null
+++ b/components/patch_service/manifest.json
@@ -0,0 +1,15 @@
+{
+  "name": "patch_service",
+  "display_name": "Patch Service",
+  "sandbox_type": "utility",
+  "interface_provider_specs": {
+    "service_manager:connector": {
+      "provides": {
+        "patch_file": [ "patch::mojom::FilePatcher" ]
+       },
+       "requires": {
+         "service_manager": [ "service_manager:all_users" ]
+       }
+     }
+  }
+}
diff --git a/components/patch_service/patch_service.cc b/components/patch_service/patch_service.cc
new file mode 100644
index 0000000..b92536e
--- /dev/null
+++ b/components/patch_service/patch_service.cc
@@ -0,0 +1,47 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/patch_service/patch_service.h"
+
+#include "build/build_config.h"
+#include "components/patch_service/file_patcher_impl.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+
+namespace patch {
+
+namespace {
+
+void OnFilePatcherRequest(
+    service_manager::ServiceContextRefFactory* ref_factory,
+    patch::mojom::FilePatcherRequest request) {
+  mojo::MakeStrongBinding(
+      std::make_unique<FilePatcherImpl>(ref_factory->CreateRef()),
+      std::move(request));
+}
+
+}  // namespace
+
+PatchService::PatchService() = default;
+
+PatchService::~PatchService() = default;
+
+std::unique_ptr<service_manager::Service> PatchService::CreateService() {
+  return std::make_unique<PatchService>();
+}
+
+void PatchService::OnStart() {
+  ref_factory_.reset(new service_manager::ServiceContextRefFactory(
+      base::Bind(&service_manager::ServiceContext::RequestQuit,
+                 base::Unretained(context()))));
+  registry_.AddInterface(base::Bind(&OnFilePatcherRequest, ref_factory_.get()));
+}
+
+void PatchService::OnBindInterface(
+    const service_manager::BindSourceInfo& source_info,
+    const std::string& interface_name,
+    mojo::ScopedMessagePipeHandle interface_pipe) {
+  registry_.BindInterface(interface_name, std::move(interface_pipe));
+}
+
+}  //  namespace patch
diff --git a/components/patch_service/patch_service.h b/components/patch_service/patch_service.h
new file mode 100644
index 0000000..a5d9dcfe
--- /dev/null
+++ b/components/patch_service/patch_service.h
@@ -0,0 +1,40 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PATCH_SERVICE_PATCH_SERVICE_H_
+#define COMPONENTS_PATCH_SERVICE_PATCH_SERVICE_H_
+
+#include <memory>
+
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/service_context.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
+
+namespace patch {
+
+class PatchService : public service_manager::Service {
+ public:
+  PatchService();
+  ~PatchService() override;
+
+  // Factory method for creating the service.
+  static std::unique_ptr<service_manager::Service> CreateService();
+
+  // Lifescycle events that occur after the service has started to spinup.
+  void OnStart() override;
+  void OnBindInterface(const service_manager::BindSourceInfo& source_info,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override;
+
+ private:
+  // State needed to manage service lifecycle and lifecycle of bound clients.
+  std::unique_ptr<service_manager::ServiceContextRefFactory> ref_factory_;
+  service_manager::BinderRegistry registry_;
+
+  DISALLOW_COPY_AND_ASSIGN(PatchService);
+};
+
+}  // namespace patch
+
+#endif  // COMPONENTS_PATCH_SERVICE_PATCH_SERVICE_H_
diff --git a/components/patch_service/public/cpp/BUILD.gn b/components/patch_service/public/cpp/BUILD.gn
new file mode 100644
index 0000000..c463436
--- /dev/null
+++ b/components/patch_service/public/cpp/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+source_set("cpp") {
+  sources = [
+    "patch.cc",
+    "patch.h",
+  ]
+
+  public_deps = [
+    "//components/patch_service/public/interfaces",
+    "//services/service_manager/public/cpp",
+  ]
+}
diff --git a/components/patch_service/public/cpp/patch.cc b/components/patch_service/public/cpp/patch.cc
new file mode 100644
index 0000000..b9ffba10
--- /dev/null
+++ b/components/patch_service/public/cpp/patch.cc
@@ -0,0 +1,107 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/patch_service/public/cpp/patch.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/string16.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "components/patch_service/public/interfaces/constants.mojom.h"
+#include "components/patch_service/public/interfaces/file_patcher.mojom.h"
+#include "components/update_client/component_patcher_operation.h"  // nogncheck
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace patch {
+
+namespace {
+
+class PatchParams : public base::RefCounted<PatchParams> {
+ public:
+  PatchParams(mojom::FilePatcherPtr file_patcher, PatchCallback callback)
+      : file_patcher_(std::move(file_patcher)),
+        callback_(std::move(callback)) {}
+
+  mojom::FilePatcherPtr* file_patcher() { return &file_patcher_; }
+
+  PatchCallback TakeCallback() { return std::move(callback_); }
+
+ private:
+  friend class base::RefCounted<PatchParams>;
+
+  ~PatchParams() = default;
+
+  // The FilePatcherPtr is stored so it does not get deleted before the callback
+  // runs.
+  mojom::FilePatcherPtr file_patcher_;
+
+  PatchCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(PatchParams);
+};
+
+void PatchDone(scoped_refptr<PatchParams> params, int result) {
+  params->TakeCallback().Run(result);
+}
+
+}  // namespace
+
+void Patch(service_manager::Connector* connector,
+           const std::string& operation,
+           const base::FilePath& input_path,
+           const base::FilePath& patch_path,
+           const base::FilePath& output_path,
+           PatchCallback callback) {
+  DCHECK(!callback.is_null());
+
+  base::File input_file(input_path,
+                        base::File::FLAG_OPEN | base::File::FLAG_READ);
+  base::File patch_file(patch_path,
+                        base::File::FLAG_OPEN | base::File::FLAG_READ);
+  base::File output_file(output_path, base::File::FLAG_CREATE |
+                                          base::File::FLAG_WRITE |
+                                          base::File::FLAG_EXCLUSIVE_WRITE);
+
+  if (!input_file.IsValid() || !patch_file.IsValid() ||
+      !output_file.IsValid()) {
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), /*result=*/-1));
+    return;
+  }
+
+  mojom::FilePatcherPtr file_patcher;
+  connector->BindInterface(mojom::kServiceName,
+                           mojo::MakeRequest(&file_patcher));
+
+  // In order to share |callback| between the connection error handler and the
+  // FilePatcher calls, we have to use a context object.
+  scoped_refptr<PatchParams> patch_params =
+      new PatchParams(std::move(file_patcher), std::move(callback));
+
+  patch_params->file_patcher()->set_connection_error_handler(
+      base::Bind(&PatchDone, patch_params, /*result=*/-1));
+
+  if (operation == update_client::kBsdiff) {
+    (*patch_params->file_patcher())
+        ->PatchFileBsdiff(std::move(input_file), std::move(patch_file),
+                          std::move(output_file),
+                          base::Bind(&PatchDone, patch_params));
+  } else if (operation == update_client::kCourgette) {
+    (*patch_params->file_patcher())
+        ->PatchFileCourgette(std::move(input_file), std::move(patch_file),
+                             std::move(output_file),
+                             base::Bind(&PatchDone, patch_params));
+  } else {
+    NOTREACHED();
+  }
+}
+
+}  // namespace patch
\ No newline at end of file
diff --git a/components/patch_service/public/cpp/patch.h b/components/patch_service/public/cpp/patch.h
new file mode 100644
index 0000000..e1f2f8d
--- /dev/null
+++ b/components/patch_service/public/cpp/patch.h
@@ -0,0 +1,34 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PATCH_SERVICE_PUBLIC_CPP_PATCH_H_
+#define COMPONENTS_PATCH_SERVICE_PUBLIC_CPP_PATCH_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace service_manager {
+class Connector;
+}
+
+namespace patch {
+
+// Patches |input_abs_path| with |patch_abs_path| using the |operation|
+// algorithm and place the output in |output_abs_path|.
+using PatchCallback = base::OnceCallback<void(int result)>;
+void Patch(service_manager::Connector* connector,
+           const std::string& operation,
+           const base::FilePath& input_abs_path,
+           const base::FilePath& patch_abs_path,
+           const base::FilePath& output_abs_path,
+           PatchCallback callback);
+
+}  // namespace patch
+
+#endif  // COMPONENTS_PATCH_SERVICE_PUBLIC_CPP_PATCH_H_
diff --git a/components/patch_service/public/interfaces/BUILD.gn b/components/patch_service/public/interfaces/BUILD.gn
new file mode 100644
index 0000000..89b83f2
--- /dev/null
+++ b/components/patch_service/public/interfaces/BUILD.gn
@@ -0,0 +1,22 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+  sources = [
+    "file_patcher.mojom",
+  ]
+
+  public_deps = [
+    ":constants",
+    "//mojo/common:common_custom_types",
+  ]
+}
+
+mojom("constants") {
+  sources = [
+    "constants.mojom",
+  ]
+}
diff --git a/components/patch_service/public/interfaces/OWNERS b/components/patch_service/public/interfaces/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/components/patch_service/public/interfaces/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/components/patch_service/public/interfaces/constants.mojom b/components/patch_service/public/interfaces/constants.mojom
new file mode 100644
index 0000000..fa5ad3c7
--- /dev/null
+++ b/components/patch_service/public/interfaces/constants.mojom
@@ -0,0 +1,7 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module patch.mojom;
+
+const string kServiceName = "patch_service";
diff --git a/chrome/common/file_patcher.mojom b/components/patch_service/public/interfaces/file_patcher.mojom
similarity index 85%
rename from chrome/common/file_patcher.mojom
rename to components/patch_service/public/interfaces/file_patcher.mojom
index 9bc13238..60758f8b 100644
--- a/chrome/common/file_patcher.mojom
+++ b/components/patch_service/public/interfaces/file_patcher.mojom
@@ -2,10 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// File patching interface provided by the utility process and exposed by
-// mojo policy control to the chrome browser process.
-
-module chrome.mojom;
+module patch.mojom;
 
 import "mojo/common/file.mojom";
 
diff --git a/components/payments/content/payment_request_converter.cc b/components/payments/content/payment_request_converter.cc
index f356eb5..57c6002e 100644
--- a/components/payments/content/payment_request_converter.cc
+++ b/components/payments/content/payment_request_converter.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "base/memory/ptr_util.h"
-#include "components/autofill/core/browser/credit_card.h"
 #include "components/payments/core/payment_currency_amount.h"
 #include "components/payments/core/payment_details.h"
 #include "components/payments/core/payment_details_modifier.h"
@@ -18,46 +17,6 @@
 namespace payments {
 namespace {
 
-// Returns the card type associated with the given BasicCardType.
-autofill::CreditCard::CardType GetBasicCardType(
-    const mojom::BasicCardType& type) {
-  switch (type) {
-    case mojom::BasicCardType::CREDIT:
-      return autofill::CreditCard::CARD_TYPE_CREDIT;
-    case mojom::BasicCardType::DEBIT:
-      return autofill::CreditCard::CARD_TYPE_DEBIT;
-    case mojom::BasicCardType::PREPAID:
-      return autofill::CreditCard::CARD_TYPE_PREPAID;
-  }
-  NOTREACHED();
-  return autofill::CreditCard::CARD_TYPE_UNKNOWN;
-}
-
-// Returns the card network name associated with a given BasicCardNetwork. Names
-// are inspired by https://www.w3.org/Payments/card-network-ids.
-std::string GetBasicCardNetworkName(const mojom::BasicCardNetwork& network) {
-  switch (network) {
-    case mojom::BasicCardNetwork::AMEX:
-      return "amex";
-    case mojom::BasicCardNetwork::DINERS:
-      return "diners";
-    case mojom::BasicCardNetwork::DISCOVER:
-      return "discover";
-    case mojom::BasicCardNetwork::JCB:
-      return "jcb";
-    case mojom::BasicCardNetwork::MASTERCARD:
-      return "mastercard";
-    case mojom::BasicCardNetwork::MIR:
-      return "mir";
-    case mojom::BasicCardNetwork::UNIONPAY:
-      return "unionpay";
-    case mojom::BasicCardNetwork::VISA:
-      return "visa";
-  }
-  NOTREACHED();
-  return std::string();
-}
-
 PaymentCurrencyAmount ConvertPaymentCurrencyAmount(
     const mojom::PaymentCurrencyAmountPtr& amount_entry) {
   PaymentCurrencyAmount amount;
@@ -109,6 +68,43 @@
 
 }  // namespace
 
+autofill::CreditCard::CardType GetBasicCardType(
+    const mojom::BasicCardType& type) {
+  switch (type) {
+    case mojom::BasicCardType::CREDIT:
+      return autofill::CreditCard::CARD_TYPE_CREDIT;
+    case mojom::BasicCardType::DEBIT:
+      return autofill::CreditCard::CARD_TYPE_DEBIT;
+    case mojom::BasicCardType::PREPAID:
+      return autofill::CreditCard::CARD_TYPE_PREPAID;
+  }
+  NOTREACHED();
+  return autofill::CreditCard::CARD_TYPE_UNKNOWN;
+}
+
+std::string GetBasicCardNetworkName(const mojom::BasicCardNetwork& network) {
+  switch (network) {
+    case mojom::BasicCardNetwork::AMEX:
+      return "amex";
+    case mojom::BasicCardNetwork::DINERS:
+      return "diners";
+    case mojom::BasicCardNetwork::DISCOVER:
+      return "discover";
+    case mojom::BasicCardNetwork::JCB:
+      return "jcb";
+    case mojom::BasicCardNetwork::MASTERCARD:
+      return "mastercard";
+    case mojom::BasicCardNetwork::MIR:
+      return "mir";
+    case mojom::BasicCardNetwork::UNIONPAY:
+      return "unionpay";
+    case mojom::BasicCardNetwork::VISA:
+      return "visa";
+  }
+  NOTREACHED();
+  return std::string();
+}
+
 PaymentMethodData ConvertPaymentMethodData(
     const mojom::PaymentMethodDataPtr& method_data_entry) {
   PaymentMethodData method_data;
diff --git a/components/payments/content/payment_request_converter.h b/components/payments/content/payment_request_converter.h
index 9f91697..b856ef3 100644
--- a/components/payments/content/payment_request_converter.h
+++ b/components/payments/content/payment_request_converter.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_CONVERTER_H_
 #define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_CONVERTER_H_
 
+#include "components/autofill/core/browser/credit_card.h"
 #include "third_party/WebKit/public/platform/modules/payments/payment_request.mojom.h"
 
 // TODO(crbug.com/760945): Write unit tests for these functions.
@@ -14,6 +15,14 @@
 class PaymentDetails;
 class PaymentMethodData;
 
+// Returns the card type associated with the given BasicCardType.
+autofill::CreditCard::CardType GetBasicCardType(
+    const mojom::BasicCardType& type);
+
+// Returns the card network name associated with a given BasicCardNetwork. Names
+// are inspired by https://www.w3.org/Payments/card-network-ids.
+std::string GetBasicCardNetworkName(const mojom::BasicCardNetwork& network);
+
 PaymentMethodData ConvertPaymentMethodData(
     const mojom::PaymentMethodDataPtr& method_data_entry);
 
diff --git a/components/payments/content/payment_request_spec.cc b/components/payments/content/payment_request_spec.cc
index 4d1fe9b8..5e4a141 100644
--- a/components/payments/content/payment_request_spec.cc
+++ b/components/payments/content/payment_request_spec.cc
@@ -226,11 +226,11 @@
     return nullptr;
 
   for (const auto& modifier : details_->modifiers) {
-    std::vector<std::string> supported_networks;
+    std::set<std::string> supported_card_networks_set;
     std::set<autofill::CreditCard::CardType> supported_types;
     // The following 4 are unused but required by PopulateValidatedMethodData.
     std::set<std::string> basic_card_specified_networks;
-    std::set<std::string> supported_card_networks_set;
+    std::vector<std::string> supported_networks;
     std::vector<GURL> url_payment_method_identifiers;
     std::set<std::string> payment_method_identifiers_set;
     std::map<std::string, std::set<std::string>> stringified_method_data;
@@ -241,8 +241,10 @@
         &payment_method_identifiers_set, &stringified_method_data);
 
     if (selected_instrument->IsValidForModifier(
-            modifier->method_data->supported_methods, supported_networks,
-            supported_types, !modifier->method_data->supported_types.empty())) {
+            modifier->method_data->supported_methods,
+            !modifier->method_data->supported_networks.empty(),
+            supported_card_networks_set,
+            !modifier->method_data->supported_types.empty(), supported_types)) {
       return &modifier;
     }
   }
diff --git a/components/payments/content/service_worker_payment_instrument.cc b/components/payments/content/service_worker_payment_instrument.cc
index fd80e39..446e87a3 100644
--- a/components/payments/content/service_worker_payment_instrument.cc
+++ b/components/payments/content/service_worker_payment_instrument.cc
@@ -6,6 +6,7 @@
 
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/payments/content/payment_request_converter.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/payment_app_provider.h"
 #include "ui/gfx/image/image_skia.h"
@@ -37,6 +38,9 @@
     icon_image_ =
         gfx::ImageSkia::CreateFrom1xBitmap(*(stored_payment_app_info_->icon))
             .DeepCopy();
+  } else {
+    // Create an empty icon image to avoid using invalid icon resource id.
+    icon_image_ = gfx::ImageSkia::CreateFrom1xBitmap(SkBitmap()).DeepCopy();
   }
 }
 
@@ -147,17 +151,73 @@
 }
 
 bool ServiceWorkerPaymentInstrument::IsValidForModifier(
-    const std::vector<std::string>& method,
-    const std::vector<std::string>& supported_networks,
-    const std::set<autofill::CreditCard::CardType>& supported_types,
-    bool supported_types_specified) const {
-  for (const auto& modifier_supported_method : method) {
+    const std::vector<std::string>& methods,
+    bool supported_networks_specified,
+    const std::set<std::string>& supported_networks,
+    bool supported_types_specified,
+    const std::set<autofill::CreditCard::CardType>& supported_types) const {
+  std::vector<std::string> matched_methods;
+  for (const auto& modifier_supported_method : methods) {
     if (base::ContainsValue(stored_payment_app_info_->enabled_methods,
                             modifier_supported_method)) {
-      return true;
+      matched_methods.emplace_back(modifier_supported_method);
     }
   }
-  return false;
+
+  if (matched_methods.empty())
+    return false;
+
+  if (matched_methods.size() > 1U || matched_methods[0] != "basic-card")
+    return true;
+
+  // Checking the capabilities of this instrument against the modifier.
+  // Return true if both card networks and types are not specified in the
+  // modifier.
+  if (!supported_networks_specified && !supported_types_specified)
+    return true;
+
+  // Return false if no capabilities for this instrument.
+  if (stored_payment_app_info_->capabilities.empty())
+    return false;
+
+  uint32_t i = 0;
+  for (; i < stored_payment_app_info_->capabilities.size(); i++) {
+    if (supported_networks_specified) {
+      std::set<std::string> app_supported_networks;
+      for (const auto& network :
+           stored_payment_app_info_->capabilities[i].supported_card_networks) {
+        app_supported_networks.insert(GetBasicCardNetworkName(
+            static_cast<mojom::BasicCardNetwork>(network)));
+      }
+
+      if (base::STLSetIntersection<std::set<std::string>>(
+              app_supported_networks, supported_networks)
+              .empty()) {
+        continue;
+      }
+    }
+
+    if (supported_types_specified) {
+      std::set<autofill::CreditCard::CardType> app_supported_types;
+      for (const auto& type :
+           stored_payment_app_info_->capabilities[i].supported_card_types) {
+        app_supported_types.insert(
+            GetBasicCardType(static_cast<mojom::BasicCardType>(type)));
+      }
+
+      if (base::STLSetIntersection<std::set<autofill::CreditCard::CardType>>(
+              app_supported_types, supported_types)
+              .empty()) {
+        continue;
+      }
+    }
+
+    break;
+  }
+
+  // i >= stored_payment_app_info_->capabilities.size() indicates no matched
+  // capabilities.
+  return i < stored_payment_app_info_->capabilities.size();
 }
 
 const gfx::ImageSkia* ServiceWorkerPaymentInstrument::icon_image_skia() const {
diff --git a/components/payments/content/service_worker_payment_instrument.h b/components/payments/content/service_worker_payment_instrument.h
index 53507cd5..6842dff7d 100644
--- a/components/payments/content/service_worker_payment_instrument.h
+++ b/components/payments/content/service_worker_payment_instrument.h
@@ -34,11 +34,12 @@
   void RecordUse() override;
   base::string16 GetLabel() const override;
   base::string16 GetSublabel() const override;
-  bool IsValidForModifier(
-      const std::vector<std::string>& method,
-      const std::vector<std::string>& supported_networks,
-      const std::set<autofill::CreditCard::CardType>& supported_types,
-      bool supported_types_specified) const override;
+  bool IsValidForModifier(const std::vector<std::string>& methods,
+                          bool supported_networks_specified,
+                          const std::set<std::string>& supported_networks,
+                          bool supported_types_specified,
+                          const std::set<autofill::CreditCard::CardType>&
+                              supported_types) const override;
   const gfx::ImageSkia* icon_image_skia() const override;
 
  private:
diff --git a/components/payments/content/service_worker_payment_instrument_unittest.cc b/components/payments/content/service_worker_payment_instrument_unittest.cc
index 41423bf0..4b34cea 100644
--- a/components/payments/content/service_worker_payment_instrument_unittest.cc
+++ b/components/payments/content/service_worker_payment_instrument_unittest.cc
@@ -51,12 +51,23 @@
     modifier_2->method_data->supported_methods = {"https://bobpay.com"};
     details->modifiers.push_back(std::move(modifier_2));
 
+    mojom::PaymentDetailsModifierPtr modifier_3 =
+        mojom::PaymentDetailsModifier::New();
+    modifier_3->total = mojom::PaymentItem::New();
+    modifier_3->total->amount = mojom::PaymentCurrencyAmount::New();
+    modifier_3->total->amount->currency = "USD";
+    modifier_3->total->amount->value = "2.00";
+    modifier_3->method_data = mojom::PaymentMethodData::New();
+    modifier_3->method_data->supported_methods = {"https://alicepay.com"};
+    details->modifiers.push_back(std::move(modifier_3));
+
     std::vector<mojom::PaymentMethodDataPtr> method_data;
     mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
     entry->supported_methods.push_back("basic-card");
     entry->supported_networks.push_back(mojom::BasicCardNetwork::UNIONPAY);
     entry->supported_networks.push_back(mojom::BasicCardNetwork::JCB);
     entry->supported_networks.push_back(mojom::BasicCardNetwork::VISA);
+    entry->supported_types.push_back(mojom::BasicCardType::DEBIT);
     method_data.push_back(std::move(entry));
 
     spec_ = base::MakeUnique<PaymentRequestSpec>(
@@ -70,6 +81,14 @@
     stored_app->name = "bobpay";
     stored_app->icon.reset(new SkBitmap());
     stored_app->enabled_methods.emplace_back("basic-card");
+    stored_app->enabled_methods.emplace_back("https://bobpay.com");
+    stored_app->capabilities.emplace_back(content::StoredCapabilities());
+    stored_app->capabilities.back().supported_card_networks.emplace_back(
+        static_cast<int32_t>(mojom::BasicCardNetwork::UNIONPAY));
+    stored_app->capabilities.back().supported_card_networks.emplace_back(
+        static_cast<int32_t>(mojom::BasicCardNetwork::JCB));
+    stored_app->capabilities.back().supported_card_types.emplace_back(
+        static_cast<int32_t>(mojom::BasicCardType::DEBIT));
     stored_app->user_hint = "Visa 4012 ... 1881";
     stored_app->prefer_related_applications = false;
 
@@ -105,15 +124,6 @@
   EXPECT_EQ(base::UTF16ToUTF8(GetInstrument()->GetSublabel()),
             "https://bobpay.com/");
   EXPECT_NE(GetInstrument()->icon_image_skia(), nullptr);
-
-  EXPECT_TRUE(
-      GetInstrument()->IsValidForModifier({"basic-card"}, {}, {}, false));
-  // Note that supported networks and types have not been implemented, so
-  // here returns true.
-  EXPECT_TRUE(GetInstrument()->IsValidForModifier(
-      {"basic-card", "https://bobpay.com"}, {"Mastercard"}, {}, true));
-  EXPECT_FALSE(GetInstrument()->IsValidForModifier({"https://bobpay.com"}, {},
-                                                   {}, false));
 }
 
 // Test payment request event can be correctly constructed for invoking
@@ -130,15 +140,50 @@
   EXPECT_EQ(event_data->method_data[0]->supported_methods.size(), 1U);
   EXPECT_EQ(event_data->method_data[0]->supported_methods[0], "basic-card");
   EXPECT_EQ(event_data->method_data[0]->supported_networks.size(), 3U);
+  EXPECT_EQ(event_data->method_data[0]->supported_types.size(), 1U);
 
   EXPECT_EQ(event_data->total->currency, "USD");
   EXPECT_EQ(event_data->total->value, "5.00");
 
-  EXPECT_EQ(event_data->modifiers.size(), 1U);
+  EXPECT_EQ(event_data->modifiers.size(), 2U);
   EXPECT_EQ(event_data->modifiers[0]->total->amount->value, "4.00");
   EXPECT_EQ(event_data->modifiers[0]->total->amount->currency, "USD");
   EXPECT_EQ(event_data->modifiers[0]->method_data->supported_methods[0],
             "basic-card");
+  EXPECT_EQ(event_data->modifiers[1]->total->amount->value, "3.00");
+  EXPECT_EQ(event_data->modifiers[1]->total->amount->currency, "USD");
+  EXPECT_EQ(event_data->modifiers[1]->method_data->supported_methods[0],
+            "https://bobpay.com");
+}
+
+// Test modifiers can be matched based on capabilities.
+TEST_F(ServiceWorkerPaymentInstrumentTest, IsValidForModifier) {
+  EXPECT_TRUE(GetInstrument()->IsValidForModifier({"basic-card"}, false, {},
+                                                  false, {}));
+
+  EXPECT_TRUE(GetInstrument()->IsValidForModifier({"https://bobpay.com"}, true,
+                                                  {}, true, {}));
+
+  EXPECT_TRUE(GetInstrument()->IsValidForModifier(
+      {"basic-card", "https://bobpay.com"}, false, {}, false, {}));
+
+  EXPECT_TRUE(GetInstrument()->IsValidForModifier(
+      {"basic-card", "https://bobpay.com"}, true, {"mastercard"}, false, {}));
+
+  EXPECT_FALSE(GetInstrument()->IsValidForModifier({"basic-card"}, true,
+                                                   {"mastercard"}, false, {}));
+
+  EXPECT_TRUE(GetInstrument()->IsValidForModifier({"basic-card"}, true,
+                                                  {"unionpay"}, false, {}));
+
+  EXPECT_TRUE(GetInstrument()->IsValidForModifier(
+      {"basic-card"}, true, {"unionpay"}, true,
+      {autofill::CreditCard::CardType::CARD_TYPE_DEBIT,
+       autofill::CreditCard::CardType::CARD_TYPE_CREDIT}));
+
+  EXPECT_FALSE(GetInstrument()->IsValidForModifier(
+      {"basic-card"}, true, {"unionpay"}, true,
+      {autofill::CreditCard::CardType::CARD_TYPE_CREDIT}));
 }
 
 }  // namespace payments
diff --git a/components/payments/core/autofill_payment_instrument.cc b/components/payments/core/autofill_payment_instrument.cc
index 4118cd4..40fa03d 100644
--- a/components/payments/core/autofill_payment_instrument.cc
+++ b/components/payments/core/autofill_payment_instrument.cc
@@ -124,42 +124,41 @@
 }
 
 bool AutofillPaymentInstrument::IsValidForModifier(
-    const std::vector<std::string>& method,
-    const std::vector<std::string>& supported_networks,
-    const std::set<autofill::CreditCard::CardType>& supported_types,
-    bool supported_types_specified) const {
+    const std::vector<std::string>& methods,
+    bool supported_networks_specified,
+    const std::set<std::string>& supported_networks,
+    bool supported_types_specified,
+    const std::set<autofill::CreditCard::CardType>& supported_types) const {
   // This instrument only matches basic-card.
-  if (std::find(method.begin(), method.end(), "basic-card") == method.end())
+  if (std::find(methods.begin(), methods.end(), "basic-card") == methods.end())
     return false;
 
   // If supported_types is not specified and this instrument matches the method,
   // the modifier is applicable. If supported_types is populated, it must
   // contain this card's type to be applicable. The same is true for
   // supported_networks.
-  bool is_supported_type =
-      std::find(supported_types.begin(), supported_types.end(),
-                credit_card_.card_type()) != supported_types.end();
+  if (supported_types_specified) {
+    // supported_types may contain CARD_TYPE_UNKNOWN because of the parsing
+    // function so the local card only matches if it's because the website
+    // didn't specify types (meaning they don't care).
+    if (credit_card_.card_type() ==
+        autofill::CreditCard::CardType::CARD_TYPE_UNKNOWN) {
+      return false;
+    }
 
-  // supported_types may contain CARD_TYPE_UNKNOWN because of the parsing
-  // function so the local card only matches if it's because the website didn't
-  // specify types (meaning they don't care).
-  if (is_supported_type &&
-      credit_card_.card_type() ==
-          autofill::CreditCard::CardType::CARD_TYPE_UNKNOWN &&
-      supported_types_specified)
-    return false;
+    if (supported_types.find(credit_card_.card_type()) == supported_types.end())
+      return false;
+  }
 
-  bool is_supported_network = supported_networks.empty();
-  if (!is_supported_network) {
+  if (supported_networks_specified) {
     std::string basic_card_network =
         autofill::data_util::GetPaymentRequestData(credit_card_.network())
             .basic_card_issuer_network;
-    is_supported_network =
-        std::find(supported_networks.begin(), supported_networks.end(),
-                  basic_card_network) != supported_networks.end();
+    if (supported_networks.find(basic_card_network) == supported_networks.end())
+      return false;
   }
 
-  return is_supported_type && is_supported_network;
+  return true;
 }
 
 void AutofillPaymentInstrument::OnFullCardRequestSucceeded(
diff --git a/components/payments/core/autofill_payment_instrument.h b/components/payments/core/autofill_payment_instrument.h
index 6c54d48..9647a711 100644
--- a/components/payments/core/autofill_payment_instrument.h
+++ b/components/payments/core/autofill_payment_instrument.h
@@ -48,11 +48,12 @@
   void RecordUse() override;
   base::string16 GetLabel() const override;
   base::string16 GetSublabel() const override;
-  bool IsValidForModifier(
-      const std::vector<std::string>& method,
-      const std::vector<std::string>& supported_networks,
-      const std::set<autofill::CreditCard::CardType>& supported_types,
-      bool supported_types_specified) const override;
+  bool IsValidForModifier(const std::vector<std::string>& methods,
+                          bool supported_networks_specified,
+                          const std::set<std::string>& supported_networks,
+                          bool supported_types_specified,
+                          const std::set<autofill::CreditCard::CardType>&
+                              supported_types) const override;
 
   // autofill::payments::FullCardRequest::ResultDelegate:
   void OnFullCardRequestSucceeded(
diff --git a/components/payments/core/payment_instrument.h b/components/payments/core/payment_instrument.h
index 1c7f6110..fe643e4 100644
--- a/components/payments/core/payment_instrument.h
+++ b/components/payments/core/payment_instrument.h
@@ -61,12 +61,14 @@
   virtual const gfx::ImageSkia* icon_image_skia() const;
 
   // Returns true if this payment instrument can be used to fulfill a request
-  // specifying |method| as a supported method of payment, false otherwise.
+  // specifying |methods| as supported methods of payment, false otherwise.
   virtual bool IsValidForModifier(
-      const std::vector<std::string>& method,
-      const std::vector<std::string>& supported_networks,
-      const std::set<autofill::CreditCard::CardType>& supported_types,
-      bool supported_types_specified) const = 0;
+      const std::vector<std::string>& methods,
+      bool supported_networks_specified,
+      const std::set<std::string>& supported_networks,
+      bool supported_types_specified,
+      const std::set<autofill::CreditCard::CardType>& supported_types)
+      const = 0;
 
   int icon_resource_id() const { return icon_resource_id_; }
   Type type() { return type_; }
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/GmsAvailabilityException.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/GmsAvailabilityException.java
index a5b6a48..57d82e5 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/GmsAvailabilityException.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/GmsAvailabilityException.java
@@ -4,7 +4,10 @@
 
 package org.chromium.components.signin;
 
+import com.google.android.gms.common.GoogleApiAvailability;
+
 /**
+ * This class encapsulates return code if GMSCore package is not available.
  */
 public class GmsAvailabilityException extends AccountManagerDelegateException {
     private final int mResultCode;
@@ -22,4 +25,8 @@
     public int getGmsAvailabilityReturnCode() {
         return mResultCode;
     }
+
+    public boolean isUserResolvableError() {
+        return GoogleApiAvailability.getInstance().isUserResolvableError(mResultCode);
+    }
 }
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
index 86b1ac5..b4ddb9a 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
@@ -94,12 +94,10 @@
             return;
         }
 
-        if (GoogleApiAvailability.getInstance().isUserResolvableError(resultCode)) {
-            throw new GmsAvailabilityException(
-                    String.format("Can't use Google Play Services: %s",
-                            GoogleApiAvailability.getInstance().getErrorString(resultCode)),
-                    resultCode);
-        }
+        throw new GmsAvailabilityException(
+                String.format("Can't use Google Play Services: %s",
+                        GoogleApiAvailability.getInstance().getErrorString(resultCode)),
+                resultCode);
     }
 
     @Override
diff --git a/components/sync_bookmarks/bookmark_change_processor.cc b/components/sync_bookmarks/bookmark_change_processor.cc
index 534150f6..0898ac26 100644
--- a/components/sync_bookmarks/bookmark_change_processor.cc
+++ b/components/sync_bookmarks/bookmark_change_processor.cc
@@ -449,10 +449,10 @@
     return;
   }
 
-  // Ignore changes with empty images. This can happen if the favicon is
-  // still being loaded.
-  const gfx::Image& favicon = model->GetFavicon(node);
-  if (favicon.IsEmpty()) {
+  // Ignore favicons that are being loaded.
+  if (!node->is_favicon_loaded()) {
+    // Sutble way to trigger a load of the favicon.
+    model->GetFavicon(node);
     return;
   }
 
@@ -844,7 +844,7 @@
 
 // static
 // Sets the favicon of the given bookmark node from the given sync node.
-bool BookmarkChangeProcessor::SetBookmarkFavicon(
+void BookmarkChangeProcessor::SetBookmarkFavicon(
     const syncer::BaseNode* sync_node,
     const BookmarkNode* bookmark_node,
     BookmarkModel* bookmark_model,
@@ -852,23 +852,12 @@
   const sync_pb::BookmarkSpecifics& specifics =
       sync_node->GetBookmarkSpecifics();
   const std::string& icon_bytes_str = specifics.favicon();
-  if (icon_bytes_str.empty())
-    return false;
-
   scoped_refptr<base::RefCountedString> icon_bytes(
       new base::RefCountedString());
   icon_bytes->data().assign(icon_bytes_str);
-  GURL icon_url(specifics.icon_url());
 
-  // Old clients may not be syncing the favicon URL. If the icon URL is not
-  // synced, use the page URL as a fake icon URL as it is guaranteed to be
-  // unique.
-  if (icon_url.is_empty())
-    icon_url = bookmark_node->url();
-
-  ApplyBookmarkFavicon(bookmark_node, sync_client, icon_url, icon_bytes);
-
-  return true;
+  ApplyBookmarkFavicon(bookmark_node, sync_client, GURL(specifics.icon_url()),
+                       icon_bytes);
 }
 
 // static
@@ -943,14 +932,36 @@
   history::HistoryService* history = sync_client->GetHistoryService();
   favicon::FaviconService* favicon_service = sync_client->GetFaviconService();
 
+  // Some tests (that use FakeSyncClient) use no services.
+  if (history == nullptr)
+    return;
+
+  DCHECK(favicon_service);
   history->AddPageNoVisitForBookmark(bookmark_node->url(),
                                      bookmark_node->GetTitle());
+
+  GURL icon_url_to_use = icon_url;
+
+  if (icon_url.is_empty()) {
+    if (bitmap_data->size() == 0) {
+      // Empty icon URL and no bitmap data means no icon mapping.
+      favicon_service->DeleteFaviconMappings({bookmark_node->url()},
+                                             favicon_base::IconType::kFavicon);
+      return;
+    } else {
+      // Ancient clients (prior to M25) may not be syncing the favicon URL. If
+      // the icon URL is not synced, use the page URL as a fake icon URL as it
+      // is guaranteed to be unique.
+      icon_url_to_use = bookmark_node->url();
+    }
+  }
+
   // The client may have cached the favicon at 2x. Use MergeFavicon() as not to
   // overwrite the cached 2x favicon bitmap. Sync favicons are always
   // gfx::kFaviconSize in width and height. Store the favicon into history
   // as such.
   gfx::Size pixel_size(gfx::kFaviconSize, gfx::kFaviconSize);
-  favicon_service->MergeFavicon(bookmark_node->url(), icon_url,
+  favicon_service->MergeFavicon(bookmark_node->url(), icon_url_to_use,
                                 favicon_base::IconType::kFavicon, bitmap_data,
                                 pixel_size);
 }
@@ -962,16 +973,21 @@
     syncer::WriteNode* sync_node) {
   scoped_refptr<base::RefCountedMemory> favicon_bytes(nullptr);
   EncodeFavicon(bookmark_node, model, &favicon_bytes);
+  sync_pb::BookmarkSpecifics updated_specifics(
+      sync_node->GetBookmarkSpecifics());
+
   if (favicon_bytes.get() && favicon_bytes->size()) {
-    sync_pb::BookmarkSpecifics updated_specifics(
-        sync_node->GetBookmarkSpecifics());
     updated_specifics.set_favicon(favicon_bytes->front(),
                                   favicon_bytes->size());
     updated_specifics.set_icon_url(bookmark_node->icon_url()
                                        ? bookmark_node->icon_url()->spec()
                                        : std::string());
-    sync_node->SetBookmarkSpecifics(updated_specifics);
+  } else {
+    updated_specifics.clear_favicon();
+    updated_specifics.clear_icon_url();
   }
+
+  sync_node->SetBookmarkSpecifics(updated_specifics);
 }
 
 bool BookmarkChangeProcessor::CanSyncNode(const BookmarkNode* node) {
diff --git a/components/sync_bookmarks/bookmark_change_processor.h b/components/sync_bookmarks/bookmark_change_processor.h
index 5427071..f1a5b9d0 100644
--- a/components/sync_bookmarks/bookmark_change_processor.h
+++ b/components/sync_bookmarks/bookmark_change_processor.h
@@ -119,10 +119,9 @@
       int index);
 
   // Sets the favicon of the given bookmark node from the given sync node.
-  // Returns whether the favicon was set in the bookmark node.
   // |profile| is the profile that contains the HistoryService and BookmarkModel
   // for the bookmark in question.
-  static bool SetBookmarkFavicon(const syncer::BaseNode* sync_node,
+  static void SetBookmarkFavicon(const syncer::BaseNode* sync_node,
                                  const bookmarks::BookmarkNode* bookmark_node,
                                  bookmarks::BookmarkModel* model,
                                  syncer::SyncClient* sync_client);
diff --git a/components/update_client/BUILD.gn b/components/update_client/BUILD.gn
index d33cc6c..675c7be0 100644
--- a/components/update_client/BUILD.gn
+++ b/components/update_client/BUILD.gn
@@ -24,7 +24,6 @@
     "crx_downloader.cc",
     "crx_downloader.h",
     "crx_update_item.h",
-    "out_of_process_patcher.h",
     "persisted_data.cc",
     "persisted_data.h",
     "ping_manager.cc",
@@ -68,6 +67,7 @@
     "//components/client_update_protocol",
     "//components/crx_file",
     "//components/data_use_measurement/core",
+    "//components/patch_service/public/cpp",
     "//components/prefs",
     "//components/version_info:version_info",
     "//courgette:courgette_lib",
@@ -99,8 +99,10 @@
   ]
   deps = [
     "//base",
+    "//components/patch_service:lib",
     "//components/prefs",
     "//net:test_support",
+    "//services/service_manager/public/cpp/test:test_support",
     "//testing/gmock",
     "//testing/gtest",
     "//url",
@@ -158,11 +160,14 @@
     ":update_client",
     "//base",
     "//components/crx_file",
+    "//components/patch_service:lib",
     "//components/prefs",
     "//components/prefs:test_support",
     "//components/version_info:version_info",
     "//courgette:courgette_lib",
     "//net:test_support",
+    "//services/service_manager/public/cpp",
+    "//services/service_manager/public/cpp/test:test_support",
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/libxml",
diff --git a/components/update_client/DEPS b/components/update_client/DEPS
index ca6755e..30e7de9 100644
--- a/components/update_client/DEPS
+++ b/components/update_client/DEPS
@@ -2,12 +2,14 @@
   "+components/client_update_protocol",
   "+components/crx_file",
   "+components/data_use_measurement/core",
+  "+components/patch_service",
   "+components/prefs",
   "+components/version_info",
   "+courgette",
   "+crypto",
   "+libxml",
   "+net",
+  "+services/service_manager/public",
   "+third_party/libxml",
   "+third_party/zlib",
 ]
diff --git a/components/update_client/component.cc b/components/update_client/component.cc
index 8e533e9c..9075541 100644
--- a/components/update_client/component.cc
+++ b/components/update_client/component.cc
@@ -155,10 +155,10 @@
     const base::FilePath& crx_path,
     const std::string& fingerprint,
     const scoped_refptr<CrxInstaller>& installer,
-    const scoped_refptr<OutOfProcessPatcher>& oop_patcher,
+    std::unique_ptr<service_manager::Connector> connector,
     InstallOnBlockingTaskRunnerCompleteCallback callback) {
   auto unpacker = base::MakeRefCounted<ComponentUnpacker>(
-      pk_hash, crx_path, installer, oop_patcher);
+      pk_hash, crx_path, installer, std::move(connector));
 
   unpacker->Unpack(base::BindOnce(&UnpackCompleteOnBlockingTaskRunner,
                                   main_task_runner, crx_path, fingerprint,
@@ -598,6 +598,10 @@
 
   component.NotifyObservers(Events::COMPONENT_UPDATE_READY);
 
+  // Create a fresh connector that can be used on the other task runner.
+  std::unique_ptr<service_manager::Connector> connector =
+      update_context.config->CreateServiceManagerConnector();
+
   base::CreateSequencedTaskRunnerWithTraits(kTaskTraits)
       ->PostTask(
           FROM_HERE,
@@ -606,7 +610,7 @@
               base::ThreadTaskRunnerHandle::Get(),
               component.crx_component_.pk_hash, component.crx_path_,
               component.next_fp_, component.crx_component_.installer,
-              update_context.config->CreateOutOfProcessPatcher(),
+              base::Passed(&connector),
               base::BindOnce(&Component::StateUpdatingDiff::InstallComplete,
                              base::Unretained(this))));
 }
@@ -658,6 +662,10 @@
 
   component.NotifyObservers(Events::COMPONENT_UPDATE_READY);
 
+  // Create a fresh connector that can be used on the other task runner.
+  std::unique_ptr<service_manager::Connector> connector =
+      update_context.config->CreateServiceManagerConnector();
+
   base::CreateSequencedTaskRunnerWithTraits(kTaskTraits)
       ->PostTask(FROM_HERE,
                  base::BindOnce(
@@ -665,7 +673,7 @@
                      base::ThreadTaskRunnerHandle::Get(),
                      component.crx_component_.pk_hash, component.crx_path_,
                      component.next_fp_, component.crx_component_.installer,
-                     update_context.config->CreateOutOfProcessPatcher(),
+                     base::Passed(&connector),
                      base::BindOnce(&Component::StateUpdating::InstallComplete,
                                     base::Unretained(this))));
 }
diff --git a/components/update_client/component_patcher.cc b/components/update_client/component_patcher.cc
index 03e835a0..e4ea386 100644
--- a/components/update_client/component_patcher.cc
+++ b/components/update_client/component_patcher.cc
@@ -20,6 +20,7 @@
 #include "components/update_client/component_patcher_operation.h"
 #include "components/update_client/update_client.h"
 #include "components/update_client/update_client_errors.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 namespace update_client {
 
@@ -48,11 +49,11 @@
     const base::FilePath& input_dir,
     const base::FilePath& unpack_dir,
     scoped_refptr<CrxInstaller> installer,
-    scoped_refptr<OutOfProcessPatcher> out_of_process_patcher)
+    std::unique_ptr<service_manager::Connector> connector)
     : input_dir_(input_dir),
       unpack_dir_(unpack_dir),
       installer_(installer),
-      out_of_process_patcher_(out_of_process_patcher) {}
+      connector_(std::move(connector)) {}
 
 ComponentPatcher::~ComponentPatcher() {
 }
@@ -87,8 +88,7 @@
 
   std::string operation;
   if (command_args->GetString(kOp, &operation)) {
-    current_operation_ =
-        CreateDeltaUpdateOp(operation, out_of_process_patcher_);
+    current_operation_ = CreateDeltaUpdateOp(operation, connector_.get());
   }
 
   if (!current_operation_.get()) {
diff --git a/components/update_client/component_patcher.h b/components/update_client/component_patcher.h
index 27bd0f24..75eebe5 100644
--- a/components/update_client/component_patcher.h
+++ b/components/update_client/component_patcher.h
@@ -39,11 +39,14 @@
 class FilePath;
 }
 
+namespace service_manager {
+class Connector;
+}
+
 namespace update_client {
 
 class CrxInstaller;
 class DeltaUpdateOp;
-class OutOfProcessPatcher;
 enum class UnpackerError;
 
 // The type of a patch file.
@@ -66,7 +69,7 @@
   ComponentPatcher(const base::FilePath& input_dir,
                    const base::FilePath& unpack_dir,
                    scoped_refptr<CrxInstaller> installer,
-                   scoped_refptr<OutOfProcessPatcher> out_of_process_patcher);
+                   std::unique_ptr<service_manager::Connector> connector);
 
   // Starts patching files. This member function returns immediately, after
   // posting a task to do the patching. When patching has been completed,
@@ -90,7 +93,7 @@
   const base::FilePath input_dir_;
   const base::FilePath unpack_dir_;
   scoped_refptr<CrxInstaller> installer_;
-  scoped_refptr<OutOfProcessPatcher> out_of_process_patcher_;
+  std::unique_ptr<service_manager::Connector> connector_;
   Callback callback_;
   std::unique_ptr<base::ListValue> commands_;
   base::ListValue::const_iterator next_command_;
diff --git a/components/update_client/component_patcher_operation.cc b/components/update_client/component_patcher_operation.cc
index 9eb162be..99906e4 100644
--- a/components/update_client/component_patcher_operation.cc
+++ b/components/update_client/component_patcher_operation.cc
@@ -15,7 +15,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/threading/sequenced_task_runner_handle.h"
-#include "components/update_client/out_of_process_patcher.h"
+#include "components/patch_service/public/cpp/patch.h"
 #include "components/update_client/update_client.h"
 #include "components/update_client/update_client_errors.h"
 #include "components/update_client/utils.h"
@@ -41,15 +41,14 @@
 const char kInput[] = "input";
 const char kPatch[] = "patch";
 
-DeltaUpdateOp* CreateDeltaUpdateOp(
-    const std::string& operation,
-    const scoped_refptr<OutOfProcessPatcher>& out_of_process_patcher) {
+DeltaUpdateOp* CreateDeltaUpdateOp(const std::string& operation,
+                                   service_manager::Connector* connector) {
   if (operation == "copy") {
     return new DeltaUpdateOpCopy();
   } else if (operation == "create") {
     return new DeltaUpdateOpCreate();
   } else if (operation == "bsdiff" || operation == "courgette") {
-    return new DeltaUpdateOpPatch(operation, out_of_process_patcher);
+    return new DeltaUpdateOpPatch(operation, connector);
   }
   return nullptr;
 }
@@ -163,10 +162,9 @@
     std::move(callback).Run(UnpackerError::kNone, 0);
 }
 
-DeltaUpdateOpPatch::DeltaUpdateOpPatch(
-    const std::string& operation,
-    const scoped_refptr<OutOfProcessPatcher>& out_of_process_patcher)
-    : operation_(operation), out_of_process_patcher_(out_of_process_patcher) {
+DeltaUpdateOpPatch::DeltaUpdateOpPatch(const std::string& operation,
+                                       service_manager::Connector* connector)
+    : operation_(operation), connector_(connector) {
   DCHECK(operation == kBsdiff || operation == kCourgette);
 }
 
@@ -193,26 +191,10 @@
 }
 
 void DeltaUpdateOpPatch::DoRun(ComponentPatcher::Callback callback) {
-  if (out_of_process_patcher_.get()) {
-    out_of_process_patcher_->Patch(
-        operation_, input_abs_path_, patch_abs_path_, output_abs_path_,
-        base::BindOnce(&DeltaUpdateOpPatch::DonePatching, this,
-                       std::move(callback)));
-    return;
-  }
-
-  if (operation_ == kBsdiff) {
-    DonePatching(std::move(callback),
-                 bsdiff::ApplyBinaryPatch(input_abs_path_, patch_abs_path_,
-                                          output_abs_path_));
-  } else if (operation_ == kCourgette) {
-    DonePatching(std::move(callback), courgette::ApplyEnsemblePatch(
-                                          input_abs_path_.value().c_str(),
-                                          patch_abs_path_.value().c_str(),
-                                          output_abs_path_.value().c_str()));
-  } else {
-    NOTREACHED();
-  }
+  patch::Patch(connector_, operation_, input_abs_path_, patch_abs_path_,
+               output_abs_path_,
+               base::Bind(&DeltaUpdateOpPatch::DonePatching, this,
+                          base::Passed(&callback)));
 }
 
 void DeltaUpdateOpPatch::DonePatching(ComponentPatcher::Callback callback,
diff --git a/components/update_client/component_patcher_operation.h b/components/update_client/component_patcher_operation.h
index 063f93d..1f99ca1 100644
--- a/components/update_client/component_patcher_operation.h
+++ b/components/update_client/component_patcher_operation.h
@@ -18,6 +18,10 @@
 class DictionaryValue;
 }  // namespace base
 
+namespace service_manager {
+class Connector;
+}
+
 namespace update_client {
 
 extern const char kOp[];
@@ -27,7 +31,6 @@
 extern const char kPatch[];
 
 class CrxInstaller;
-class OutOfProcessPatcher;
 enum class UnpackerError;
 
 class DeltaUpdateOp : public base::RefCountedThreadSafe<DeltaUpdateOp> {
@@ -129,10 +132,8 @@
 // unpacking directory.
 class DeltaUpdateOpPatch : public DeltaUpdateOp {
  public:
-  // |out_of_process_patcher| may be NULL.
-  DeltaUpdateOpPatch(
-      const std::string& operation,
-      const scoped_refptr<OutOfProcessPatcher>& out_of_process_patcher);
+  DeltaUpdateOpPatch(const std::string& operation,
+                     service_manager::Connector* connector);
 
  private:
   ~DeltaUpdateOpPatch() override;
@@ -150,16 +151,15 @@
   void DonePatching(ComponentPatcher::Callback callback, int result);
 
   std::string operation_;
-  const scoped_refptr<OutOfProcessPatcher> out_of_process_patcher_;
+  service_manager::Connector* connector_;
   base::FilePath patch_abs_path_;
   base::FilePath input_abs_path_;
 
   DISALLOW_COPY_AND_ASSIGN(DeltaUpdateOpPatch);
 };
 
-DeltaUpdateOp* CreateDeltaUpdateOp(
-    const std::string& operation,
-    const scoped_refptr<OutOfProcessPatcher>& out_of_process_patcher);
+DeltaUpdateOp* CreateDeltaUpdateOp(const std::string& operation,
+                                   service_manager::Connector* connector);
 
 }  // namespace update_client
 
diff --git a/components/update_client/component_patcher_unittest.cc b/components/update_client/component_patcher_unittest.cc
index d1da56a..af431818 100644
--- a/components/update_client/component_patcher_unittest.cc
+++ b/components/update_client/component_patcher_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "components/update_client/component_patcher.h"
 #include "base/base_paths.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -12,13 +13,14 @@
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/values.h"
-#include "components/update_client/component_patcher.h"
+#include "components/patch_service/patch_service.h"
 #include "components/update_client/component_patcher_operation.h"
 #include "components/update_client/component_patcher_unittest.h"
 #include "components/update_client/test_installer.h"
 #include "components/update_client/update_client_errors.h"
 #include "courgette/courgette.h"
 #include "courgette/third_party/bsdiff/bsdiff.h"
+#include "services/service_manager/public/cpp/test/test_connector_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -148,9 +150,15 @@
   command_args->SetString("input", "binary_input.bin");
   command_args->SetString("patch", "binary_courgette_patch.bin");
 
+  // The operation needs a connector to access the PatchService.
+  service_manager::TestConnectorFactory connector_factory(
+      std::make_unique<patch::PatchService>());
+  std::unique_ptr<service_manager::Connector> connector =
+      connector_factory.CreateConnector();
+
   TestCallback callback;
   scoped_refptr<DeltaUpdateOp> op =
-      CreateDeltaUpdateOp("courgette", nullptr /* out_of_process_patcher */);
+      CreateDeltaUpdateOp("courgette", connector.get());
   op->Run(command_args.get(), input_dir_.GetPath(), unpack_dir_.GetPath(),
           installer_.get(),
           base::BindOnce(&TestCallback::Set, base::Unretained(&callback)));
@@ -181,9 +189,15 @@
   command_args->SetString("input", "binary_input.bin");
   command_args->SetString("patch", "binary_bsdiff_patch.bin");
 
+  // The operation needs a connector to access the PatchService.
+  service_manager::TestConnectorFactory connector_factory(
+      std::make_unique<patch::PatchService>());
+  std::unique_ptr<service_manager::Connector> connector =
+      connector_factory.CreateConnector();
+
   TestCallback callback;
   scoped_refptr<DeltaUpdateOp> op =
-      CreateDeltaUpdateOp("bsdiff", nullptr /* out_of_process_patcher */);
+      CreateDeltaUpdateOp("bsdiff", connector.get());
   op->Run(command_args.get(), input_dir_.GetPath(), unpack_dir_.GetPath(),
           installer_.get(),
           base::BindOnce(&TestCallback::Set, base::Unretained(&callback)));
diff --git a/components/update_client/component_unpacker.cc b/components/update_client/component_unpacker.cc
index 40f70a1..c642af3 100644
--- a/components/update_client/component_unpacker.cc
+++ b/components/update_client/component_unpacker.cc
@@ -34,12 +34,12 @@
     const std::vector<uint8_t>& pk_hash,
     const base::FilePath& path,
     const scoped_refptr<CrxInstaller>& installer,
-    const scoped_refptr<OutOfProcessPatcher>& oop_patcher)
+    std::unique_ptr<service_manager::Connector> connector)
     : pk_hash_(pk_hash),
       path_(path),
       is_delta_(false),
       installer_(installer),
-      oop_patcher_(oop_patcher),
+      connector_(std::move(connector)),
       error_(UnpackerError::kNone),
       extended_error_(0) {}
 
@@ -104,7 +104,7 @@
       return false;
     }
     patcher_ = base::MakeRefCounted<ComponentPatcher>(
-        unpack_diff_path_, unpack_path_, installer_, oop_patcher_);
+        unpack_diff_path_, unpack_path_, installer_, std::move(connector_));
     base::SequencedTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::BindOnce(&ComponentPatcher::Start, patcher_,
diff --git a/components/update_client/component_unpacker.h b/components/update_client/component_unpacker.h
index e57ba1e..7a6fc76 100644
--- a/components/update_client/component_unpacker.h
+++ b/components/update_client/component_unpacker.h
@@ -15,8 +15,8 @@
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "components/update_client/out_of_process_patcher.h"
 #include "components/update_client/update_client_errors.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 namespace update_client {
 
@@ -84,7 +84,7 @@
   ComponentUnpacker(const std::vector<uint8_t>& pk_hash,
                     const base::FilePath& path,
                     const scoped_refptr<CrxInstaller>& installer,
-                    const scoped_refptr<OutOfProcessPatcher>& oop_patcher);
+                    std::unique_ptr<service_manager::Connector> connector);
 
   // Begins the actual unpacking of the files. May invoke a patcher and the
   // component installer if the package is a differential update.
@@ -127,7 +127,7 @@
   scoped_refptr<ComponentPatcher> patcher_;
   scoped_refptr<CrxInstaller> installer_;
   Callback callback_;
-  scoped_refptr<OutOfProcessPatcher> oop_patcher_;
+  std::unique_ptr<service_manager::Connector> connector_;
   UnpackerError error_;
   int extended_error_;
   std::string public_key_;
diff --git a/components/update_client/configurator.h b/components/update_client/configurator.h
index 99ebcbc1..fd29c79c 100644
--- a/components/update_client/configurator.h
+++ b/components/update_client/configurator.h
@@ -22,10 +22,13 @@
 class URLRequestContextGetter;
 }
 
+namespace service_manager {
+class Connector;
+}
+
 namespace update_client {
 
 class ActivityDataService;
-class OutOfProcessPatcher;
 
 // Controls the component updater behavior.
 // TODO(sorin): this class will be split soon in two. One class controls
@@ -95,10 +98,10 @@
   // The source of contexts for all the url requests.
   virtual net::URLRequestContextGetter* RequestContext() const = 0;
 
-  // Returns a new out of process patcher. May be NULL for implementations
-  // that patch in-process.
-  virtual scoped_refptr<update_client::OutOfProcessPatcher>
-  CreateOutOfProcessPatcher() const = 0;
+  // Returns a new connector to the service manager. That connector is not bound
+  // to any thread yet.
+  virtual std::unique_ptr<service_manager::Connector>
+  CreateServiceManagerConnector() const = 0;
 
   // True means that this client can handle delta updates.
   virtual bool EnabledDeltas() const = 0;
diff --git a/components/update_client/out_of_process_patcher.h b/components/update_client/out_of_process_patcher.h
deleted file mode 100644
index 18deec7..0000000
--- a/components/update_client/out_of_process_patcher.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_UPDATE_CLIENT_OUT_OF_PROCESS_PATCHER_H_
-#define COMPONENTS_UPDATE_CLIENT_OUT_OF_PROCESS_PATCHER_H_
-
-#include <string>
-
-#include "base/callback_forward.h"
-#include "base/memory/ref_counted.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace update_client {
-
-// An interface an embedder can implement to enable out-of-process patching.
-class OutOfProcessPatcher
-    : public base::RefCountedThreadSafe<OutOfProcessPatcher> {
- public:
-  virtual void Patch(const std::string& operation,
-                     const base::FilePath& input_abs_path,
-                     const base::FilePath& patch_abs_path,
-                     const base::FilePath& output_abs_path,
-                     base::OnceCallback<void(int result)> callback) = 0;
-
- protected:
-  friend class base::RefCountedThreadSafe<OutOfProcessPatcher>;
-
-  virtual ~OutOfProcessPatcher() {}
-};
-
-}  // namespace update_client
-
-#endif  // COMPONENTS_UPDATE_CLIENT_OUT_OF_PROCESS_PATCHER_H_
diff --git a/components/update_client/test_configurator.cc b/components/update_client/test_configurator.cc
index 810364a5..ba1dc7e 100644
--- a/components/update_client/test_configurator.cc
+++ b/components/update_client/test_configurator.cc
@@ -8,10 +8,13 @@
 
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/version.h"
+#include "components/patch_service/file_patcher_impl.h"
+#include "components/patch_service/patch_service.h"
+#include "components/patch_service/public/interfaces/file_patcher.mojom.h"
 #include "components/prefs/pref_service.h"
 #include "components/update_client/activity_data_service.h"
-#include "components/update_client/out_of_process_patcher.h"
 #include "net/url_request/url_request_test_util.h"
+#include "services/service_manager/public/cpp/connector.h"
 #include "url/gurl.h"
 
 namespace update_client {
@@ -33,6 +36,8 @@
       ondemand_time_(0),
       enabled_cup_signing_(false),
       enabled_component_updates_(true),
+      connector_factory_(std::make_unique<patch::PatchService>()),
+      connector_(connector_factory_.CreateConnector()),
       context_(base::MakeRefCounted<net::TestURLRequestContextGetter>(
           base::ThreadTaskRunnerHandle::Get())) {}
 
@@ -106,9 +111,9 @@
   return context_.get();
 }
 
-scoped_refptr<OutOfProcessPatcher> TestConfigurator::CreateOutOfProcessPatcher()
-    const {
-  return nullptr;
+std::unique_ptr<service_manager::Connector>
+TestConfigurator::CreateServiceManagerConnector() const {
+  return connector_->Clone();
 }
 
 bool TestConfigurator::EnabledDeltas() const {
diff --git a/components/update_client/test_configurator.h b/components/update_client/test_configurator.h
index 0e70c79..0b3b4bc0 100644
--- a/components/update_client/test_configurator.h
+++ b/components/update_client/test_configurator.h
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "components/update_client/configurator.h"
+#include "services/service_manager/public/cpp/test/test_connector_factory.h"
 #include "url/gurl.h"
 
 class PrefService;
@@ -23,6 +24,10 @@
 class URLRequestContextGetter;
 }  // namespace net
 
+namespace service_manager {
+class Connector;
+}
+
 namespace update_client {
 
 class ActivityDataService;
@@ -81,7 +86,8 @@
   std::string ExtraRequestParams() const override;
   std::string GetDownloadPreference() const override;
   net::URLRequestContextGetter* RequestContext() const override;
-  scoped_refptr<OutOfProcessPatcher> CreateOutOfProcessPatcher() const override;
+  std::unique_ptr<service_manager::Connector> CreateServiceManagerConnector()
+      const override;
   bool EnabledDeltas() const override;
   bool EnabledComponentUpdates() const override;
   bool EnabledBackgroundDownloader() const override;
@@ -104,6 +110,8 @@
   friend class base::RefCountedThreadSafe<TestConfigurator>;
   ~TestConfigurator() override;
 
+  class TestPatchService;
+
   std::string brand_;
   int initial_time_;
   int ondemand_time_;
@@ -113,6 +121,8 @@
   GURL update_check_url_;
   GURL ping_url_;
 
+  service_manager::TestConnectorFactory connector_factory_;
+  std::unique_ptr<service_manager::Connector> connector_;
   scoped_refptr<net::TestURLRequestContextGetter> context_;
 
   DISALLOW_COPY_AND_ASSIGN(TestConfigurator);
diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc
index 5d570ef..185e2d5 100644
--- a/content/browser/download/save_package.cc
+++ b/content/browser/download/save_package.cc
@@ -139,7 +139,7 @@
   }
 
  private:
-  base::WeakPtr<SavePackage> save_package_;
+  base::WeakPtr<SavePackage> const save_package_;
 };
 
 }  // namespace
@@ -335,13 +335,9 @@
 
   download_->OnAllDataSaved(size, std::unique_ptr<crypto::SecureHash>());
 
-  if (!download_manager_->GetDelegate()) {
-    Finish();
-    return;
-  }
-
-  if (download_manager_->GetDelegate()->ShouldCompleteDownload(
-          download_, base::Bind(&SavePackage::Finish, this))) {
+  auto* delegate = download_manager_->GetDelegate();
+  if (!delegate || delegate->ShouldCompleteDownload(
+                       download_, base::Bind(&SavePackage::Finish, this))) {
     Finish();
   }
 }
@@ -360,6 +356,7 @@
 #endif
 }
 
+// static
 bool SavePackage::TruncateBaseNameToFitPathConstraints(
     const base::FilePath& dir_path,
     const base::FilePath::StringType& file_name_ext,
@@ -430,58 +427,63 @@
   // Check whether we already have same name in a case insensitive manner.
   FileNameSet::const_iterator iter = file_name_set_.find(file_name);
   if (iter == file_name_set_.end()) {
+    DCHECK(!file_name.empty());
     file_name_set_.insert(file_name);
+    generated_name->assign(file_name);
+    return true;
+  }
+
+  // Found same name, increase the ordinal number for the file name.
+  base_name = base::FilePath(*iter).RemoveExtension().BaseName().value();
+  base::FilePath::StringType base_file_name = StripOrdinalNumber(base_name);
+
+  // We need to make sure the length of base file name plus maximum ordinal
+  // number path will be less than or equal to kMaxFilePathLength.
+  if (!TruncateBaseNameToFitPathConstraints(
+          saved_main_directory_path_, file_name_ext,
+          max_path - kMaxFileOrdinalNumberPartLength, &base_file_name)) {
+    return false;
+  }
+
+  // Prepare the new ordinal number.
+  uint32_t ordinal_number;
+  FileNameCountMap::iterator it = file_name_count_map_.find(base_file_name);
+  if (it == file_name_count_map_.end()) {
+    // First base-name-conflict resolving, use 1 as initial ordinal number.
+    file_name_count_map_[base_file_name] = 1;
+    ordinal_number = 1;
   } else {
-    // Found same name, increase the ordinal number for the file name.
-    base_name = base::FilePath(*iter).RemoveExtension().BaseName().value();
-    base::FilePath::StringType base_file_name = StripOrdinalNumber(base_name);
+    // We have met same base-name conflict, use latest ordinal number.
+    ordinal_number = it->second;
+  }
 
-    // We need to make sure the length of base file name plus maximum ordinal
-    // number path will be less than or equal to kMaxFilePathLength.
-    if (!TruncateBaseNameToFitPathConstraints(
-            saved_main_directory_path_, file_name_ext,
-            max_path - kMaxFileOrdinalNumberPartLength, &base_file_name))
+  if (ordinal_number > kMaxFileOrdinalNumber - 1) {
+    // Use a random file from temporary file.
+    base::FilePath temp_file;
+    base::CreateTemporaryFile(&temp_file);
+    file_name = temp_file.RemoveExtension().BaseName().value();
+    // Get safe pure file name.
+    if (!TruncateBaseNameToFitPathConstraints(saved_main_directory_path_,
+                                              base::FilePath::StringType(),
+                                              max_path, &file_name)) {
       return false;
-
-    // Prepare the new ordinal number.
-    uint32_t ordinal_number;
-    FileNameCountMap::iterator it = file_name_count_map_.find(base_file_name);
-    if (it == file_name_count_map_.end()) {
-      // First base-name-conflict resolving, use 1 as initial ordinal number.
-      file_name_count_map_[base_file_name] = 1;
-      ordinal_number = 1;
-    } else {
-      // We have met same base-name conflict, use latest ordinal number.
-      ordinal_number = it->second;
     }
-
-    if (ordinal_number > (kMaxFileOrdinalNumber - 1)) {
-      // Use a random file from temporary file.
-      base::FilePath temp_file;
-      base::CreateTemporaryFile(&temp_file);
-      file_name = temp_file.RemoveExtension().BaseName().value();
-      // Get safe pure file name.
-      if (!TruncateBaseNameToFitPathConstraints(saved_main_directory_path_,
-                                                base::FilePath::StringType(),
-                                                max_path, &file_name))
-        return false;
-    } else {
-      for (int i = ordinal_number; i < kMaxFileOrdinalNumber; ++i) {
-        base::FilePath::StringType new_name = base_file_name +
-            base::StringPrintf(FILE_PATH_LITERAL("(%d)"), i) + file_name_ext;
-        if (file_name_set_.find(new_name) == file_name_set_.end()) {
-          // Resolved name conflict.
-          file_name = new_name;
-          file_name_count_map_[base_file_name] = ++i;
-          break;
-        }
+  } else {
+    for (int i = ordinal_number; i < kMaxFileOrdinalNumber; ++i) {
+      base::FilePath::StringType new_name =
+          base_file_name + base::StringPrintf(FILE_PATH_LITERAL("(%d)"), i) +
+          file_name_ext;
+      if (!base::ContainsKey(file_name_set_, new_name)) {
+        // Resolved name conflict.
+        file_name = new_name;
+        file_name_count_map_[base_file_name] = ++i;
+        break;
       }
     }
-
-    file_name_set_.insert(file_name);
   }
 
   DCHECK(!file_name.empty());
+  file_name_set_.insert(file_name);
   generated_name->assign(file_name);
 
   return true;
@@ -833,33 +835,7 @@
 
 void SavePackage::DoSavingProcess() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML) {
-    // We guarantee that images and JavaScripts must be downloaded first.
-    // So when finishing all those sub-resources, we will know which
-    // sub-resource's link can be replaced with local file path, which
-    // sub-resource's link need to be replaced with absolute URL which
-    // point to its internet address because it got error when saving its data.
-
-    // Start a new SaveItem job if we still have job in waiting queue.
-    if (waiting_item_queue_.size()) {
-      DCHECK_EQ(NET_FILES, wait_state_);
-      const SaveItem* save_item = waiting_item_queue_.front().get();
-      if (save_item->save_source() != SaveFileCreateInfo::SAVE_FILE_FROM_DOM) {
-        SaveNextFile(false);
-      } else if (!in_process_count()) {
-        // If there is no in-process SaveItem, it means all sub-resources
-        // have been processed. Now we need to start serializing HTML DOM
-        // for the current page to get the generated HTML data.
-        wait_state_ = HTML_DATA;
-        // All non-HTML resources have been finished, start all remaining
-        // HTML files.
-        SaveNextFile(true);
-      }
-    } else if (in_process_count()) {
-      // Continue asking for HTML data.
-      DCHECK_EQ(HTML_DATA, wait_state_);
-    }
-  } else {
+  if (save_type_ != SAVE_PAGE_TYPE_AS_COMPLETE_HTML) {
     // Save as HTML only or MHTML.
     DCHECK_EQ(NET_FILES, wait_state_);
     DCHECK((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) ||
@@ -869,6 +845,33 @@
       DCHECK_EQ(all_save_items_count_, waiting_item_queue_.size());
       SaveNextFile(false);
     }
+    return;
+  }
+
+  // We guarantee that images and JavaScripts must be downloaded first.
+  // So when finishing all those sub-resources, we will know which
+  // sub-resource's link can be replaced with local file path, which
+  // sub-resource's link need to be replaced with absolute URL which
+  // point to its internet address because it got error when saving its data.
+
+  // Start a new SaveItem job if we still have job in waiting queue.
+  if (!waiting_item_queue_.empty()) {
+    DCHECK_EQ(NET_FILES, wait_state_);
+    const SaveItem* save_item = waiting_item_queue_.front().get();
+    if (save_item->save_source() != SaveFileCreateInfo::SAVE_FILE_FROM_DOM) {
+      SaveNextFile(false);
+    } else if (!in_process_count()) {
+      // If there is no in-process SaveItem, it means all sub-resources
+      // have been processed. Now we need to start serializing HTML DOM
+      // for the current page to get the generated HTML data.
+      wait_state_ = HTML_DATA;
+      // All non-HTML resources have been finished, start all remaining
+      // HTML files.
+      SaveNextFile(true);
+    }
+  } else if (in_process_count()) {
+    // Continue asking for HTML data.
+    DCHECK_EQ(HTML_DATA, wait_state_);
   }
 }
 
@@ -1143,7 +1146,7 @@
   return save_item;
 }
 
-SaveItem* SavePackage::CreatePendingSaveItemDeduplicatingByUrl(
+void SavePackage::CreatePendingSaveItemDeduplicatingByUrl(
     int container_frame_tree_node_id,
     int save_item_frame_tree_node_id,
     const GURL& url,
@@ -1155,20 +1158,15 @@
   // Frames should not be deduplicated by URL.
   DCHECK_NE(SaveFileCreateInfo::SAVE_FILE_FROM_DOM, save_source);
 
-  SaveItem* save_item;
   auto it = url_to_save_item_.find(url);
   if (it != url_to_save_item_.end()) {
-    save_item = it->second;
     frame_tree_node_id_to_contained_save_items_[container_frame_tree_node_id]
-        .push_back(save_item);
+        .push_back(it->second);
   } else {
-    save_item = CreatePendingSaveItem(container_frame_tree_node_id,
-                                      save_item_frame_tree_node_id, url,
-                                      referrer, save_source);
-    url_to_save_item_[url] = save_item;
+    url_to_save_item_[url] = CreatePendingSaveItem(container_frame_tree_node_id,
+                                                   save_item_frame_tree_node_id,
+                                                   url, referrer, save_source);
   }
-
-  return save_item;
 }
 
 void SavePackage::EnqueueSavableResource(int container_frame_tree_node_id,
@@ -1267,8 +1265,7 @@
                 url_formatter::IDNToUnicode(page_url.host()));
       }
     } else {
-      name_with_proper_ext =
-          base::FilePath::FromUTF8Unsafe(std::string("dataurl"));
+      name_with_proper_ext = base::FilePath::FromUTF8Unsafe("dataurl");
     }
   }
 
@@ -1327,14 +1324,14 @@
   static const struct {
     const char* mime_type;
     const base::FilePath::CharType* suggested_extension;
-  } extensions[] = {
-    { "text/html", kDefaultHtmlExtension },
-    { "text/xml", FILE_PATH_LITERAL("xml") },
-    { "application/xhtml+xml", FILE_PATH_LITERAL("xhtml") },
-    { "text/plain", FILE_PATH_LITERAL("txt") },
-    { "text/css", FILE_PATH_LITERAL("css") },
+  } kExtensions[] = {
+      {"text/html", kDefaultHtmlExtension},
+      {"text/xml", FILE_PATH_LITERAL("xml")},
+      {"application/xhtml+xml", FILE_PATH_LITERAL("xhtml")},
+      {"text/plain", FILE_PATH_LITERAL("txt")},
+      {"text/css", FILE_PATH_LITERAL("css")},
   };
-  for (const auto& extension : extensions) {
+  for (const auto& extension : kExtensions) {
     if (contents_mime_type == extension.mime_type)
       return extension.suggested_extension;
   }
diff --git a/content/browser/download/save_package.h b/content/browser/download/save_package.h
index 1a5c6bd..0df676c5 100644
--- a/content/browser/download/save_package.h
+++ b/content/browser/download/save_package.h
@@ -152,6 +152,8 @@
               const base::FilePath& file_full_path,
               const base::FilePath& directory_full_path);
 
+  ~SavePackage() override;
+
   void InitWithDownloadItem(
       const SavePackageDownloadCreatedCallback& download_created_callback,
       DownloadItemImpl* item);
@@ -159,8 +161,6 @@
   // Callback for WebContents::GenerateMHTML().
   void OnMHTMLGenerated(int64_t size);
 
-  ~SavePackage() override;
-
   // Notes from Init() above applies here as well.
   void InternalInit();
 
@@ -246,7 +246,7 @@
 
   // Helper for finding a SaveItem with the given url, or falling back to
   // creating a SaveItem with the given parameters.
-  SaveItem* CreatePendingSaveItemDeduplicatingByUrl(
+  void CreatePendingSaveItemDeduplicatingByUrl(
       int container_frame_tree_node_id,
       int save_item_frame_tree_node_id,
       const GURL& url,
@@ -394,12 +394,12 @@
   DownloadItemImpl* download_ = nullptr;
 
   // The URL of the page the user wants to save.
-  GURL page_url_;
+  const GURL page_url_;
   base::FilePath saved_main_file_path_;
   base::FilePath saved_main_directory_path_;
 
   // The title of the page the user wants to save.
-  base::string16 title_;
+  const base::string16 title_;
 
   // Used to calculate package download speed (in files per second).
   const base::TimeTicks start_tick_;
diff --git a/content/browser/file_url_loader_factory.cc b/content/browser/file_url_loader_factory.cc
index 3035db5..03d521f 100644
--- a/content/browser/file_url_loader_factory.cc
+++ b/content/browser/file_url_loader_factory.cc
@@ -18,9 +18,11 @@
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/file_url_loader.h"
 #include "content/public/common/resource_request.h"
 #include "content/public/common/url_loader.mojom.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
@@ -52,6 +54,35 @@
               "Default file data pipe size must be at least as large as a MIME-"
               "type sniffing buffer.");
 
+// Policy to control how a FileURLLoader will handle directory URLs.
+enum class DirectoryLoadingPolicy {
+  // File paths which refer to directories are allowed and will load as an
+  // HTML directory listing.
+  kRespondWithListing,
+
+  // File paths which refer to directories are treated as non-existent and
+  // will result in FILE_NOT_FOUND errors.
+  kFail,
+};
+
+// Policy to control whether or not file access constraints imposed by content
+// or its embedder should be honored by a FileURLLoader.
+enum class FileAccessPolicy {
+  // Enforces file acccess policy defined by content and/or its embedder.
+  kRestricted,
+
+  // Ignores file access policy, allowing contents to be loaded from any
+  // resolvable file path given.
+  kUnrestricted,
+};
+
+// Policy to control whether or not a FileURLLoader should follow filesystem
+// links (e.g. Windows shortcuts) where applicable.
+enum class LinkFollowingPolicy {
+  kFollow,
+  kDoNotFollow,
+};
+
 class FileURLDirectoryLoader
     : public mojom::URLLoader,
       public net::DirectoryLister::DirectoryListerDelegate {
@@ -249,13 +280,17 @@
   static void CreateAndStart(const base::FilePath& profile_path,
                              const ResourceRequest& request,
                              mojom::URLLoaderRequest loader,
-                             mojom::URLLoaderClientPtrInfo client_info) {
+                             mojom::URLLoaderClientPtrInfo client_info,
+                             DirectoryLoadingPolicy directory_loading_policy,
+                             FileAccessPolicy file_access_policy,
+                             LinkFollowingPolicy link_following_policy) {
     // Owns itself. Will live as long as its URLLoader and URLLoaderClientPtr
     // bindings are alive - essentially until either the client gives up or all
     // file data has been sent to it.
     auto* file_url_loader = new FileURLLoader;
     file_url_loader->Start(profile_path, request, std::move(loader),
-                           std::move(client_info));
+                           std::move(client_info), directory_loading_policy,
+                           file_access_policy, link_following_policy);
   }
 
   // mojom::URLLoader:
@@ -272,7 +307,10 @@
   void Start(const base::FilePath& profile_path,
              const ResourceRequest& request,
              mojom::URLLoaderRequest loader,
-             mojom::URLLoaderClientPtrInfo client_info) {
+             mojom::URLLoaderClientPtrInfo client_info,
+             DirectoryLoadingPolicy directory_loading_policy,
+             FileAccessPolicy file_access_policy,
+             LinkFollowingPolicy link_following_policy) {
     ResourceResponseHead head;
     head.request_start = base::TimeTicks::Now();
     head.response_start = base::TimeTicks::Now();
@@ -296,24 +334,36 @@
       return;
     }
 
-    if (info.is_directory && !path.EndsWithSeparator()) {
-      // If the named path is a directory with no trailing slash, redirect to
-      // the same path, but with a trailing slash.
-      std::string new_path = request.url.path() + '/';
-      GURL::Replacements replacements;
-      replacements.SetPathStr(new_path);
-      GURL new_url = request.url.ReplaceComponents(replacements);
+    if (info.is_directory) {
+      if (directory_loading_policy == DirectoryLoadingPolicy::kFail) {
+        client->OnComplete(
+            ResourceRequestCompletionStatus(net::ERR_FILE_NOT_FOUND));
+        return;
+      }
 
-      net::RedirectInfo redirect_info;
-      redirect_info.new_method = "GET";
-      redirect_info.status_code = 301;
-      redirect_info.new_url = new_url;
-      head.encoded_data_length = 0;
-      client->OnReceiveRedirect(redirect_info, head);
+      DCHECK_EQ(directory_loading_policy,
+                DirectoryLoadingPolicy::kRespondWithListing);
+
+      GURL directory_url = request.url;
+      if (!path.EndsWithSeparator()) {
+        // If the named path is a directory with no trailing slash, redirect to
+        // the same path, but with a trailing slash.
+        std::string new_path = directory_url.path() + '/';
+        GURL::Replacements replacements;
+        replacements.SetPathStr(new_path);
+        directory_url = directory_url.ReplaceComponents(replacements);
+
+        net::RedirectInfo redirect_info;
+        redirect_info.new_method = "GET";
+        redirect_info.status_code = 301;
+        redirect_info.new_url = directory_url;
+        head.encoded_data_length = 0;
+        client->OnReceiveRedirect(redirect_info, head);
+      }
 
       // Restart the request with a directory loader.
       ResourceRequest new_request = request;
-      new_request.url = new_url;
+      new_request.url = directory_url;
       FileURLDirectoryLoader::CreateAndStart(
           profile_path, new_request, binding_.Unbind(), client.PassInterface());
       MaybeDeleteSelf();
@@ -322,7 +372,8 @@
 
 #if defined(OS_WIN)
     base::FilePath shortcut_target;
-    if (base::LowerCaseEqualsASCII(path.Extension(), ".lnk") &&
+    if (link_following_policy == LinkFollowingPolicy::kFollow &&
+        base::LowerCaseEqualsASCII(path.Extension(), ".lnk") &&
         base::win::ResolveShortcut(path, &shortcut_target, nullptr)) {
       // Follow Windows shortcuts
       GURL new_url = net::FilePathToFileURL(shortcut_target);
@@ -338,11 +389,13 @@
       ResourceRequest new_request = request;
       new_request.url = redirect_info.new_url;
       return Start(profile_path, request, binding_.Unbind(),
-                   client.PassInterface());
+                   client.PassInterface(), directory_loading_policy,
+                   file_access_policy, link_following_policy);
     }
 #endif  // defined(OS_WIN)
 
-    if (!GetContentClient()->browser()->IsFileAccessAllowed(
+    if (file_access_policy == FileAccessPolicy::kRestricted &&
+        !GetContentClient()->browser()->IsFileAccessAllowed(
             path, base::MakeAbsoluteFilePath(path), profile_path)) {
       client->OnComplete(
           ResourceRequestCompletionStatus(net::ERR_ACCESS_DENIED));
@@ -488,10 +541,6 @@
 
 FileURLLoaderFactory::~FileURLLoaderFactory() = default;
 
-void FileURLLoaderFactory::BindRequest(mojom::URLLoaderFactoryRequest loader) {
-  bindings_.AddBinding(this, std::move(loader));
-}
-
 void FileURLLoaderFactory::CreateLoaderAndStart(
     mojom::URLLoaderRequest loader,
     int32_t routing_id,
@@ -511,12 +560,30 @@
     task_runner_->PostTask(
         FROM_HERE,
         base::BindOnce(&FileURLLoader::CreateAndStart, profile_path_, request,
-                       std::move(loader), client.PassInterface()));
+                       std::move(loader), client.PassInterface(),
+                       DirectoryLoadingPolicy::kRespondWithListing,
+                       FileAccessPolicy::kRestricted,
+                       LinkFollowingPolicy::kFollow));
   }
 }
 
 void FileURLLoaderFactory::Clone(mojom::URLLoaderFactoryRequest loader) {
-  BindRequest(std::move(loader));
+  bindings_.AddBinding(this, std::move(loader));
+}
+
+void CreateFileURLLoader(const ResourceRequest& request,
+                         mojom::URLLoaderRequest loader,
+                         mojom::URLLoaderClientPtr client) {
+  auto task_runner = base::CreateSequencedTaskRunnerWithTraits(
+      {base::MayBlock(), base::TaskPriority::BACKGROUND,
+       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+  task_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(&FileURLLoader::CreateAndStart, base::FilePath(), request,
+                     std::move(loader), client.PassInterface(),
+                     DirectoryLoadingPolicy::kFail,
+                     FileAccessPolicy::kUnrestricted,
+                     LinkFollowingPolicy::kDoNotFollow));
 }
 
 }  // namespace content
diff --git a/content/browser/file_url_loader_factory.h b/content/browser/file_url_loader_factory.h
index e0c94e6..cf511c3 100644
--- a/content/browser/file_url_loader_factory.h
+++ b/content/browser/file_url_loader_factory.h
@@ -25,8 +25,6 @@
                        scoped_refptr<base::SequencedTaskRunner> task_runner);
   ~FileURLLoaderFactory() override;
 
-  void BindRequest(mojom::URLLoaderFactoryRequest loader);
-
  private:
   // mojom::URLLoaderFactory:
   void CreateLoaderAndStart(mojom::URLLoaderRequest loader,
diff --git a/content/browser/frame_host/frame_navigation_entry.cc b/content/browser/frame_host/frame_navigation_entry.cc
index 940f0531..2ecfb5d 100644
--- a/content/browser/frame_host/frame_navigation_entry.cc
+++ b/content/browser/frame_host/frame_navigation_entry.cc
@@ -80,14 +80,17 @@
 
 void FrameNavigationEntry::set_item_sequence_number(
     int64_t item_sequence_number) {
-  // TODO(creis): Assert that this does not change after being assigned, once
-  // location.replace is classified as NEW_PAGE rather than EXISTING_PAGE.
-  // Same for document sequence number.  See https://crbug.com/596707.
+  // Once assigned, the item sequence number shouldn't change.
+  DCHECK(item_sequence_number_ == -1 ||
+         item_sequence_number_ == item_sequence_number);
   item_sequence_number_ = item_sequence_number;
 }
 
 void FrameNavigationEntry::set_document_sequence_number(
     int64_t document_sequence_number) {
+  // Once assigned, the document sequence number shouldn't change.
+  DCHECK(document_sequence_number_ == -1 ||
+         document_sequence_number_ == document_sequence_number);
   document_sequence_number_ = document_sequence_number;
 }
 
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index 4cf5056..d3a487d 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -858,7 +858,6 @@
                                    navigation_handle);
       break;
     case NAVIGATION_TYPE_EXISTING_PAGE:
-      details->did_replace_entry = details->is_same_document;
       RendererDidNavigateToExistingPage(rfh, params, details->is_same_document,
                                         was_restored, navigation_handle);
       break;
@@ -998,18 +997,6 @@
     return NAVIGATION_TYPE_NEW_SUBFRAME;
   }
 
-  // Cross-process location.replace navigations should be classified as New with
-  // replacement rather than ExistingPage, since it is not safe to reuse the
-  // NavigationEntry.
-  // TODO(creis): Have the renderer classify location.replace as
-  // did_create_new_entry for all cases and eliminate this special case.  This
-  // requires updating several test expectations.  See https://crbug.com/596707.
-  if (!rfh->GetParent() && GetLastCommittedEntry() &&
-      GetLastCommittedEntry()->site_instance() != rfh->GetSiteInstance() &&
-      params.should_replace_current_entry) {
-    return NAVIGATION_TYPE_NEW_PAGE;
-  }
-
   // We only clear the session history when navigating to a new page.
   DCHECK(!params.history_list_was_cleared);
 
@@ -1036,8 +1023,7 @@
     if (!last_committed)
       return NAVIGATION_TYPE_NAV_IGNORE;
 
-    // This is history.replaceState(), history.reload(), or a client-side
-    // redirect.
+    // This is history.replaceState() or history.reload().
     return NAVIGATION_TYPE_EXISTING_PAGE;
   }
 
@@ -1258,9 +1244,6 @@
   // We should only get here for main frame navigations.
   DCHECK(!rfh->GetParent());
 
-  // TODO(creis): Classify location.replace as NEW_PAGE instead of EXISTING_PAGE
-  // in https://crbug.com/596707.
-
   NavigationEntryImpl* entry;
   if (params.intended_as_new_entry) {
     // This was intended as a new entry but the pending entry was lost in the
@@ -1338,7 +1321,7 @@
     }
   } else {
     // This is renderer-initiated. The only kinds of renderer-initated
-    // navigations that are EXISTING_PAGE are reloads and location.replace,
+    // navigations that are EXISTING_PAGE are reloads and history.replaceState,
     // which land us at the last committed entry.
     entry = GetLastCommittedEntry();
 
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index fcb3421..2ba5b2db 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -634,12 +634,20 @@
     return is_same_documents_[0];
   }
 
+  bool did_replace_entry() {
+    EXPECT_EQ(1U, did_replace_entries_.size());
+    return did_replace_entries_[0];
+  }
+
   const std::vector<ui::PageTransition>& transitions() { return transitions_; }
   const std::vector<GURL>& urls() { return urls_; }
   const std::vector<NavigationType>& navigation_types() {
     return navigation_types_;
   }
   const std::vector<bool>& is_same_documents() { return is_same_documents_; }
+  const std::vector<bool>& did_replace_entries() {
+    return did_replace_entries_;
+  }
 
  private:
   void DidFinishNavigation(NavigationHandle* navigation_handle) override {
@@ -656,6 +664,7 @@
         static_cast<NavigationHandleImpl*>(navigation_handle)
             ->navigation_type());
     is_same_documents_.push_back(navigation_handle->IsSameDocument());
+    did_replace_entries_.push_back(navigation_handle->DidReplaceEntry());
     if (!navigations_remaining_ &&
         (!web_contents()->IsLoading() || !wait_for_load_))
       message_loop_runner_->Quit();
@@ -679,6 +688,7 @@
   std::vector<GURL> urls_;
   std::vector<NavigationType> navigation_types_;
   std::vector<bool> is_same_documents_;
+  std::vector<bool> did_replace_entries_;
 
   // The MessageLoopRunner used to spin the message loop.
   scoped_refptr<MessageLoopRunner> message_loop_runner_;
@@ -991,16 +1001,15 @@
     EXPECT_EQ(2, controller.GetEntryCount());
   }
 
-  // Navigate again to the page that fails to load. It must result in an error
-  // page, the EXISTING_PAGE navigation type, and no addition to the history
-  // list. We do not use SAME_PAGE here; that case only differs in that it
-  // clears the pending entry, and there is no pending entry after a load
-  // failure.
+  // Navigate again to the page that fails to load. It results in an error page,
+  // the NEW_PAGE navigation type with replacement, and no addition to the
+  // history list.
   {
     FrameNavigateParamsCapturer capturer(root);
     NavigateFrameToURL(root, error_url);
     capturer.Wait();
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_TRUE(capturer.did_replace_entry());
     NavigationEntry* entry = controller.GetLastCommittedEntry();
     EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
     EXPECT_EQ(2, controller.GetEntryCount());
@@ -1011,14 +1020,12 @@
   EXPECT_EQ(3, controller.GetEntryCount());
 
   // ... and replace it with a failed load.
-  // TODO(creis): Make this be NEW_PAGE along with the other location.replace
-  // cases.  There isn't much impact to having this be EXISTING_PAGE for now.
-  // See https://crbug.com/596707.
   {
     FrameNavigateParamsCapturer capturer(root);
     RendererLocationReplace(shell(), error_url);
     capturer.Wait();
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_TRUE(capturer.did_replace_entry());
     NavigationEntry* entry = controller.GetLastCommittedEntry();
     EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
     EXPECT_EQ(3, controller.GetEntryCount());
@@ -1037,6 +1044,7 @@
     RendererLocationReplace(shell(), error_url);
     capturer.Wait();
     EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_TRUE(capturer.did_replace_entry());
     NavigationEntry* entry = controller.GetLastCommittedEntry();
     EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
     EXPECT_EQ(4, controller.GetEntryCount());
@@ -1126,21 +1134,20 @@
     EXPECT_TRUE(capturer.is_same_document());
   }
 
-  if (AreAllSitesIsolatedForTesting()) {
-    // Cross-process location.replace().
-    FrameNavigateParamsCapturer capturer(root);
-    GURL frame_url(embedded_test_server()->GetURL(
-        "foo.com", "/navigation_controller/simple_page_1.html"));
-    std::string script = "location.replace('" + frame_url.spec() + "')";
-    EXPECT_TRUE(ExecuteScript(root, script));
-    capturer.Wait();
-    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
-        capturer.transition(),
-        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
-                                  ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
-    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
-    EXPECT_FALSE(capturer.is_same_document());
-  }
+  // location.replace().
+  FrameNavigateParamsCapturer capturer(root);
+  GURL frame_url(embedded_test_server()->GetURL(
+      "foo.com", "/navigation_controller/simple_page_1.html"));
+  std::string script = "location.replace('" + frame_url.spec() + "')";
+  EXPECT_TRUE(ExecuteScript(root, script));
+  capturer.Wait();
+  EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+      capturer.transition(),
+      ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+                                ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
+  EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+  EXPECT_TRUE(capturer.did_replace_entry());
+  EXPECT_FALSE(capturer.is_same_document());
 }
 
 // Verify that navigations for NAVIGATION_TYPE_EXISTING_PAGE are correctly
@@ -1268,8 +1275,6 @@
 
   {
     // location.replace().
-    // TODO(creis): Change this to be NEW_PAGE with replacement in
-    // https://crbug.com/596707.
     FrameNavigateParamsCapturer capturer(root);
     GURL frame_url(embedded_test_server()->GetURL(
         "/navigation_controller/simple_page_1.html"));
@@ -1280,13 +1285,29 @@
         capturer.transition(),
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_TRUE(capturer.did_replace_entry());
     EXPECT_FALSE(capturer.is_same_document());
   }
 
   // Now, various same document navigations.
 
   {
+    // Same-document location.replace().
+    FrameNavigateParamsCapturer capturer(root);
+    std::string script = "location.replace('#foo')";
+    EXPECT_TRUE(ExecuteScript(root, script));
+    capturer.Wait();
+    EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
+        capturer.transition(),
+        ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+                                  ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
+    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_TRUE(capturer.did_replace_entry());
+    EXPECT_TRUE(capturer.is_same_document());
+  }
+
+  {
     // history.replaceState().
     FrameNavigateParamsCapturer capturer(root);
     std::string script =
@@ -1658,7 +1679,8 @@
         capturer.transitions()[1],
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_types()[1]);
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_types()[1]);
+    EXPECT_TRUE(capturer.did_replace_entries()[1]);
   }
 }
 
@@ -4904,7 +4926,8 @@
         capturer.transition(),
         ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
                                   ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
-    EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.navigation_type());
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.navigation_type());
+    EXPECT_TRUE(capturer.did_replace_entry());
   }
 
   // Modify an entry in the session history and reload the original request.
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index cf84355..1b49409 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -2622,11 +2622,12 @@
   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   navigation_entry_committed_counter_ = 0;
 
-  // Ensure main page navigation to same url respects the
-  // was_within_same_document hint provided in the params.
+  // Ensure renderer-initiated main frame navigation to same url replaces the
+  // current entry. This behavior differs from the browser-initiated case.
   FrameHostMsg_DidCommitProvisionalLoad_Params self_params;
   self_params.nav_entry_id = 0;
-  self_params.did_create_new_entry = false;
+  self_params.did_create_new_entry = true;
+  self_params.should_replace_current_entry = true;
   self_params.url = url1;
   self_params.transition = ui::PAGE_TRANSITION_LINK;
   self_params.should_update_history = false;
@@ -2637,7 +2638,7 @@
   self_params.page_state = PageState::CreateForTestingWithSequenceNumbers(
       url1, self_params.item_sequence_number,
       self_params.document_sequence_number);
-  self_params.was_within_same_document = true;
+  self_params.was_within_same_document = false;
 
   LoadCommittedDetailsObserver observer(contents());
   main_test_rfh()->SendRendererInitiatedNavigationRequest(url1, false);
@@ -2646,7 +2647,7 @@
   NavigationEntry* entry1 = controller.GetLastCommittedEntry();
   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   navigation_entry_committed_counter_ = 0;
-  EXPECT_TRUE(observer.is_same_document());
+  EXPECT_FALSE(observer.is_same_document());
   EXPECT_TRUE(observer.did_replace_entry());
   EXPECT_EQ(1, controller.GetEntryCount());
 
@@ -2680,6 +2681,7 @@
   controller.GoBack();
   back_params.nav_entry_id = entry1->GetUniqueID();
   back_params.did_create_new_entry = false;
+  back_params.was_within_same_document = true;
   main_test_rfh()->SendNavigateWithParams(&back_params);
   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   navigation_entry_committed_counter_ = 0;
@@ -2743,11 +2745,12 @@
   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   navigation_entry_committed_counter_ = 0;
 
-  // First navigation.
+  // First navigation (using location.replace).
   const GURL url2("http://foo#a");
   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   params.nav_entry_id = 0;
   params.did_create_new_entry = false;
+  params.should_replace_current_entry = true;
   params.url = url2;
   params.transition = ui::PAGE_TRANSITION_LINK;
   params.should_update_history = false;
@@ -2791,12 +2794,13 @@
     navigation_entry_committed_counter_ = 0;
   }
 
-  // Navigate within the page.
+  // Navigate within the page using location.replace.
   {
     const GURL url("http://foo2/#a");
     FrameHostMsg_DidCommitProvisionalLoad_Params params;
     params.nav_entry_id = 0;
     params.did_create_new_entry = false;
+    params.should_replace_current_entry = true;
     params.url = url;
     params.transition = ui::PAGE_TRANSITION_LINK;
     params.redirects.push_back(url);
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 73df47b..6ef5830 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -3501,11 +3501,20 @@
           base::CreateSequencedTaskRunnerWithTraits(
               {base::MayBlock(), base::TaskPriority::BACKGROUND,
                base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
-      mojom::URLLoaderFactoryPtr file_factory_proxy;
-      file_factory->BindRequest(mojo::MakeRequest(&file_factory_proxy));
-      non_network_url_loader_factories_.emplace_back(std::move(file_factory));
-      subresource_loader_factories->RegisterFactory(
-          url::kFileScheme, std::move(file_factory_proxy));
+      non_network_url_loader_factories_.emplace(url::kFileScheme,
+                                                std::move(file_factory));
+    }
+
+    GetContentClient()
+        ->browser()
+        ->RegisterNonNetworkSubresourceURLLoaderFactories(
+            this, common_params.url, &non_network_url_loader_factories_);
+
+    for (auto& factory : non_network_url_loader_factories_) {
+      mojom::URLLoaderFactoryPtr factory_proxy;
+      factory.second->Clone(mojo::MakeRequest(&factory_proxy));
+      subresource_loader_factories->RegisterFactory(factory.first,
+                                                    std::move(factory_proxy));
     }
   }
 
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 50c00cd8..2cb44b7 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -43,6 +43,7 @@
 #include "content/common/image_downloader/image_downloader.mojom.h"
 #include "content/common/input/input_handler.mojom.h"
 #include "content/common/navigation_params.h"
+#include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/common/javascript_dialog_type.h"
 #include "content/public/common/previews_state.h"
@@ -1285,7 +1286,7 @@
   // A collection of non-network URLLoaderFactory implementations which are used
   // to service any supported non-network subresource requests for the currently
   // committed navigation.
-  std::vector<std::unique_ptr<mojom::URLLoaderFactory>>
+  ContentBrowserClient::NonNetworkURLLoaderFactoryMap
       non_network_url_loader_factories_;
 
   // Bitfield for renderer-side state that blocks fast shutdown of the frame.
diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc
index 1b36488..51cc187 100644
--- a/content/browser/loader/navigation_url_loader_network_service.cc
+++ b/content/browser/loader/navigation_url_loader_network_service.cc
@@ -582,13 +582,13 @@
   int frame_tree_node_id = request_info->frame_tree_node_id;
 
   // Check if a web UI scheme wants to handle this request.
+  FrameTreeNode* frame_tree_node =
+      FrameTreeNode::GloballyFindByID(frame_tree_node_id);
   mojom::URLLoaderFactoryPtrInfo factory_for_webui;
   mojom::URLLoaderFactoryPtrInfo subresource_factory_for_webui;
   const auto& schemes = URLDataManagerBackend::GetWebUISchemes();
   if (std::find(schemes.begin(), schemes.end(), new_request->url.scheme()) !=
       schemes.end()) {
-    FrameTreeNode* frame_tree_node =
-        FrameTreeNode::GloballyFindByID(frame_tree_node_id);
     factory_for_webui = CreateWebUIURLLoader(frame_tree_node).PassInterface();
     subresource_factory_for_webui =
         CreateWebUIURLLoader(frame_tree_node).PassInterface();
@@ -623,6 +623,15 @@
           base::CreateSequencedTaskRunnerWithTraits(
               {base::MayBlock(), base::TaskPriority::BACKGROUND,
                base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
+
+  if (frame_tree_node) {
+    // |frame_tree_node| may be null in some unit test environments.
+    GetContentClient()
+        ->browser()
+        ->RegisterNonNetworkNavigationURLLoaderFactories(
+            frame_tree_node->current_frame_host(),
+            &non_network_url_loader_factories_);
+  }
 }
 
 NavigationURLLoaderNetworkService::~NavigationURLLoaderNetworkService() {
diff --git a/content/browser/loader/navigation_url_loader_network_service.h b/content/browser/loader/navigation_url_loader_network_service.h
index dd75d94..e1611602 100644
--- a/content/browser/loader/navigation_url_loader_network_service.h
+++ b/content/browser/loader/navigation_url_loader_network_service.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "content/browser/loader/navigation_url_loader.h"
+#include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/ssl_status.h"
 #include "content/public/common/url_loader.mojom.h"
 #include "content/public/common/url_loader_factory.mojom.h"
@@ -75,7 +76,7 @@
   bool allow_download_;
 
   // Factories to handle navigation requests for non-network resources.
-  std::map<std::string, std::unique_ptr<mojom::URLLoaderFactory>>
+  ContentBrowserClient::NonNetworkURLLoaderFactoryMap
       non_network_url_loader_factories_;
 
   base::WeakPtrFactory<NavigationURLLoaderNetworkService> weak_factory_;
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 182a14f..09606b1 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2053,14 +2053,15 @@
 
   DidCompleteResizeOrRepaint(params, paint_start);
 
+  last_auto_resize_request_number_ = params.sequence_number;
+
   if (auto_resize_enabled_) {
     bool post_callback = new_auto_size_.IsEmpty();
     new_auto_size_ = params.view_size;
     if (post_callback) {
       base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE,
-          base::BindOnce(&RenderWidgetHostImpl::DelayedAutoResized,
-                         weak_factory_.GetWeakPtr(), params.sequence_number));
+          FROM_HERE, base::BindOnce(&RenderWidgetHostImpl::DelayedAutoResized,
+                                    weak_factory_.GetWeakPtr()));
     }
   }
 
@@ -2448,7 +2449,7 @@
   return true;
 }
 
-void RenderWidgetHostImpl::DelayedAutoResized(uint64_t sequence_number) {
+void RenderWidgetHostImpl::DelayedAutoResized() {
   gfx::Size new_size = new_auto_size_;
   // Clear the new_auto_size_ since the empty value is used as a flag to
   // indicate that no callback is in progress (i.e. without this line
@@ -2457,10 +2458,10 @@
   if (!auto_resize_enabled_)
     return;
 
-  last_auto_resize_request_number_ = sequence_number;
-
-  if (delegate_)
-    delegate_->ResizeDueToAutoResize(this, new_size, sequence_number);
+  if (delegate_) {
+    delegate_->ResizeDueToAutoResize(this, new_size,
+                                     last_auto_resize_request_number_);
+  }
 }
 
 void RenderWidgetHostImpl::DetachDelegate() {
@@ -2470,13 +2471,16 @@
 
 void RenderWidgetHostImpl::DidAllocateLocalSurfaceIdForAutoResize(
     uint64_t sequence_number) {
-  if (last_auto_resize_request_number_ != sequence_number)
+  if (!view_ || last_auto_resize_request_number_ != sequence_number)
     return;
 
   viz::LocalSurfaceId local_surface_id(view_->GetLocalSurfaceId());
   if (local_surface_id.is_valid()) {
+    ScreenInfo screen_info;
+    GetScreenInfo(&screen_info);
     Send(new ViewMsg_SetLocalSurfaceIdForAutoResize(
-        routing_id_, sequence_number, local_surface_id));
+        routing_id_, sequence_number, min_size_for_auto_resize_,
+        max_size_for_auto_resize_, screen_info, local_surface_id));
   }
 }
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index be1be388..ad8dcae 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -592,6 +592,10 @@
     return last_frame_metadata_;
   }
 
+  uint64_t last_auto_resize_request_number() const {
+    return last_auto_resize_request_number_;
+  }
+
   bool HasGestureStopped() override;
 
   // viz::mojom::CompositorFrameSink implementation.
@@ -650,6 +654,7 @@
                            StopAndStartHangMonitorTimeout);
   FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostTest,
                            ShorterDelayHangMonitorTimeout);
+  FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest, AutoResizeWithScale);
   FRIEND_TEST_ALL_PREFIXES(DevToolsManagerTest,
                            NoUnresponsiveDialogInInspectedContents);
   friend class MockRenderWidgetHost;
@@ -755,7 +760,7 @@
 
   // Called when there is a new auto resize (using a post to avoid a stack
   // which may get in recursive loops).
-  void DelayedAutoResized(uint64_t sequence_number);
+  void DelayedAutoResized();
 
   void WindowSnapshotReachedScreen(int snapshot_id);
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 894e433..ab38e0f 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -867,6 +867,18 @@
   }
 }
 
+void RenderWidgetHostViewAura::UpdateScreenInfo(gfx::NativeView view) {
+  RenderWidgetHostViewBase::UpdateScreenInfo(view);
+  if (!host_->auto_resize_enabled())
+    return;
+
+  window_->AllocateLocalSurfaceId();
+  host_->DidAllocateLocalSurfaceIdForAutoResize(
+      host_->last_auto_resize_request_number());
+  if (delegated_frame_host_)
+    delegated_frame_host_->WasResized();
+}
+
 gfx::Size RenderWidgetHostViewAura::GetRequestedRendererSize() const {
   return delegated_frame_host_
              ? delegated_frame_host_->GetRequestedRendererSize()
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index ee434ec..9122c61a 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -140,6 +140,7 @@
                          int error_code) override;
   void Destroy() override;
   void SetTooltipText(const base::string16& tooltip_text) override;
+  void UpdateScreenInfo(gfx::NativeView view) override;
   gfx::Size GetRequestedRendererSize() const override;
   bool IsSurfaceAvailableForCopy() const override;
   void CopyFromSurface(const gfx::Rect& src_rect,
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 de49228..3c6c1c1 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
@@ -243,11 +243,45 @@
   }
 
   double get_last_device_scale_factor() { return last_device_scale_factor_; }
+  void ResizeDueToAutoResize(RenderWidgetHostImpl* render_widget_host,
+                             const gfx::Size& new_size,
+                             uint64_t sequence_number) override {
+    RenderWidgetHostViewBase* rwhv = rwh_->GetView();
+    if (rwhv)
+      rwhv->ResizeDueToAutoResize(new_size, sequence_number);
+  }
   void ScreenInfoChanged() override {
     display::Screen* screen = display::Screen::GetScreen();
     const display::Display display = screen->GetPrimaryDisplay();
     last_device_scale_factor_ = display.device_scale_factor();
   }
+
+  void GetScreenInfo(ScreenInfo* result) override {
+    display::Screen* screen = display::Screen::GetScreen();
+    const display::Display display = screen->GetPrimaryDisplay();
+    result->rect = display.bounds();
+    result->available_rect = display.work_area();
+    result->depth = display.color_depth();
+    result->depth_per_component = display.depth_per_component();
+    result->is_monochrome = display.is_monochrome();
+    result->device_scale_factor = display.device_scale_factor();
+    result->color_space = display.color_space();
+    result->color_space.GetICCProfile(&result->icc_profile);
+
+    // The Display rotation and the ScreenInfo orientation are not the same
+    // angle. The former is the physical display rotation while the later is the
+    // rotation required by the content to be shown properly on the screen, in
+    // other words, relative to the physical display.
+    result->orientation_angle = display.RotationAsDegree();
+    if (result->orientation_angle == 90)
+      result->orientation_angle = 270;
+    else if (result->orientation_angle == 270)
+      result->orientation_angle = 90;
+
+    result->orientation_type =
+        RenderWidgetHostViewBase::GetOrientationTypeForDesktop(display);
+  }
+
   void set_pre_handle_keyboard_event_result(
       KeyboardEventProcessingResult result) {
     pre_handle_keyboard_event_result_ = result;
@@ -2239,6 +2273,56 @@
   EXPECT_EQ("100x100", view_->GetPhysicalBackingSize().ToString());
 }
 
+// This test verifies that in AutoResize mode a new
+// ViewMsg_SetLocalSurfaceIdForAutoResize message is sent when ScreenInfo
+// changes and that message contains the latest ScreenInfo.
+TEST_F(RenderWidgetHostViewAuraTest, AutoResizeWithScale) {
+  view_->InitAsChild(nullptr);
+  aura::client::ParentWindowWithContext(
+      view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(),
+      gfx::Rect());
+  sink_->ClearMessages();
+  widget_host_->SetAutoResize(true, gfx::Size(50, 50), gfx::Size(100, 100));
+  ViewHostMsg_ResizeOrRepaint_ACK_Params params;
+  params.view_size = gfx::Size(75, 75);
+  params.sequence_number = 1;
+  widget_host_->OnResizeOrRepaintACK(params);
+
+  // RenderWidgetHostImpl has delayed auto-resize processing. Yield here to
+  // let it complete.
+  base::RunLoop run_loop;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                run_loop.QuitClosure());
+  run_loop.Run();
+
+  EXPECT_EQ(1u, sink_->message_count());
+  {
+    const IPC::Message* msg = sink_->GetMessageAt(0);
+    EXPECT_EQ(ViewMsg_SetLocalSurfaceIdForAutoResize::ID, msg->type());
+    ViewMsg_SetLocalSurfaceIdForAutoResize::Param params;
+    ViewMsg_SetLocalSurfaceIdForAutoResize::Read(msg, &params);
+    EXPECT_EQ(1u, std::get<0>(params));  // sequence_number
+    EXPECT_EQ("50x50", std::get<1>(params).ToString());
+    EXPECT_EQ("100x100", std::get<2>(params).ToString());
+    EXPECT_EQ(1, std::get<3>(params).device_scale_factor);
+  }
+
+  sink_->ClearMessages();
+  aura_test_helper_->test_screen()->SetDeviceScaleFactor(2.0f);
+
+  EXPECT_EQ(2u, sink_->message_count());
+  {
+    const IPC::Message* msg = sink_->GetMessageAt(1);
+    EXPECT_EQ(ViewMsg_SetLocalSurfaceIdForAutoResize::ID, msg->type());
+    ViewMsg_SetLocalSurfaceIdForAutoResize::Param params;
+    ViewMsg_SetLocalSurfaceIdForAutoResize::Read(msg, &params);
+    EXPECT_EQ(1u, std::get<0>(params));  // sequence_number
+    EXPECT_EQ("50x50", std::get<1>(params).ToString());
+    EXPECT_EQ("100x100", std::get<2>(params).ToString());
+    EXPECT_EQ(2, std::get<3>(params).device_scale_factor);
+  }
+}
+
 // Checks that InputMsg_CursorVisibilityChange IPC messages are dispatched
 // to the renderer at the correct times.
 TEST_F(RenderWidgetHostViewAuraTest, CursorVisibilityChange) {
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 a6e7b71c..49e2ae6 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -156,7 +156,7 @@
   void DidReceiveRendererFrame();
 
   // Notification that a resize or move session ended on the native widget.
-  void UpdateScreenInfo(gfx::NativeView view);
+  virtual void UpdateScreenInfo(gfx::NativeView view);
 
   // Tells if the display property (work area/scale factor) has
   // changed since the last time.
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index 862cc65f..dcf639b3 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -313,6 +313,7 @@
                          int error_code) override;
   void Destroy() override;
   void SetTooltipText(const base::string16& tooltip_text) override;
+  void UpdateScreenInfo(gfx::NativeView view) override;
   bool IsSurfaceAvailableForCopy() const override;
   void CopyFromSurface(const gfx::Rect& src_rect,
                        const gfx::Size& output_size,
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index 66b0aba..89aae9a 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -1110,6 +1110,18 @@
   }
 }
 
+void RenderWidgetHostViewMac::UpdateScreenInfo(gfx::NativeView view) {
+  RenderWidgetHostViewBase::UpdateScreenInfo(view);
+
+  if (!render_widget_host_->auto_resize_enabled())
+    return;
+
+  local_surface_id_ = local_surface_id_allocator_.GenerateId();
+  render_widget_host_->DidAllocateLocalSurfaceIdForAutoResize(
+      render_widget_host_->last_auto_resize_request_number());
+  browser_compositor_->GetDelegatedFrameHost()->WasResized();
+}
+
 bool RenderWidgetHostViewMac::SupportsSpeech() const {
   return [NSApp respondsToSelector:@selector(speakString:)] &&
          [NSApp respondsToSelector:@selector(stopSpeaking:)];
@@ -1782,8 +1794,13 @@
     }
     RenderWidgetHostImpl* host =
         RenderWidgetHostImpl::From(GetRenderWidgetHost());
-    if (host && host->delegate())
+    if (host) {
+      if (host->auto_resize_enabled()) {
+        host->DidAllocateLocalSurfaceIdForAutoResize(
+            host->last_auto_resize_request_number());
+      }
       host->WasResized();
+    }
   }
 
   UpdateBackingStoreProperties();
diff --git a/content/browser/service_worker/foreign_fetch_request_handler.cc b/content/browser/service_worker/foreign_fetch_request_handler.cc
index 4a638b9..6ec227a7 100644
--- a/content/browser/service_worker/foreign_fetch_request_handler.cc
+++ b/content/browser/service_worker/foreign_fetch_request_handler.cc
@@ -31,8 +31,6 @@
 
 namespace {
 
-int kUserDataKey;  // Only address is used.
-
 class ForeignFetchRequestInterceptor : public net::URLRequestInterceptor {
  public:
   explicit ForeignFetchRequestInterceptor(ResourceContext* resource_context)
@@ -56,6 +54,9 @@
 
 }  // namespace
 
+// static
+int ForeignFetchRequestHandler::user_data_key_;
+
 bool ForeignFetchRequestHandler::IsForeignFetchEnabled() {
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableExperimentalWebPlatformFeatures)) {
@@ -135,13 +136,13 @@
           context_wrapper, blob_storage_context->AsWeakPtr(), request_mode,
           credentials_mode, redirect_mode, integrity, keepalive, resource_type,
           request_context_type, frame_type, body, timeout));
-  request->SetUserData(&kUserDataKey, std::move(handler));
+  request->SetUserData(&user_data_key_, std::move(handler));
 }
 
 ForeignFetchRequestHandler* ForeignFetchRequestHandler::GetHandler(
     net::URLRequest* request) {
   return static_cast<ForeignFetchRequestHandler*>(
-      request->GetUserData(&kUserDataKey));
+      request->GetUserData(&user_data_key_));
 }
 
 std::unique_ptr<net::URLRequestInterceptor>
diff --git a/content/browser/service_worker/foreign_fetch_request_handler.h b/content/browser/service_worker/foreign_fetch_request_handler.h
index b5df9d3..441ab36 100644
--- a/content/browser/service_worker/foreign_fetch_request_handler.h
+++ b/content/browser/service_worker/foreign_fetch_request_handler.h
@@ -148,6 +148,8 @@
 
   base::WeakPtrFactory<ForeignFetchRequestHandler> weak_factory_;
 
+  static int user_data_key_;  // Only address is used.
+
   DISALLOW_COPY_AND_ASSIGN(ForeignFetchRequestHandler);
 };
 
diff --git a/content/browser/service_worker/service_worker_request_handler.cc b/content/browser/service_worker/service_worker_request_handler.cc
index 532f38d9c..9c6dd74 100644
--- a/content/browser/service_worker/service_worker_request_handler.cc
+++ b/content/browser/service_worker/service_worker_request_handler.cc
@@ -36,8 +36,6 @@
 
 namespace {
 
-int kUserDataKey;  // Key value is not important.
-
 class ServiceWorkerRequestInterceptor
     : public net::URLRequestInterceptor {
  public:
@@ -62,6 +60,9 @@
 
 }  // namespace
 
+// static
+int ServiceWorkerRequestHandler::user_data_key_;
+
 // PlzNavigate:
 // static
 void ServiceWorkerRequestHandler::InitializeForNavigation(
@@ -109,7 +110,7 @@
           frame_type, blob_storage_context->AsWeakPtr(), body,
           skip_service_worker));
   if (handler)
-    request->SetUserData(&kUserDataKey, std::move(handler));
+    request->SetUserData(&user_data_key_, std::move(handler));
 
   // Transfer ownership to the ServiceWorkerNavigationHandleCore.
   // In the case of a successful navigation, the SWProviderHost will be
@@ -214,14 +215,14 @@
           resource_type, request_context_type, frame_type,
           blob_storage_context->AsWeakPtr(), body, skip_service_worker));
   if (handler)
-    request->SetUserData(&kUserDataKey, std::move(handler));
+    request->SetUserData(&user_data_key_, std::move(handler));
 }
 
 // static
 ServiceWorkerRequestHandler* ServiceWorkerRequestHandler::GetHandler(
     const net::URLRequest* request) {
   return static_cast<ServiceWorkerRequestHandler*>(
-      request->GetUserData(&kUserDataKey));
+      request->GetUserData(&user_data_key_));
 }
 
 // static
diff --git a/content/browser/service_worker/service_worker_request_handler.h b/content/browser/service_worker/service_worker_request_handler.h
index 879dc74..51d2572 100644
--- a/content/browser/service_worker/service_worker_request_handler.h
+++ b/content/browser/service_worker/service_worker_request_handler.h
@@ -165,6 +165,8 @@
   int old_process_id_;
   int old_provider_id_;
 
+  static int user_data_key_;  // Only address is used.
+
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRequestHandler);
 };
 
diff --git a/content/browser/service_worker/service_worker_response_info.cc b/content/browser/service_worker/service_worker_response_info.cc
index 028e30d..38fc093 100644
--- a/content/browser/service_worker/service_worker_response_info.cc
+++ b/content/browser/service_worker/service_worker_response_info.cc
@@ -10,21 +10,18 @@
 
 namespace content {
 
-namespace {
-
-int kUserDataKey;  // Only address is used, value is not important.
-
-}  // namespace
+// static
+int ServiceWorkerResponseInfo::user_data_key_;
 
 // static
 ServiceWorkerResponseInfo* ServiceWorkerResponseInfo::ForRequest(
     net::URLRequest* request,
     bool create) {
   ServiceWorkerResponseInfo* info = static_cast<ServiceWorkerResponseInfo*>(
-      request->GetUserData(&kUserDataKey));
+      request->GetUserData(&user_data_key_));
   if (!info && create) {
     info = new ServiceWorkerResponseInfo();
-    request->SetUserData(&kUserDataKey, base::WrapUnique(info));
+    request->SetUserData(&user_data_key_, base::WrapUnique(info));
   }
   return info;
 }
diff --git a/content/browser/service_worker/service_worker_response_info.h b/content/browser/service_worker/service_worker_response_info.h
index ab759f1..2ab68de 100644
--- a/content/browser/service_worker/service_worker_response_info.h
+++ b/content/browser/service_worker/service_worker_response_info.h
@@ -108,6 +108,8 @@
   std::string response_cache_storage_cache_name_;
   ServiceWorkerHeaderList cors_exposed_header_names_;
   bool did_navigation_preload_ = false;
+
+  static int user_data_key_;  // Only address is used.
 };
 
 }  // namespace content
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 67da3880..72f2565 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -342,8 +342,11 @@
 
 // Tells the widget to use the provided viz::LocalSurfaceId to submit
 // CompositorFrames for autosize.
-IPC_MESSAGE_ROUTED2(ViewMsg_SetLocalSurfaceIdForAutoResize,
+IPC_MESSAGE_ROUTED5(ViewMsg_SetLocalSurfaceIdForAutoResize,
                     uint64_t /* sequence_number */,
+                    gfx::Size /* min_size */,
+                    gfx::Size /* max_size */,
+                    content::ScreenInfo /* screen_info */,
                     viz::LocalSurfaceId /* local_surface_id */)
 
 // Enables device emulation. See WebDeviceEmulationParams for description.
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
index f297f52..f6fc402d 100644
--- a/content/gpu/gpu_main.cc
+++ b/content/gpu/gpu_main.cc
@@ -367,8 +367,7 @@
   bool res = service_manager::SandboxLinux::GetInstance()->InitializeSandbox(
       service_manager::SandboxTypeFromCommandLine(
           *base::CommandLine::ForCurrentProcess()),
-      GetGpuProcessPreSandboxHook(sandbox_options.use_amd_specific_policies),
-      sandbox_options);
+      base::BindOnce(GpuProcessPreSandboxHook), sandbox_options);
 
   if (watchdog_thread) {
     base::Thread::Options thread_options;
diff --git a/content/gpu/gpu_sandbox_hook_linux.cc b/content/gpu/gpu_sandbox_hook_linux.cc
index 8d592bf..0ff7c59 100644
--- a/content/gpu/gpu_sandbox_hook_linux.cc
+++ b/content/gpu/gpu_sandbox_hook_linux.cc
@@ -83,9 +83,12 @@
 #endif
 }
 
-void AddV4L2GpuWhitelist(std::vector<BrokerFilePermission>* permissions,
-                         bool accelerated_video_decode_enabled) {
-  if (accelerated_video_decode_enabled) {
+constexpr int dlopen_flag = RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE;
+
+void AddV4L2GpuWhitelist(
+    std::vector<BrokerFilePermission>* permissions,
+    const service_manager::SandboxSeccompBPF::Options& options) {
+  if (options.accelerated_video_decode_enabled) {
     // Device nodes for V4L2 video decode accelerator drivers.
     static const base::FilePath::CharType kDevicePath[] =
         FILE_PATH_LITERAL("/dev/");
@@ -107,6 +110,179 @@
   permissions->push_back(BrokerFilePermission::ReadWrite(kDevJpegDecPath));
 }
 
+void AddArmMaliGpuWhitelist(std::vector<BrokerFilePermission>* permissions) {
+  // Device file needed by the ARM GPU userspace.
+  static const char kMali0Path[] = "/dev/mali0";
+
+  // Image processor used on ARM platforms.
+  static const char kDevImageProc0Path[] = "/dev/image-proc0";
+
+  permissions->push_back(BrokerFilePermission::ReadWrite(kMali0Path));
+  permissions->push_back(BrokerFilePermission::ReadWrite(kDevImageProc0Path));
+}
+
+void AddAmdGpuWhitelist(std::vector<BrokerFilePermission>* permissions) {
+  static const char* const kReadOnlyList[] = {"/etc/ld.so.cache",
+                                              "/usr/lib64/libEGL.so.1",
+                                              "/usr/lib64/libGLESv2.so.2"};
+  for (const char* item : kReadOnlyList)
+    permissions->push_back(BrokerFilePermission::ReadOnly(item));
+
+  static const char* const kReadWriteList[] = {
+      "/dev/dri",
+      "/dev/dri/card0",
+      "/dev/dri/controlD64",
+      "/dev/dri/renderD128",
+      "/sys/class/drm/card0/device/config",
+      "/sys/class/drm/controlD64/device/config",
+      "/sys/class/drm/renderD128/device/config",
+      "/usr/share/libdrm/amdgpu.ids"};
+  for (const char* item : kReadWriteList)
+    permissions->push_back(BrokerFilePermission::ReadWrite(item));
+
+  static const char kCharDevices[] = "/sys/dev/char/";
+  permissions->push_back(BrokerFilePermission::ReadOnlyRecursive(kCharDevices));
+}
+
+void AddArmGpuWhitelist(std::vector<BrokerFilePermission>* permissions) {
+  // On ARM we're enabling the sandbox before the X connection is made,
+  // so we need to allow access to |.Xauthority|.
+  static const char kXAuthorityPath[] = "/home/chronos/.Xauthority";
+  static const char kLdSoCache[] = "/etc/ld.so.cache";
+
+  // Files needed by the ARM GPU userspace.
+  static const char kLibGlesPath[] = "/usr/lib/libGLESv2.so.2";
+  static const char kLibEglPath[] = "/usr/lib/libEGL.so.1";
+
+  permissions->push_back(BrokerFilePermission::ReadOnly(kXAuthorityPath));
+  permissions->push_back(BrokerFilePermission::ReadOnly(kLdSoCache));
+  permissions->push_back(BrokerFilePermission::ReadOnly(kLibGlesPath));
+  permissions->push_back(BrokerFilePermission::ReadOnly(kLibEglPath));
+
+  AddArmMaliGpuWhitelist(permissions);
+}
+
+void AddStandardGpuWhiteList(std::vector<BrokerFilePermission>* permissions) {
+  static const char kDriCardBasePath[] = "/dev/dri/card";
+  static const char kNvidiaCtlPath[] = "/dev/nvidiactl";
+  static const char kNvidiaDeviceBasePath[] = "/dev/nvidia";
+  static const char kNvidiaParamsPath[] = "/proc/driver/nvidia/params";
+  static const char kDevShm[] = "/dev/shm/";
+
+  // For shared memory.
+  permissions->push_back(
+      BrokerFilePermission::ReadWriteCreateUnlinkRecursive(kDevShm));
+
+  // For DRI cards.
+  for (int i = 0; i <= 9; ++i) {
+    permissions->push_back(BrokerFilePermission::ReadWrite(
+        base::StringPrintf("%s%d", kDriCardBasePath, i)));
+  }
+
+  // For Nvidia GLX driver.
+  permissions->push_back(BrokerFilePermission::ReadWrite(kNvidiaCtlPath));
+  for (int i = 0; i < 10; ++i) {
+    permissions->push_back(BrokerFilePermission::ReadWrite(
+        base::StringPrintf("%s%d", kNvidiaDeviceBasePath, i)));
+  }
+  permissions->push_back(BrokerFilePermission::ReadOnly(kNvidiaParamsPath));
+}
+
+std::vector<BrokerFilePermission> FilePermissionsForGpu(
+    const service_manager::SandboxSeccompBPF::Options& options) {
+  std::vector<BrokerFilePermission> permissions;
+
+  // All GPU process policies need this file brokered out.
+  static const char kDriRcPath[] = "/etc/drirc";
+  permissions.push_back(BrokerFilePermission::ReadOnly(kDriRcPath));
+
+  if (IsChromeOS()) {
+    if (IsArchitectureArm())
+      AddArmGpuWhitelist(&permissions);
+    if (options.use_amd_specific_policies)
+      AddAmdGpuWhitelist(&permissions);
+    if (UseV4L2Codec())
+      AddV4L2GpuWhitelist(&permissions, options);
+  } else {
+    AddStandardGpuWhiteList(&permissions);
+  }
+
+  return permissions;
+}
+
+void LoadArmGpuLibraries() {
+  // Preload the Mali library.
+  dlopen("/usr/lib/libmali.so", dlopen_flag);
+
+  // Preload the Tegra V4L2 (video decode acceleration) library.
+  dlopen("/usr/lib/libtegrav4l2.so", dlopen_flag);
+}
+
+bool LoadAmdGpuLibraries() {
+  // Preload the amdgpu-dependent libraries.
+  if (nullptr == dlopen("libglapi.so", dlopen_flag)) {
+    LOG(ERROR) << "dlopen(libglapi.so) failed with error: " << dlerror();
+    return false;
+  }
+  if (nullptr == dlopen("/usr/lib64/dri/radeonsi_dri.so", dlopen_flag)) {
+    LOG(ERROR) << "dlopen(radeonsi_dri.so) failed with error: " << dlerror();
+    return false;
+  }
+  return true;
+}
+
+void LoadV4L2Libraries() {
+  if (UseLibV4L2()) {
+    dlopen("/usr/lib/libv4l2.so", dlopen_flag);
+
+    // This is a device-specific encoder plugin.
+    dlopen("/usr/lib/libv4l/plugins/libv4l-encplugin.so", dlopen_flag);
+  }
+}
+
+void LoadStandardLibraries(
+    const service_manager::SandboxSeccompBPF::Options& options) {
+  if (IsArchitectureX86_64() || IsArchitectureI386()) {
+    // Accelerated video dlopen()'s some shared objects
+    // inside the sandbox, so preload them now.
+    if (options.vaapi_accelerated_video_encode_enabled ||
+        options.accelerated_video_decode_enabled) {
+      const char* I965DrvVideoPath = nullptr;
+      const char* I965HybridDrvVideoPath = nullptr;
+      if (IsArchitectureX86_64()) {
+        I965DrvVideoPath = "/usr/lib64/va/drivers/i965_drv_video.so";
+        I965HybridDrvVideoPath = "/usr/lib64/va/drivers/hybrid_drv_video.so";
+      } else if (IsArchitectureI386()) {
+        I965DrvVideoPath = "/usr/lib/va/drivers/i965_drv_video.so";
+      }
+      dlopen(I965DrvVideoPath, dlopen_flag);
+      if (I965HybridDrvVideoPath)
+        dlopen(I965HybridDrvVideoPath, dlopen_flag);
+      dlopen("libva.so.1", dlopen_flag);
+#if defined(USE_OZONE)
+      dlopen("libva-drm.so.1", dlopen_flag);
+#elif defined(USE_X11)
+      dlopen("libva-x11.so.1", dlopen_flag);
+#endif
+    }
+  }
+}
+
+bool LoadLibrariesForGpu(
+    const service_manager::SandboxSeccompBPF::Options& options) {
+  if (IsChromeOS()) {
+    if (IsArchitectureArm())
+      LoadArmGpuLibraries();
+    if (options.use_amd_specific_policies && !LoadAmdGpuLibraries())
+      return false;
+    if (UseV4L2Codec())
+      LoadV4L2Libraries();
+  } else {
+    LoadStandardLibraries(options);
+  }
+  return true;
+}
+
 void UpdateProcessTypeToGpuBroker() {
   base::CommandLine::StringVector exec =
       base::CommandLine::ForCurrentProcess()->GetArgs();
@@ -129,65 +305,6 @@
       client_sandbox_policy->GetBrokerSandboxPolicy(), base::ScopedFD());
 }
 
-void AddArmMaliGpuWhitelist(std::vector<BrokerFilePermission>* permissions) {
-  // Device file needed by the ARM GPU userspace.
-  static const char kMali0Path[] = "/dev/mali0";
-
-  // Image processor used on ARM platforms.
-  static const char kDevImageProc0Path[] = "/dev/image-proc0";
-
-  permissions->push_back(BrokerFilePermission::ReadWrite(kMali0Path));
-  permissions->push_back(BrokerFilePermission::ReadWrite(kDevImageProc0Path));
-}
-
-void AddAmdGpuWhitelist(std::vector<BrokerFilePermission>* permissions) {
-  static const char* kReadOnlyList[] = {"/etc/ld.so.cache",
-                                        "/usr/lib64/libEGL.so.1",
-                                        "/usr/lib64/libGLESv2.so.2"};
-  int listSize = arraysize(kReadOnlyList);
-
-  for (int i = 0; i < listSize; i++) {
-    permissions->push_back(BrokerFilePermission::ReadOnly(kReadOnlyList[i]));
-  }
-
-  static const char* kReadWriteList[] = {
-      "/dev/dri",
-      "/dev/dri/card0",
-      "/dev/dri/controlD64",
-      "/dev/dri/renderD128",
-      "/sys/class/drm/card0/device/config",
-      "/sys/class/drm/controlD64/device/config",
-      "/sys/class/drm/renderD128/device/config",
-      "/usr/share/libdrm/amdgpu.ids"};
-
-  listSize = arraysize(kReadWriteList);
-
-  for (int i = 0; i < listSize; i++) {
-    permissions->push_back(BrokerFilePermission::ReadWrite(kReadWriteList[i]));
-  }
-
-  static const char kCharDevices[] = "/sys/dev/char/";
-  permissions->push_back(BrokerFilePermission::ReadOnlyRecursive(kCharDevices));
-}
-
-void AddArmGpuWhitelist(std::vector<BrokerFilePermission>* permissions) {
-  // On ARM we're enabling the sandbox before the X connection is made,
-  // so we need to allow access to |.Xauthority|.
-  static const char kXAuthorityPath[] = "/home/chronos/.Xauthority";
-  static const char kLdSoCache[] = "/etc/ld.so.cache";
-
-  // Files needed by the ARM GPU userspace.
-  static const char kLibGlesPath[] = "/usr/lib/libGLESv2.so.2";
-  static const char kLibEglPath[] = "/usr/lib/libEGL.so.1";
-
-  permissions->push_back(BrokerFilePermission::ReadOnly(kXAuthorityPath));
-  permissions->push_back(BrokerFilePermission::ReadOnly(kLdSoCache));
-  permissions->push_back(BrokerFilePermission::ReadOnly(kLibGlesPath));
-  permissions->push_back(BrokerFilePermission::ReadOnly(kLibEglPath));
-
-  AddArmMaliGpuWhitelist(permissions);
-}
-
 // Start a broker process to handle open() inside the sandbox.
 // |client_sandbox_policy| is a the policy the untrusted client is
 // running, but which can allocate a suitable sandbox policy for
@@ -196,50 +313,7 @@
 // whitelisted by the broker process, in addition to the basic ones.
 std::unique_ptr<BrokerProcess> InitGpuBrokerProcess(
     service_manager::BPFBasePolicy* client_sandbox_policy,
-    const std::vector<BrokerFilePermission>& permissions_extra,
-    bool accelerated_video_decode_enabled) {
-  static const char kDriRcPath[] = "/etc/drirc";
-  static const char kDriCardBasePath[] = "/dev/dri/card";
-  static const char kNvidiaCtlPath[] = "/dev/nvidiactl";
-  static const char kNvidiaDeviceBasePath[] = "/dev/nvidia";
-  static const char kNvidiaParamsPath[] = "/proc/driver/nvidia/params";
-  static const char kDevShm[] = "/dev/shm/";
-
-  // All GPU process policies need these files brokered out.
-  std::vector<BrokerFilePermission> permissions;
-  permissions.push_back(BrokerFilePermission::ReadOnly(kDriRcPath));
-
-  if (!IsChromeOS()) {
-    // For shared memory.
-    permissions.push_back(
-        BrokerFilePermission::ReadWriteCreateUnlinkRecursive(kDevShm));
-    // For DRI cards.
-    for (int i = 0; i <= 9; ++i) {
-      permissions.push_back(BrokerFilePermission::ReadWrite(
-          base::StringPrintf("%s%d", kDriCardBasePath, i)));
-    }
-    // For Nvidia GLX driver.
-    permissions.push_back(BrokerFilePermission::ReadWrite(kNvidiaCtlPath));
-    for (int i = 0; i <= 9; ++i) {
-      permissions.push_back(BrokerFilePermission::ReadWrite(
-          base::StringPrintf("%s%d", kNvidiaDeviceBasePath, i)));
-    }
-    permissions.push_back(BrokerFilePermission::ReadOnly(kNvidiaParamsPath));
-  } else if (UseV4L2Codec()) {
-    AddV4L2GpuWhitelist(&permissions, accelerated_video_decode_enabled);
-    if (UseLibV4L2()) {
-      dlopen("/usr/lib/libv4l2.so", RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
-      // This is a device-specific encoder plugin.
-      dlopen("/usr/lib/libv4l/plugins/libv4l-encplugin.so",
-             RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
-    }
-  }
-
-  // Add eventual extra files from permissions_extra.
-  for (const auto& perm : permissions_extra) {
-    permissions.push_back(perm);
-  }
-
+    const std::vector<BrokerFilePermission>& permissions) {
   auto result = std::make_unique<BrokerProcess>(
       service_manager::BPFBasePolicy::GetFSDeniedErrno(), permissions);
 
@@ -250,114 +324,19 @@
   return result;
 }
 
-bool GpuPreSandboxHook(service_manager::BPFBasePolicy* policy,
-                       service_manager::SandboxSeccompBPF::Options options) {
-  // Warm up resources needed by the policy we're about to enable and
-  // eventually start a broker process.
-  const bool chromeos_arm_gpu = IsChromeOS() && IsArchitectureArm();
-  // This policy is for x86 or Desktop.
-  DCHECK(!chromeos_arm_gpu);
-
-  // Create a new broker process with no extra files in whitelist.
-  service_manager::SandboxLinux::GetInstance()->set_broker_process(
-      InitGpuBrokerProcess(policy, std::vector<BrokerFilePermission>(),
-                           options.accelerated_video_decode_enabled));
-
-  if (IsArchitectureX86_64() || IsArchitectureI386()) {
-    // Accelerated video dlopen()'s some shared objects
-    // inside the sandbox, so preload them now.
-    if (options.vaapi_accelerated_video_encode_enabled ||
-        options.accelerated_video_decode_enabled) {
-      const char* I965DrvVideoPath = nullptr;
-      const char* I965HybridDrvVideoPath = nullptr;
-
-      if (IsArchitectureX86_64()) {
-        I965DrvVideoPath = "/usr/lib64/va/drivers/i965_drv_video.so";
-        I965HybridDrvVideoPath = "/usr/lib64/va/drivers/hybrid_drv_video.so";
-      } else if (IsArchitectureI386()) {
-        I965DrvVideoPath = "/usr/lib/va/drivers/i965_drv_video.so";
-      }
-
-      dlopen(I965DrvVideoPath, RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
-      if (I965HybridDrvVideoPath)
-        dlopen(I965HybridDrvVideoPath, RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
-      dlopen("libva.so.1", RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
-#if defined(USE_OZONE)
-      dlopen("libva-drm.so.1", RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
-#elif defined(USE_X11)
-      dlopen("libva-x11.so.1", RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
-#endif
-    }
-  }
-
-  return true;
-}
-
-bool CrosArmGpuPreSandboxHook(
-    service_manager::BPFBasePolicy* policy,
-    service_manager::SandboxSeccompBPF::Options options) {
-  DCHECK(IsChromeOS() && IsArchitectureArm());
-
-  // Add ARM-specific files to whitelist in the broker.
-  std::vector<BrokerFilePermission> permissions;
-  AddArmGpuWhitelist(&permissions);
-  service_manager::SandboxLinux::GetInstance()->set_broker_process(
-      InitGpuBrokerProcess(policy, permissions,
-                           options.accelerated_video_decode_enabled));
-
-  const int dlopen_flag = RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE;
-
-  // Preload the Mali library.
-  dlopen("/usr/lib/libmali.so", dlopen_flag);
-  // Preload the Tegra V4L2 (video decode acceleration) library.
-  dlopen("/usr/lib/libtegrav4l2.so", dlopen_flag);
-  // Resetting errno since platform-specific libraries will fail on other
-  // platforms.
-  errno = 0;
-
-  return true;
-}
-
-bool CrosAmdGpuPreSandboxHook(
-    service_manager::BPFBasePolicy* policy,
-    service_manager::SandboxSeccompBPF::Options options) {
-  DCHECK(IsChromeOS());
-
-  // Add AMD-specific files to whitelist in the broker.
-  std::vector<BrokerFilePermission> permissions;
-  AddAmdGpuWhitelist(&permissions);
-
-  service_manager::SandboxLinux::GetInstance()->set_broker_process(
-      InitGpuBrokerProcess(policy, permissions,
-                           options.accelerated_video_decode_enabled));
-
-  const int dlopen_flag = RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE;
-
-  // Preload the amdgpu-dependent libraries.
-  errno = 0;
-  if (nullptr == dlopen("libglapi.so", dlopen_flag)) {
-    LOG(ERROR) << "dlopen(libglapi.so) failed with error: " << dlerror();
-    return false;
-  }
-  if (nullptr == dlopen("/usr/lib64/dri/radeonsi_dri.so", dlopen_flag)) {
-    LOG(ERROR) << "dlopen(radeonsi_dri.so) failed with error: " << dlerror();
-    return false;
-  }
-
-  return true;
-}
-
 }  // namespace
 
-service_manager::SandboxSeccompBPF::PreSandboxHook GetGpuProcessPreSandboxHook(
-    bool use_amd_specific_policies) {
-  if (IsChromeOS()) {
-    if (IsArchitectureArm())
-      return base::BindOnce(&CrosArmGpuPreSandboxHook);
-    if (use_amd_specific_policies)
-      return base::BindOnce(&CrosAmdGpuPreSandboxHook);
-  }
-  return base::BindOnce(&GpuPreSandboxHook);
+bool GpuProcessPreSandboxHook(
+    service_manager::BPFBasePolicy* policy,
+    service_manager::SandboxSeccompBPF::Options options) {
+  service_manager::SandboxLinux::GetInstance()->set_broker_process(
+      InitGpuBrokerProcess(policy, FilePermissionsForGpu(options)));
+
+  if (!LoadLibrariesForGpu(options))
+    return false;
+
+  errno = 0;
+  return true;
 }
 
 }  // namespace content
diff --git a/content/gpu/gpu_sandbox_hook_linux.h b/content/gpu/gpu_sandbox_hook_linux.h
index 22e2d22..3157d6b 100644
--- a/content/gpu/gpu_sandbox_hook_linux.h
+++ b/content/gpu/gpu_sandbox_hook_linux.h
@@ -9,8 +9,9 @@
 
 namespace content {
 
-service_manager::SandboxSeccompBPF::PreSandboxHook GetGpuProcessPreSandboxHook(
-    bool use_amd_specific_policies);
+bool GpuProcessPreSandboxHook(
+    service_manager::BPFBasePolicy* policy,
+    service_manager::SandboxSeccompBPF::Options options);
 
 }  // namespace content
 
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index 3cbe117..df14357 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -88,6 +88,7 @@
           "test",
           "url_loader"
         ],
+        "patch_service": [ "patch_file" ],
         "ui": [ "display_output_protection" ],
         "service_manager": [
           "service_manager:client_process",
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index 1af086ae..9ad74820 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -121,6 +121,7 @@
     "download_url_parameters.h",
     "favicon_status.cc",
     "favicon_status.h",
+    "file_url_loader.h",
     "focused_node_details.h",
     "font_list_async.h",
     "frame_service_base.h",
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index d466211..ada2869e 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -534,6 +534,15 @@
   return std::vector<std::unique_ptr<URLLoaderThrottle>>();
 }
 
+void ContentBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories(
+    RenderFrameHost* frame_host,
+    NonNetworkURLLoaderFactoryMap* factories) {}
+
+void ContentBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
+    RenderFrameHost* frame_host,
+    const GURL& frame_url,
+    NonNetworkURLLoaderFactoryMap* factories) {}
+
 mojom::NetworkContextPtr ContentBrowserClient::CreateNetworkContext(
     BrowserContext* context,
     bool in_memory,
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index c7acf27..5b64e27d 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -896,6 +896,25 @@
   virtual std::vector<std::unique_ptr<URLLoaderThrottle>>
   CreateURLLoaderThrottles(const base::Callback<WebContents*()>& wc_getter);
 
+  // Allows the embedder to register per-scheme URLLoaderFactory implementations
+  // to handle navigation URL requests for schemes not handled by the Network
+  // Service. Only called when the Network Service is enabled.
+  using NonNetworkURLLoaderFactoryMap =
+      std::map<std::string, std::unique_ptr<mojom::URLLoaderFactory>>;
+  virtual void RegisterNonNetworkNavigationURLLoaderFactories(
+      RenderFrameHost* frame_host,
+      NonNetworkURLLoaderFactoryMap* factories);
+
+  // Allows the embedder to register per-scheme URLLoaderFactory implementations
+  // to handle subresource URL requests for schemes not handled by the Network
+  // Service. The factories added to this map will only be used to service
+  // subresource requests from |frame_host| as long as it's navigated to
+  // |frame_url|. Only called when the Network Service is enabled.
+  virtual void RegisterNonNetworkSubresourceURLLoaderFactories(
+      RenderFrameHost* frame_host,
+      const GURL& frame_url,
+      NonNetworkURLLoaderFactoryMap* factories);
+
   // Creates a NetworkContext for a BrowserContext's StoragePartition. If the
   // network service is enabled, it must return a NetworkContext using the
   // network service. If the network service is disabled, the embedder may
diff --git a/content/public/browser/file_url_loader.h b/content/public/browser/file_url_loader.h
new file mode 100644
index 0000000..e467256a
--- /dev/null
+++ b/content/public/browser/file_url_loader.h
@@ -0,0 +1,32 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_FILE_URL_LOADER_H_
+#define CONTENT_PUBLIC_BROWSER_FILE_URL_LOADER_H_
+
+#include "content/common/content_export.h"
+#include "content/public/common/url_loader.mojom.h"
+
+namespace content {
+
+struct ResourceRequest;
+
+// Helper to create a self-owned URLLoader instance which fulfills |request|
+// using the contents of the file at |path|. The URL in |request| must be a
+// file:// URL.
+//
+// Note that this does not restrict filesystem access *in any way*, so if the
+// file at |path| is accessible to the browser, it will be loaded and used to
+// the request.
+//
+// The URLLoader created by this function does *not* automatically follow
+// filesytem links (e.g. Windows shortcuts) or support directory listing.
+// A directory path will always yield a FILE_NOT_FOUND network error.
+CONTENT_EXPORT void CreateFileURLLoader(const ResourceRequest& request,
+                                        mojom::URLLoaderRequest loader,
+                                        mojom::URLLoaderClientPtr client);
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_BROWSER_FILE_URL_LOADER_H_
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index 829aeb5..5d5bb7f6 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -81,9 +81,14 @@
 }
 
 void MockRenderProcessHost::SimulateCrash() {
+  SimulateRenderProcessExit(base::TERMINATION_STATUS_PROCESS_CRASHED, 0);
+}
+
+void MockRenderProcessHost::SimulateRenderProcessExit(
+    base::TerminationStatus status,
+    int exit_code) {
   has_connection_ = false;
-  RenderProcessHost::RendererClosedDetails details(
-      base::TERMINATION_STATUS_PROCESS_CRASHED, 0);
+  RenderProcessHost::RendererClosedDetails details(status, exit_code);
   NotificationService::current()->Notify(
       NOTIFICATION_RENDERER_PROCESS_CLOSED, Source<RenderProcessHost>(this),
       Details<RenderProcessHost::RendererClosedDetails>(&details));
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index a3a8772..4e52b71 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -7,7 +7,10 @@
 
 #include <stddef.h>
 #include <stdint.h>
+
+#include <map>
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -51,6 +54,8 @@
 
   // Provides tests a way to simulate this render process crashing.
   void SimulateCrash();
+  void SimulateRenderProcessExit(base::TerminationStatus termination_status,
+                                 int exit_code);
 
   // RenderProcessHost implementation (public portion).
   bool Init() override;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 9c3eab9..1ae3a9e9 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -5183,7 +5183,6 @@
   params->method = "GET";
   params->intended_as_new_entry =
       navigation_state->request_params().intended_as_new_entry;
-  params->did_create_new_entry = commit_type == blink::kWebStandardCommit;
   params->should_replace_current_entry =
       document_loader->ReplacesCurrentHistoryItem();
   params->post_id = -1;
@@ -5200,6 +5199,19 @@
   params->socket_address.set_port(response.RemotePort());
   params->was_within_same_document = navigation_state->WasWithinSameDocument();
 
+  // "Standard" commits from Blink create new NavigationEntries. We also treat
+  // main frame "inert" commits as creating new NavigationEntries if they
+  // replace the current entry on a cross-document navigation (e.g., client
+  // redirects, location.replace, navigation to same URL), since this will
+  // replace all the subframes and could go cross-origin. We don't want to rely
+  // on updating the existing NavigationEntry in this case, since it could leave
+  // stale state around.
+  params->did_create_new_entry =
+      (commit_type == blink::kWebStandardCommit) ||
+      (commit_type == blink::kWebHistoryInertCommit && !frame->Parent() &&
+       params->should_replace_current_entry &&
+       !params->was_within_same_document);
+
   WebDocument frame_document = frame->GetDocument();
   // Set the origin of the frame.  This will be replicated to the corresponding
   // RenderFrameProxies in other processes.
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 69b69876..de60e72 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1153,6 +1153,8 @@
                         OnEnablePreferredSizeChangedMode)
     IPC_MESSAGE_HANDLER(ViewMsg_EnableAutoResize, OnEnableAutoResize)
     IPC_MESSAGE_HANDLER(ViewMsg_DisableAutoResize, OnDisableAutoResize)
+    IPC_MESSAGE_HANDLER(ViewMsg_SetLocalSurfaceIdForAutoResize,
+                        OnSetLocalSurfaceIdForAutoResize)
     IPC_MESSAGE_HANDLER(ViewMsg_DisableScrollbarsForSmallWindows,
                         OnDisableScrollbarsForSmallWindows)
     IPC_MESSAGE_HANDLER(ViewMsg_SetRendererPrefs, OnSetRendererPrefs)
@@ -1990,6 +1992,27 @@
   }
 }
 
+void RenderViewImpl::OnSetLocalSurfaceIdForAutoResize(
+    uint64_t sequence_number,
+    const gfx::Size& min_size,
+    const gfx::Size& max_size,
+    const content::ScreenInfo& screen_info,
+    const viz::LocalSurfaceId& local_surface_id) {
+  if (!auto_resize_mode_ || resize_or_repaint_ack_num_ != sequence_number)
+    return;
+
+  SetLocalSurfaceIdForAutoResize(sequence_number, screen_info,
+                                 local_surface_id);
+
+  if (IsUseZoomForDSFEnabled()) {
+    webview()->EnableAutoResizeMode(
+        gfx::ScaleToCeiledSize(min_size, device_scale_factor_),
+        gfx::ScaleToCeiledSize(max_size, device_scale_factor_));
+  } else {
+    webview()->EnableAutoResizeMode(min_size, max_size);
+  }
+}
+
 void RenderViewImpl::OnEnablePreferredSizeChangedMode() {
   if (send_preferred_size_changes_)
     return;
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index c060595..d6b96784c 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -506,6 +506,12 @@
   void OnEnablePreferredSizeChangedMode();
   void OnEnableAutoResize(const gfx::Size& min_size, const gfx::Size& max_size);
   void OnDisableAutoResize(const gfx::Size& new_size);
+  void OnSetLocalSurfaceIdForAutoResize(
+      uint64_t sequence_number,
+      const gfx::Size& min_size,
+      const gfx::Size& max_size,
+      const content::ScreenInfo& screen_info,
+      const viz::LocalSurfaceId& local_surface_id);
   void OnEnumerateDirectoryResponse(int id,
                                     const std::vector<base::FilePath>& paths);
   void OnMediaPlayerActionAt(const gfx::Point& location,
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index efc2b1d..6cb9a96 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -604,6 +604,30 @@
 }
 #endif
 
+void RenderWidget::SetLocalSurfaceIdForAutoResize(
+    uint64_t sequence_number,
+    const content::ScreenInfo& screen_info,
+    const viz::LocalSurfaceId& local_surface_id) {
+  bool screen_info_changed = screen_info_ != screen_info;
+
+  screen_info_ = screen_info;
+  if (device_scale_factor_ != screen_info_.device_scale_factor) {
+    device_scale_factor_ = screen_info_.device_scale_factor;
+    OnDeviceScaleFactorChanged();
+  }
+
+  if (screen_info_changed) {
+    for (auto& observer : render_frame_proxies_)
+      observer.OnScreenInfoChanged(screen_info);
+
+    // Notify all BrowserPlugins of the updated ScreenInfo.
+    if (BrowserPluginManager::Get())
+      BrowserPluginManager::Get()->ScreenInfoChanged(screen_info);
+  }
+
+  AutoResizeCompositor(local_surface_id);
+}
+
 void RenderWidget::OnShowHostContextMenu(ContextMenuParams* params) {
   if (screen_metrics_emulator_)
     screen_metrics_emulator_->OnShowContextMenu(params);
@@ -768,10 +792,15 @@
 
 void RenderWidget::OnSetLocalSurfaceIdForAutoResize(
     uint64_t sequence_number,
+    const gfx::Size& min_size,
+    const gfx::Size& max_size,
+    const content::ScreenInfo& screen_info,
     const viz::LocalSurfaceId& local_surface_id) {
   if (!auto_resize_mode_ || resize_or_repaint_ack_num_ != sequence_number)
     return;
-  AutoResizeCompositor(local_surface_id);
+
+  SetLocalSurfaceIdForAutoResize(sequence_number, screen_info,
+                                 local_surface_id);
 }
 
 void RenderWidget::OnEnableDeviceEmulation(
@@ -2219,7 +2248,8 @@
   if (GetFocusedPepperPluginInsideWidget())
     return;
 #endif
-  WebRange web_range = GetWebWidget()->CompositionRange();
+  blink::WebInputMethodController* controller = GetInputMethodController();
+  WebRange web_range = controller ? controller->CompositionRange() : WebRange();
   if (web_range.IsNull()) {
     *range = gfx::Range::InvalidRange();
     return;
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 5d8eb7a93..d7a8b29 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -517,6 +517,11 @@
       RenderWidgetScreenMetricsEmulator* emulator);
 #endif
 
+  void SetLocalSurfaceIdForAutoResize(
+      uint64_t sequence_number,
+      const content::ScreenInfo& screen_info,
+      const viz::LocalSurfaceId& local_surface_id);
+
   // RenderWidget IPC message handlers
   void OnHandleInputEvent(
       const blink::WebInputEvent* event,
@@ -528,6 +533,9 @@
   virtual void OnResize(const ResizeParams& params);
   void OnSetLocalSurfaceIdForAutoResize(
       uint64_t sequence_number,
+      const gfx::Size& min_size,
+      const gfx::Size& max_size,
+      const content::ScreenInfo& screen_info,
       const viz::LocalSurfaceId& local_surface_id);
   void OnEnableDeviceEmulation(const blink::WebDeviceEmulationParams& params);
   void OnDisableDeviceEmulation();
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 9530929..5a9b99e 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -157,6 +157,8 @@
     self.Fail('conformance2/glsl3/' +
         'vector-dynamic-indexing-swizzled-lvalue.html',
         ['win', 'nvidia', 'opengl'], bug=709874)
+    self.Flaky('conformance2/rendering/attrib-type-match.html',
+        ['win', 'nvidia', 'opengl'], bug=782254)
 
     # Win / AMD
     self.Fail('conformance2/rendering/blitframebuffer-stencil-only.html',
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index b33a9b7a..d238a0b 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -357,7 +357,6 @@
     "//components/web_modal",
     "//components/zoom",
     "//content/public/browser",
-    "//content/public/common",
     "//crypto:platform",
     "//crypto:platform",
     "//extensions:extensions_browser_resources",
@@ -375,6 +374,7 @@
   ]
 
   public_deps = [
+    "//content/public/common",
     "//extensions/browser/install",
     "//extensions/browser/kiosk",
     "//extensions/browser/updater",
diff --git a/extensions/browser/api/networking_private/networking_private_chromeos.cc b/extensions/browser/api/networking_private/networking_private_chromeos.cc
index 4c50ee7..f28c62a5 100644
--- a/extensions/browser/api/networking_private/networking_private_chromeos.cc
+++ b/extensions/browser/api/networking_private/networking_private_chromeos.cc
@@ -516,8 +516,11 @@
     int limit,
     const NetworkListCallback& success_callback,
     const FailureCallback& failure_callback) {
+  // When requesting configured Ethernet networks, include EthernetEAP.
   NetworkTypePattern pattern =
-      chromeos::onc::NetworkTypePatternFromOncType(network_type);
+      (!visible_only && network_type == ::onc::network_type::kEthernet)
+          ? NetworkTypePattern::EthernetOrEthernetEAP()
+          : chromeos::onc::NetworkTypePatternFromOncType(network_type);
   std::unique_ptr<base::ListValue> network_properties_list =
       chromeos::network_util::TranslateNetworkListToONC(
           pattern, configured_only, visible_only, limit);
diff --git a/extensions/browser/extension_protocols.cc b/extensions/browser/extension_protocols.cc
index 9a3e73a..af316d9 100644
--- a/extensions/browser/extension_protocols.cc
+++ b/extensions/browser/extension_protocols.cc
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <algorithm>
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -24,6 +25,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -33,15 +35,25 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/timer/elapsed_timer.h"
 #include "build/build_config.h"
-#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/file_url_loader.h"
+#include "content/public/browser/navigation_ui_data.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/common/browser_side_navigation_policy.h"
+#include "content/public/common/resource_request_completion_status.h"
 #include "content/public/common/resource_type.h"
 #include "crypto/secure_hash.h"
 #include "crypto/sha2.h"
 #include "extensions/browser/content_verifier.h"
 #include "extensions/browser/content_verify_job.h"
+#include "extensions/browser/extension_navigation_ui_data.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_util.h"
 #include "extensions/browser/extensions_browser_client.h"
+#include "extensions/browser/guest_view/web_view/web_view_guest.h"
+#include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
 #include "extensions/browser/info_map.h"
 #include "extensions/browser/url_request_util.h"
 #include "extensions/common/constants.h"
@@ -54,6 +66,8 @@
 #include "extensions/common/manifest_handlers/incognito_info.h"
 #include "extensions/common/manifest_handlers/shared_module_info.h"
 #include "extensions/common/manifest_handlers/web_accessible_resources_info.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "net/base/filename_util.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_request_headers.h"
@@ -64,7 +78,6 @@
 #include "net/url_request/url_request_simple_job.h"
 #include "url/url_util.h"
 
-using content::BrowserThread;
 using content::ResourceRequestInfo;
 using extensions::Extension;
 using extensions::SharedModuleInfo;
@@ -74,6 +87,20 @@
 
 ExtensionProtocolTestHandler* g_test_handler = nullptr;
 
+void GenerateBackgroundPageContents(const Extension* extension,
+                                    std::string* mime_type,
+                                    std::string* charset,
+                                    std::string* data) {
+  *mime_type = "text/html";
+  *charset = "utf-8";
+  *data = "<!DOCTYPE html>\n<body>\n";
+  for (const auto& script : BackgroundInfo::GetBackgroundScripts(extension)) {
+    *data += "<script src=\"";
+    *data += script;
+    *data += "\"></script>\n";
+  }
+}
+
 class GeneratedBackgroundPageJob : public net::URLRequestSimpleJob {
  public:
   GeneratedBackgroundPageJob(net::URLRequest* request,
@@ -94,18 +121,7 @@
               std::string* charset,
               std::string* data,
               const net::CompletionCallback& callback) const override {
-    *mime_type = "text/html";
-    *charset = "utf-8";
-
-    *data = "<!DOCTYPE html>\n<body>\n";
-    const std::vector<std::string>& background_scripts =
-        extensions::BackgroundInfo::GetBackgroundScripts(extension_.get());
-    for (size_t i = 0; i < background_scripts.size(); ++i) {
-      *data += "<script src=\"";
-      *data += background_scripts[i];
-      *data += "\"></script>\n";
-    }
-
+    GenerateBackgroundPageContents(extension_.get(), mime_type, charset, data);
     return net::OK;
   }
 
@@ -329,53 +345,39 @@
   base::WeakPtrFactory<URLRequestExtensionJob> weak_factory_;
 };
 
-bool ExtensionCanLoadInIncognito(const ResourceRequestInfo* info,
-                                 const std::string& extension_id,
-                                 extensions::InfoMap* extension_info_map) {
-  if (!extension_info_map->IsIncognitoEnabled(extension_id))
+bool ExtensionCanLoadInIncognito(bool is_main_frame,
+                                 const Extension* extension,
+                                 bool extension_enabled_in_incognito) {
+  if (!extension || !extension_enabled_in_incognito)
     return false;
+  if (!is_main_frame)
+    return true;
 
   // Only allow incognito toplevel navigations to extension resources in
   // split mode. In spanning mode, the extension must run in a single process,
   // and an incognito tab prevents that.
-  if (info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME) {
-    const Extension* extension =
-        extension_info_map->extensions().GetByID(extension_id);
-    return extension && extensions::IncognitoInfo::IsSplitMode(extension);
-  }
-
-  return true;
+  return IncognitoInfo::IsSplitMode(extension);
 }
 
 // Returns true if an chrome-extension:// resource should be allowed to load.
 // Pass true for |is_incognito| only for incognito profiles and not Chrome OS
 // guest mode profiles.
-// TODO(aa): This should be moved into ExtensionResourceRequestPolicy, but we
-// first need to find a way to get CanLoadInIncognito state into the renderers.
-bool AllowExtensionResourceLoad(net::URLRequest* request,
+//
+// May be called on the IO thread (non-Network Service path) or the UI thread
+// (Network Service path).
+bool AllowExtensionResourceLoad(const GURL& url,
+                                content::ResourceType resource_type,
+                                ui::PageTransition page_transition,
+                                int child_id,
                                 bool is_incognito,
                                 const Extension* extension,
-                                extensions::InfoMap* extension_info_map) {
-  const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
-
-  // We have seen crashes where info is NULL: crbug.com/52374.
-  if (!info) {
-    // SeviceWorker net requests created through ServiceWorkerWriteToCacheJob
-    // do not have ResourceRequestInfo associated with them. So skip logging
-    // spurious errors below.
-    // TODO(falken): Either consider attaching ResourceRequestInfo to these or
-    // finish refactoring ServiceWorkerWriteToCacheJob so that it doesn't spawn
-    // a new URLRequest.
-    if (!ResourceRequestInfo::OriginatedFromServiceWorker(request)) {
-      LOG(ERROR) << "Allowing load of " << request->url().spec()
-                 << "from unknown origin. Could not find user data for "
-                 << "request.";
-    }
-    return true;
-  }
-
-  if (is_incognito && !ExtensionCanLoadInIncognito(
-                          info, request->url().host(), extension_info_map)) {
+                                bool extension_enabled_in_incognito,
+                                const ExtensionSet& extensions,
+                                const ProcessMap& process_map) {
+  const bool is_main_frame = resource_type == content::RESOURCE_TYPE_MAIN_FRAME;
+  if (is_incognito &&
+      !ExtensionCanLoadInIncognito(is_main_frame, extension,
+                                   extension_enabled_in_incognito)) {
     return false;
   }
 
@@ -392,22 +394,20 @@
   // process to request each other's resources. We can't do a more precise
   // check, since the renderer can lie about which extension has made the
   // request.
-  if (extension_info_map->process_map().Contains(
-      request->url().host(), info->GetChildID())) {
+  if (process_map.Contains(url.host(), child_id))
     return true;
-  }
 
   // PlzNavigate: frame navigations to extensions have already been checked in
   // the ExtensionNavigationThrottle.
-  if (info->GetChildID() == -1 &&
-      content::IsResourceTypeFrame(info->GetResourceType()) &&
+  if (child_id == -1 && content::IsResourceTypeFrame(resource_type) &&
       content::IsBrowserSideNavigationEnabled()) {
     return true;
   }
 
   // Allow the extension module embedder to grant permission for loads.
   if (ExtensionsBrowserClient::Get()->AllowCrossRendererResourceLoad(
-          request, is_incognito, extension, extension_info_map)) {
+          url, resource_type, page_transition, child_id, is_incognito,
+          extension, extensions, process_map)) {
     return true;
   }
 
@@ -418,7 +418,6 @@
 // Returns true if the given URL references an icon in the given extension.
 bool URLIsForExtensionIcon(const GURL& url, const Extension* extension) {
   DCHECK(url.SchemeIs(extensions::kExtensionScheme));
-
   if (!extension)
     return false;
 
@@ -426,8 +425,85 @@
   base::StringPiece path = url.path_piece();
   DCHECK(path.length() > 0 && path[0] == '/');
   base::StringPiece path_without_slash = path.substr(1);
-  return extensions::IconsInfo::GetIcons(extension).ContainsPath(
-      path_without_slash);
+  return IconsInfo::GetIcons(extension).ContainsPath(path_without_slash);
+}
+
+// Retrieves the path corresponding to an extension on disk. Returns |true| on
+// success and populates |*path|; otherwise returns |false|.
+bool GetDirectoryForExtensionURL(const GURL& url,
+                                 const std::string& extension_id,
+                                 const Extension* extension,
+                                 const ExtensionSet& disabled_extensions,
+                                 base::FilePath* out_path) {
+  base::FilePath path;
+  if (extension)
+    path = extension->path();
+  const Extension* disabled_extension =
+      disabled_extensions.GetByID(extension_id);
+  if (path.empty()) {
+    // For disabled extensions, we only resolve the directory path to service
+    // extension icon URL requests.
+    if (URLIsForExtensionIcon(url, disabled_extension))
+      path = disabled_extension->path();
+  }
+
+  if (!path.empty()) {
+    *out_path = path;
+    return true;
+  }
+
+  DLOG_IF(WARNING, !disabled_extension)
+      << "Failed to get directory for extension " << extension_id;
+
+  return false;
+}
+
+bool IsWebViewRequest(net::URLRequest* request) {
+  const content::ResourceRequestInfo* info =
+      content::ResourceRequestInfo::ForRequest(request);
+  // |info| can be null sometimes: http://crbug.com/370070.
+  if (!info)
+    return false;
+  if (WebViewRendererState::GetInstance()->IsGuest(info->GetChildID()))
+    return true;
+
+  // GetChildId() is -1 with PlzNavigate for navigation requests, so also try
+  // the ExtensionNavigationUIData data.
+  const ExtensionNavigationUIData* data =
+      ExtensionsBrowserClient::Get()->GetExtensionNavigationUIData(request);
+  return data && data->is_web_view();
+}
+
+void GetSecurityPolicyForURL(const GURL& url,
+                             const Extension* extension,
+                             bool is_web_view_request,
+                             std::string* content_security_policy,
+                             bool* send_cors_header,
+                             bool* follow_symlinks_anywhere) {
+  std::string resource_path = url.path();
+
+  // Use default CSP for <webview>.
+  if (!is_web_view_request) {
+    *content_security_policy =
+        extensions::CSPInfo::GetResourceContentSecurityPolicy(extension,
+                                                              resource_path);
+  }
+
+  if ((extension->manifest_version() >= 2 ||
+       extensions::WebAccessibleResourcesInfo::HasWebAccessibleResources(
+           extension)) &&
+      extensions::WebAccessibleResourcesInfo::IsResourceWebAccessible(
+          extension, resource_path)) {
+    *send_cors_header = true;
+  }
+
+  *follow_symlinks_anywhere =
+      (extension->creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE) != 0;
+}
+
+bool IsBackgroundPageURL(const GURL& url) {
+  std::string path = url.path();
+  return path.size() > 1 && path.substr(1) == kGeneratedBackgroundPageFilename;
 }
 
 class ExtensionProtocolHandler
@@ -457,60 +533,52 @@
   std::string extension_id = request->url().host();
   const Extension* extension =
       extension_info_map_->extensions().GetByID(extension_id);
+  const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
+  const bool enabled_in_incognito =
+      extension_info_map_->IsIncognitoEnabled(extension_id);
 
-  if (!AllowExtensionResourceLoad(
-          request, is_incognito_, extension, extension_info_map_)) {
+  // We have seen crashes where info is NULL: crbug.com/52374.
+  if (!info) {
+    // SeviceWorker net requests created through ServiceWorkerWriteToCacheJob
+    // do not have ResourceRequestInfo associated with them. So skip logging
+    // spurious errors below.
+    // TODO(falken): Either consider attaching ResourceRequestInfo to these or
+    // finish refactoring ServiceWorkerWriteToCacheJob so that it doesn't spawn
+    // a new URLRequest.
+    if (!ResourceRequestInfo::OriginatedFromServiceWorker(request)) {
+      LOG(ERROR) << "Allowing load of " << request->url().spec()
+                 << "from unknown origin. Could not find user data for "
+                 << "request.";
+    }
+  } else if (!AllowExtensionResourceLoad(
+                 request->url(), info->GetResourceType(),
+                 info->GetPageTransition(), info->GetChildID(), is_incognito_,
+                 extension, enabled_in_incognito,
+                 extension_info_map_->extensions(),
+                 extension_info_map_->process_map())) {
     return new net::URLRequestErrorJob(request, network_delegate,
                                        net::ERR_BLOCKED_BY_CLIENT);
   }
 
-  // If this is a disabled extension only allow the icon to load.
   base::FilePath directory_path;
-  if (extension)
-    directory_path = extension->path();
-  if (directory_path.value().empty()) {
-    const Extension* disabled_extension =
-        extension_info_map_->disabled_extensions().GetByID(extension_id);
-    if (URLIsForExtensionIcon(request->url(), disabled_extension))
-      directory_path = disabled_extension->path();
-    if (directory_path.value().empty()) {
-      LOG(WARNING) << "Failed to GetPathForExtension: " << extension_id;
-      return NULL;
-    }
+  if (!GetDirectoryForExtensionURL(request->url(), extension_id, extension,
+                                   extension_info_map_->disabled_extensions(),
+                                   &directory_path)) {
+    return nullptr;
   }
 
   // Set up content security policy.
   std::string content_security_policy;
   bool send_cors_header = false;
   bool follow_symlinks_anywhere = false;
-
   if (extension) {
-    std::string resource_path = request->url().path();
-
-    // Use default CSP for <webview>.
-    if (!url_request_util::IsWebViewRequest(request)) {
-      content_security_policy =
-          extensions::CSPInfo::GetResourceContentSecurityPolicy(extension,
-                                                                resource_path);
-    }
-
-    if ((extension->manifest_version() >= 2 ||
-         extensions::WebAccessibleResourcesInfo::HasWebAccessibleResources(
-             extension)) &&
-        extensions::WebAccessibleResourcesInfo::IsResourceWebAccessible(
-            extension, resource_path)) {
-      send_cors_header = true;
-    }
-
-    follow_symlinks_anywhere =
-        (extension->creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)
-        != 0;
+    GetSecurityPolicyForURL(request->url(), extension,
+                            IsWebViewRequest(request), &content_security_policy,
+                            &send_cors_header, &follow_symlinks_anywhere);
   }
 
   // Create a job for a generated background page.
-  std::string path = request->url().path();
-  if (path.size() > 1 &&
-      path.substr(1) == extensions::kGeneratedBackgroundPageFilename) {
+  if (IsBackgroundPageURL(request->url())) {
     return new GeneratedBackgroundPageJob(
         request, network_delegate, extension, content_security_policy);
   }
@@ -537,6 +605,7 @@
     return nullptr;
 
   // Handle shared resources (extension A loading resources out of extension B).
+  std::string path = request->url().path();
   if (SharedModuleInfo::IsImportedPath(path)) {
     std::string new_extension_id;
     std::string new_relative_path;
@@ -562,7 +631,7 @@
       return test_job;
   }
 
-  ContentVerifyJob* verify_job = NULL;
+  ContentVerifyJob* verify_job = nullptr;
   ContentVerifier* verifier = extension_info_map_->content_verifier();
   if (verifier) {
     verify_job =
@@ -582,9 +651,182 @@
                                     verify_job);
 }
 
+void LoadExtensionResourceFromFileOnBackgroundSequence(
+    const content::ResourceRequest& request,
+    const std::string& extension_id,
+    const base::FilePath& directory_path,
+    const base::FilePath& relative_path,
+    content::mojom::URLLoaderRequest loader,
+    content::mojom::URLLoaderClientPtrInfo client_info) {
+  // NOTE: ExtensionResource::GetFilePath() must be called on a sequence which
+  // tolerates blocking operations.
+  ExtensionResource resource(extension_id, directory_path, relative_path);
+  content::mojom::URLLoaderClientPtr client;
+  client.Bind(std::move(client_info));
+
+  content::ResourceRequest file_request = request;
+  file_request.url = net::FilePathToFileURL(resource.GetFilePath());
+  content::CreateFileURLLoader(file_request, std::move(loader),
+                               std::move(client));
+}
+
+class ExtensionURLLoaderFactory : public content::mojom::URLLoaderFactory {
+ public:
+  // |frame_host| is the RenderFrameHost which is either being navigated or
+  // loading a subresource. For navigation requests, |frame_url| is empty; for
+  // subresource requests it's the URL of the currently committed navigation on
+  // |frame_host|.
+  explicit ExtensionURLLoaderFactory(content::RenderFrameHost* frame_host,
+                                     const GURL& frame_url)
+      : frame_host_(frame_host), frame_url_(frame_url) {}
+  ~ExtensionURLLoaderFactory() override = default;
+
+  // content::mojom::URLLoaderFactory:
+  void CreateLoaderAndStart(content::mojom::URLLoaderRequest loader,
+                            int32_t routing_id,
+                            int32_t request_id,
+                            uint32_t options,
+                            const content::ResourceRequest& request,
+                            content::mojom::URLLoaderClientPtr client,
+                            const net::MutableNetworkTrafficAnnotationTag&
+                                traffic_annotation) override {
+    content::RenderProcessHost* process_host = frame_host_->GetProcess();
+    content::BrowserContext* browser_context =
+        process_host->GetBrowserContext();
+    ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context);
+    std::string extension_id = request.url.host();
+    const Extension* extension = registry->GetInstalledExtension(extension_id);
+
+    if (!AllowExtensionResourceLoad(
+            request.url, request.resource_type, request.transition_type,
+            process_host->GetID(), browser_context->IsOffTheRecord(), extension,
+            util::IsIncognitoEnabled(extension_id, browser_context),
+            registry->enabled_extensions(),
+            *ProcessMap::Get(browser_context))) {
+      client->OnComplete(
+          content::ResourceRequestCompletionStatus(net::ERR_BLOCKED_BY_CLIENT));
+      return;
+    }
+
+    base::FilePath directory_path;
+    if (!GetDirectoryForExtensionURL(request.url, extension_id, extension,
+                                     registry->disabled_extensions(),
+                                     &directory_path)) {
+      client->OnComplete(
+          content::ResourceRequestCompletionStatus(net::ERR_FAILED));
+      return;
+    }
+
+    // Set up content security policy.
+    std::string content_security_policy;
+    bool send_cors_header = false;
+    bool follow_symlinks_anywhere = false;
+    if (extension) {
+      const bool is_web_view_request =
+          WebViewGuest::FromWebContents(
+              content::WebContents::FromRenderFrameHost(frame_host_)) !=
+          nullptr;
+      GetSecurityPolicyForURL(request.url, extension, is_web_view_request,
+                              &content_security_policy, &send_cors_header,
+                              &follow_symlinks_anywhere);
+    }
+
+    if (IsBackgroundPageURL(request.url)) {
+      // Handle background page requests immediately with a simple generated
+      // chunk of HTML.
+
+      // Leave cache headers out of generated background page jobs.
+      content::ResourceResponseHead head;
+      const bool send_cors_headers = false;
+      head.headers = BuildHttpHeaders(content_security_policy,
+                                      send_cors_headers, base::Time());
+      std::string contents;
+      GenerateBackgroundPageContents(extension, &head.mime_type, &head.charset,
+                                     &contents);
+      uint32_t size = base::saturated_cast<uint32_t>(contents.size());
+      mojo::DataPipe pipe(size);
+      MojoResult result = pipe.producer_handle->WriteData(
+          contents.data(), &size, MOJO_WRITE_DATA_FLAG_NONE);
+      if (result != MOJO_RESULT_OK || size < contents.size()) {
+        client->OnComplete(
+            content::ResourceRequestCompletionStatus(net::ERR_FAILED));
+        return;
+      }
+
+      client->OnReceiveResponse(head, base::nullopt, nullptr);
+      client->OnStartLoadingResponseBody(std::move(pipe.consumer_handle));
+      client->OnComplete(content::ResourceRequestCompletionStatus(net::OK));
+      return;
+    }
+
+    // TODO(crbug.com/782015): Support component extension resource loading from
+    // the embedder's resource files. This would be the right place to try to
+    // resolve such resources, before we attempt to hit other files on disk.
+
+    base::FilePath relative_path =
+        file_util::ExtensionURLToRelativeFilePath(request.url);
+
+    // Do not allow requests for resources in the _metadata folder, since any
+    // files there are internal implementation details that should not be
+    // considered part of the extension.
+    if (base::FilePath(kMetadataFolder).IsParent(relative_path)) {
+      client->OnComplete(
+          content::ResourceRequestCompletionStatus(net::ERR_FILE_NOT_FOUND));
+      return;
+    }
+
+    // Handle shared resources (extension A loading resources out of extension
+    // B).
+    std::string path = request.url.path();
+    if (SharedModuleInfo::IsImportedPath(path)) {
+      std::string new_extension_id;
+      std::string new_relative_path;
+      SharedModuleInfo::ParseImportedPath(path, &new_extension_id,
+                                          &new_relative_path);
+      const Extension* new_extension =
+          registry->enabled_extensions().GetByID(new_extension_id);
+      if (SharedModuleInfo::ImportsExtensionById(extension, new_extension_id) &&
+          new_extension) {
+        directory_path = new_extension->path();
+        extension_id = new_extension_id;
+        relative_path = base::FilePath::FromUTF8Unsafe(new_relative_path);
+      } else {
+        client->OnComplete(content::ResourceRequestCompletionStatus(
+            net::ERR_BLOCKED_BY_CLIENT));
+        return;
+      }
+    }
+
+    // TODO(crbug.com/782015): Support content verification on extension
+    // resource requests. This is roughly the point at which we'd want to create
+    // a ContentVerifyJob and somehow hook it into the file URLLoader we set up
+    // below.
+
+    auto task_runner = base::CreateSequencedTaskRunnerWithTraits(
+        {base::MayBlock(), base::TaskPriority::BACKGROUND});
+    task_runner->PostTask(
+        FROM_HERE,
+        base::BindOnce(&LoadExtensionResourceFromFileOnBackgroundSequence,
+                       request, extension_id, directory_path, relative_path,
+                       std::move(loader), client.PassInterface()));
+  }
+
+  void Clone(content::mojom::URLLoaderFactoryRequest request) override {
+    bindings_.AddBinding(this, std::move(request));
+  }
+
+ private:
+  content::RenderFrameHost* const frame_host_;
+  const GURL frame_url_;
+
+  mojo::BindingSet<content::mojom::URLLoaderFactory> bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExtensionURLLoaderFactory);
+};
+
 }  // namespace
 
-net::HttpResponseHeaders* BuildHttpHeaders(
+scoped_refptr<net::HttpResponseHeaders> BuildHttpHeaders(
     const std::string& content_security_policy,
     bool send_cors_header,
     const base::Time& last_modified_time) {
@@ -633,4 +875,27 @@
   g_test_handler = handler;
 }
 
+std::unique_ptr<content::mojom::URLLoaderFactory>
+CreateExtensionNavigationURLLoaderFactory(
+    content::RenderFrameHost* frame_host) {
+  return std::make_unique<ExtensionURLLoaderFactory>(frame_host, GURL());
+}
+
+std::unique_ptr<content::mojom::URLLoaderFactory>
+MaybeCreateExtensionSubresourceURLLoaderFactory(
+    content::RenderFrameHost* frame_host,
+    const GURL& frame_url) {
+  // Ensure we have a non-empty URL so that the factory we create knows it's
+  // only for subresources.
+  CHECK(!frame_url.is_empty());
+
+  // TODO(rockot): We can probably avoid creating this factory in cases where
+  // |frame_url| corresponds to a non-extensions URL and the URL in question
+  // cannot have any active content scripts running and has no access to
+  // any extension's web accessible resources. For now we always create a
+  // factory, because the loader itself correctly prevents disallowed resources
+  // from loading in an invalid context.
+  return std::make_unique<ExtensionURLLoaderFactory>(frame_host, frame_url);
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/extension_protocols.h b/extensions/browser/extension_protocols.h
index 97a7e607..a83a7198 100644
--- a/extensions/browser/extension_protocols.h
+++ b/extensions/browser/extension_protocols.h
@@ -9,6 +9,8 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "content/public/common/url_loader_factory.mojom.h"
 #include "net/url_request/url_request_job_factory.h"
 
 namespace base {
@@ -16,12 +18,18 @@
 class Time;
 }
 
+namespace content {
+class RenderFrameHost;
+}
+
 namespace net {
 class URLRequest;
 class URLRequestJob;
 class HttpResponseHeaders;
 }
 
+class GURL;
+
 namespace extensions {
 class InfoMap;
 
@@ -32,7 +40,7 @@
 
 // Builds HTTP headers for an extension request. Hashes the time to avoid
 // exposing the exact user installation time of the extension.
-net::HttpResponseHeaders* BuildHttpHeaders(
+scoped_refptr<net::HttpResponseHeaders> BuildHttpHeaders(
     const std::string& content_security_policy,
     bool send_cors_header,
     const base::Time& last_modified_time);
@@ -48,6 +56,20 @@
 // way to map extra resources to be included in extensions.
 void SetExtensionProtocolTestHandler(ExtensionProtocolTestHandler* handler);
 
+// Creates a new content::mojom::URLLoaderFactory implementation suitable for
+// handling navigation requests to extension URLs.
+std::unique_ptr<content::mojom::URLLoaderFactory>
+CreateExtensionNavigationURLLoaderFactory(content::RenderFrameHost* frame_host);
+
+// Attempts to create a content::mojom::URLLoaderFactory implementation suitable
+// for handling subresource requests for extension URLs from |frame_host|. May
+// return null if |frame_host| is never allowed to load extension subresources
+// from its current navigation URL.
+std::unique_ptr<content::mojom::URLLoaderFactory>
+MaybeCreateExtensionSubresourceURLLoaderFactory(
+    content::RenderFrameHost* frame_host,
+    const GURL& frame_url);
+
 }  // namespace extensions
 
 #endif  // EXTENSIONS_BROWSER_EXTENSION_PROTOCOLS_H_
diff --git a/extensions/browser/extensions_browser_client.h b/extensions/browser/extensions_browser_client.h
index 0c70794..4f0cc1c 100644
--- a/extensions/browser/extensions_browser_client.h
+++ b/extensions/browser/extensions_browser_client.h
@@ -12,12 +12,16 @@
 #include "base/memory/ref_counted.h"
 #include "build/build_config.h"
 #include "content/public/browser/bluetooth_chooser.h"
+#include "content/public/common/resource_type.h"
+#include "content/public/common/url_loader.mojom.h"
 #include "extensions/browser/extension_event_histogram_value.h"
 #include "extensions/browser/extension_prefs_observer.h"
 #include "extensions/common/view_type.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
+#include "ui/base/page_transition_types.h"
 
 class ExtensionFunctionRegistry;
+class GURL;
 class PrefService;
 
 namespace base {
@@ -54,12 +58,13 @@
 class ExtensionApiFrameIdMap;
 class ExtensionApiFrameIdMapHelper;
 class ExtensionNavigationUIData;
+class ExtensionSet;
 class ExtensionSystem;
 class ExtensionSystemProvider;
 class ExtensionWebContentsObserver;
-class InfoMap;
 class KioskDelegate;
 class ProcessManagerDelegate;
+class ProcessMap;
 class RuntimeAPIDelegate;
 
 // Interface to allow the extensions module to make browser-process-specific
@@ -138,11 +143,16 @@
   // Returns true if the embedder wants to allow a chrome-extension:// resource
   // request coming from renderer A to access a resource in an extension running
   // in renderer B. For example, Chrome overrides this to provide support for
-  // webview and dev tools. Called on the IO thread.
-  virtual bool AllowCrossRendererResourceLoad(net::URLRequest* request,
-                                              bool is_incognito,
-                                              const Extension* extension,
-                                              InfoMap* extension_info_map) = 0;
+  // webview and dev tools. May be called on either the UI or IO thread.
+  virtual bool AllowCrossRendererResourceLoad(
+      const GURL& url,
+      content::ResourceType resource_type,
+      ui::PageTransition page_transition,
+      int child_id,
+      bool is_incognito,
+      const Extension* extension,
+      const ExtensionSet& extensions,
+      const ProcessMap& process_map) = 0;
 
   // Returns the PrefService associated with |context|.
   virtual PrefService* GetPrefServiceForContext(
diff --git a/extensions/browser/sandboxed_unpacker.cc b/extensions/browser/sandboxed_unpacker.cc
index 6384603..8a8be31 100644
--- a/extensions/browser/sandboxed_unpacker.cc
+++ b/extensions/browser/sandboxed_unpacker.cc
@@ -354,6 +354,8 @@
 SandboxedUnpacker::~SandboxedUnpacker() {
   // To avoid blocking shutdown, don't delete temporary directory here if it
   // hasn't been cleaned up or passed on to another owner yet.
+  // This is OK because ExtensionGarbageCollector will take care of the leaked
+  // |temp_dir_| eventually.
   temp_dir_.Take();
 }
 
diff --git a/extensions/browser/test_extensions_browser_client.cc b/extensions/browser/test_extensions_browser_client.cc
index 65a13d2..13e9718 100644
--- a/extensions/browser/test_extensions_browser_client.cc
+++ b/extensions/browser/test_extensions_browser_client.cc
@@ -132,10 +132,14 @@
 }
 
 bool TestExtensionsBrowserClient::AllowCrossRendererResourceLoad(
-    net::URLRequest* request,
+    const GURL& url,
+    content::ResourceType resource_type,
+    ui::PageTransition page_transition,
+    int child_id,
     bool is_incognito,
     const Extension* extension,
-    InfoMap* extension_info_map) {
+    const ExtensionSet& extensions,
+    const ProcessMap& process_map) {
   return false;
 }
 
diff --git a/extensions/browser/test_extensions_browser_client.h b/extensions/browser/test_extensions_browser_client.h
index 362a1e4..8cac8ff2 100644
--- a/extensions/browser/test_extensions_browser_client.h
+++ b/extensions/browser/test_extensions_browser_client.h
@@ -87,10 +87,14 @@
       const base::FilePath& directory_path,
       const std::string& content_security_policy,
       bool send_cors_header) override;
-  bool AllowCrossRendererResourceLoad(net::URLRequest* request,
+  bool AllowCrossRendererResourceLoad(const GURL& url,
+                                      content::ResourceType resource_type,
+                                      ui::PageTransition page_transition,
+                                      int child_id,
                                       bool is_incognito,
                                       const Extension* extension,
-                                      InfoMap* extension_info_map) override;
+                                      const ExtensionSet& extensions,
+                                      const ProcessMap& process_map) override;
   PrefService* GetPrefServiceForContext(
       content::BrowserContext* context) override;
   void GetEarlyExtensionPrefsObservers(
diff --git a/extensions/browser/url_request_util.cc b/extensions/browser/url_request_util.cc
index 13a79cbe..9d4c9c8 100644
--- a/extensions/browser/url_request_util.cc
+++ b/extensions/browser/url_request_util.cc
@@ -8,11 +8,13 @@
 
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/common/browser_side_navigation_policy.h"
+#include "content/public/common/resource_request.h"
 #include "extensions/browser/extension_navigation_ui_data.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
-#include "extensions/browser/info_map.h"
+#include "extensions/browser/process_map.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_set.h"
 #include "extensions/common/manifest_handlers/icons_handler.h"
 #include "extensions/common/manifest_handlers/web_accessible_resources_info.h"
 #include "extensions/common/manifest_handlers/webview_info.h"
@@ -21,19 +23,20 @@
 namespace extensions {
 namespace url_request_util {
 
-bool AllowCrossRendererResourceLoad(net::URLRequest* request,
+bool AllowCrossRendererResourceLoad(const GURL& url,
+                                    content::ResourceType resource_type,
+                                    ui::PageTransition page_transition,
+                                    int child_id,
                                     bool is_incognito,
                                     const Extension* extension,
-                                    InfoMap* extension_info_map,
+                                    const ExtensionSet& extensions,
+                                    const ProcessMap& process_map,
                                     bool* allowed) {
-  const content::ResourceRequestInfo* info =
-      content::ResourceRequestInfo::ForRequest(request);
-  std::string resource_path = request->url().path();
+  std::string resource_path = url.path();
 
   // PlzNavigate: this logic is performed for main frame requests in
   // ExtensionNavigationThrottle::WillStartRequest.
-  if (info->GetChildID() != -1 ||
-      info->GetResourceType() != content::RESOURCE_TYPE_MAIN_FRAME ||
+  if (child_id != -1 || resource_type != content::RESOURCE_TYPE_MAIN_FRAME ||
       !content::IsBrowserSideNavigationEnabled()) {
     // Extensions with webview: allow loading certain resources by guest
     // renderers with privileged partition IDs as specified in owner's extension
@@ -41,16 +44,15 @@
     std::string owner_extension_id;
     int owner_process_id;
     WebViewRendererState::GetInstance()->GetOwnerInfo(
-        info->GetChildID(), &owner_process_id, &owner_extension_id);
-    const Extension* owner_extension =
-        extension_info_map->extensions().GetByID(owner_extension_id);
+        child_id, &owner_process_id, &owner_extension_id);
+    const Extension* owner_extension = extensions.GetByID(owner_extension_id);
     std::string partition_id;
     bool is_guest = WebViewRendererState::GetInstance()->GetPartitionID(
-        info->GetChildID(), &partition_id);
+        child_id, &partition_id);
 
     if (AllowCrossRendererResourceLoadHelper(
             is_guest, extension, owner_extension, partition_id, resource_path,
-            info->GetPageTransition(), allowed)) {
+            page_transition, allowed)) {
       return true;
     }
   }
@@ -68,19 +70,17 @@
   // some extensions want to be able to do things like create their own
   // launchers.
   base::StringPiece resource_root_relative_path =
-      request->url().path_piece().empty()
-          ? base::StringPiece()
-          : request->url().path_piece().substr(1);
+      url.path_piece().empty() ? base::StringPiece()
+                               : url.path_piece().substr(1);
   if (extension->is_hosted_app() &&
       !IconsInfo::GetIcons(extension)
            .ContainsPath(resource_root_relative_path)) {
-    LOG(ERROR) << "Denying load of " << request->url().spec() << " from "
-               << "hosted app.";
+    LOG(ERROR) << "Denying load of " << url.spec() << " from hosted app.";
     *allowed = false;
     return true;
   }
 
-  DCHECK_EQ(extension->url(), request->url().GetWithEmptyPath());
+  DCHECK_EQ(extension->url(), url.GetWithEmptyPath());
 
   // Extensions with manifest before v2 did not have web_accessible_resource
   // section, therefore the request needs to be allowed.
@@ -91,14 +91,14 @@
 
   // Navigating the main frame to an extension URL is allowed, even if not
   // explicitly listed as web_accessible_resource.
-  if (info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME) {
+  if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME) {
     *allowed = true;
     return true;
-  } else if (info->GetResourceType() == content::RESOURCE_TYPE_SUB_FRAME) {
+  } else if (resource_type == content::RESOURCE_TYPE_SUB_FRAME) {
     // When navigating in subframe, allow if it is the same origin
     // as the top-level frame. This can only be the case if the subframe
     // request is coming from the extension process.
-    if (extension_info_map->process_map().Contains(info->GetChildID())) {
+    if (process_map.Contains(child_id)) {
       *allowed = true;
       return true;
     }
@@ -114,13 +114,13 @@
   // Since not all subresources are required to be listed in a v2
   // manifest, we must allow all subresource loads if there are any web
   // accessible resources. See http://crbug.com/179127.
-  if (!content::IsResourceTypeFrame(info->GetResourceType()) &&
+  if (!content::IsResourceTypeFrame(resource_type) &&
       WebAccessibleResourcesInfo::HasWebAccessibleResources(extension)) {
     *allowed = true;
     return true;
   }
 
-  if (!ui::PageTransitionIsWebTriggerable(info->GetPageTransition())) {
+  if (!ui::PageTransitionIsWebTriggerable(page_transition)) {
     *allowed = false;
     return true;
   }
@@ -129,22 +129,6 @@
   return false;
 }
 
-bool IsWebViewRequest(net::URLRequest* request) {
-  const content::ResourceRequestInfo* info =
-      content::ResourceRequestInfo::ForRequest(request);
-  // |info| can be NULL sometimes: http://crbug.com/370070.
-  if (!info)
-    return false;
-  if (WebViewRendererState::GetInstance()->IsGuest(info->GetChildID()))
-    return true;
-
-  // GetChildId() is -1 with PlzNavigate for navigation requests, so also try
-  // the ExtensionNavigationUIData data.
-  ExtensionNavigationUIData* data =
-      ExtensionsBrowserClient::Get()->GetExtensionNavigationUIData(request);
-  return data && data->is_web_view();
-}
-
 bool AllowCrossRendererResourceLoadHelper(bool is_guest,
                                           const Extension* extension,
                                           const Extension* owner_extension,
diff --git a/extensions/browser/url_request_util.h b/extensions/browser/url_request_util.h
index e3a5eb52..fb831a1bc 100644
--- a/extensions/browser/url_request_util.h
+++ b/extensions/browser/url_request_util.h
@@ -7,15 +7,19 @@
 
 #include <string>
 
+#include "content/public/common/resource_type.h"
 #include "ui/base/page_transition_types.h"
 
+class GURL;
+
 namespace net {
 class URLRequest;
 }
 
 namespace extensions {
 class Extension;
-class InfoMap;
+class ExtensionSet;
+class ProcessMap;
 
 // Utilities related to URLRequest jobs for extension resources. See
 // chrome/browser/extensions/extension_protocols_unittest.cc for related tests.
@@ -24,16 +28,16 @@
 // Sets allowed=true to allow a chrome-extension:// resource request coming from
 // renderer A to access a resource in an extension running in renderer B.
 // Returns false when it couldn't determine if the resource is allowed or not
-bool AllowCrossRendererResourceLoad(net::URLRequest* request,
+bool AllowCrossRendererResourceLoad(const GURL& url,
+                                    content::ResourceType resource_type,
+                                    ui::PageTransition page_transition,
+                                    int child_id,
                                     bool is_incognito,
                                     const Extension* extension,
-                                    InfoMap* extension_info_map,
+                                    const ExtensionSet& extensions,
+                                    const ProcessMap& process_map,
                                     bool* allowed);
 
-// Returns true if |request| corresponds to a resource request from a
-// <webview>.
-bool IsWebViewRequest(net::URLRequest* request);
-
 // Helper method that is called by both AllowCrossRendererResourceLoad and
 // ExtensionNavigationThrottle to share logic.
 // Sets allowed=true to allow a chrome-extension:// resource request coming from
diff --git a/extensions/common/features/feature_session_type.cc b/extensions/common/features/feature_session_type.cc
index 83a3740..191655c6 100644
--- a/extensions/common/features/feature_session_type.cc
+++ b/extensions/common/features/feature_session_type.cc
@@ -26,7 +26,11 @@
   // |ScopedCurrentFeatureSessionType|.
   CHECK(g_current_session_type == kDefaultSessionType ||
         session_type == g_current_session_type);
-  g_current_session_type = session_type;
+  // In certain unit tests, SetCurrentFeatureSessionType() can be called
+  // within the same process (where e.g. utility processes run as a separate
+  // thread). Don't write if the value is the same to avoid TSAN failures.
+  if (session_type != g_current_session_type)
+    g_current_session_type = session_type;
 }
 
 std::unique_ptr<base::AutoReset<FeatureSessionType>>
diff --git a/extensions/shell/browser/shell_extensions_browser_client.cc b/extensions/shell/browser/shell_extensions_browser_client.cc
index 942572bb9..e2c35d0 100644
--- a/extensions/shell/browser/shell_extensions_browser_client.cc
+++ b/extensions/shell/browser/shell_extensions_browser_client.cc
@@ -127,13 +127,18 @@
 }
 
 bool ShellExtensionsBrowserClient::AllowCrossRendererResourceLoad(
-    net::URLRequest* request,
+    const GURL& url,
+    content::ResourceType resource_type,
+    ui::PageTransition page_transition,
+    int child_id,
     bool is_incognito,
     const Extension* extension,
-    InfoMap* extension_info_map) {
+    const ExtensionSet& extensions,
+    const ProcessMap& process_map) {
   bool allowed = false;
   if (url_request_util::AllowCrossRendererResourceLoad(
-          request, is_incognito, extension, extension_info_map, &allowed)) {
+          url, resource_type, page_transition, child_id, is_incognito,
+          extension, extensions, process_map, &allowed)) {
     return allowed;
   }
 
diff --git a/extensions/shell/browser/shell_extensions_browser_client.h b/extensions/shell/browser/shell_extensions_browser_client.h
index 6d20f68c..398aea7 100644
--- a/extensions/shell/browser/shell_extensions_browser_client.h
+++ b/extensions/shell/browser/shell_extensions_browser_client.h
@@ -58,10 +58,14 @@
       const base::FilePath& directory_path,
       const std::string& content_security_policy,
       bool send_cors_header) override;
-  bool AllowCrossRendererResourceLoad(net::URLRequest* request,
+  bool AllowCrossRendererResourceLoad(const GURL& url,
+                                      content::ResourceType resource_type,
+                                      ui::PageTransition page_transition,
+                                      int child_id,
                                       bool is_incognito,
                                       const Extension* extension,
-                                      InfoMap* extension_info_map) override;
+                                      const ExtensionSet& extensions,
+                                      const ProcessMap& process_map) override;
   PrefService* GetPrefServiceForContext(
       content::BrowserContext* context) override;
   void GetEarlyExtensionPrefsObservers(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 8d37b235..61767cf 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -630,6 +630,7 @@
   ErrorState* GetErrorState() override;
   const ContextState* GetContextState() override { return &state_; }
   scoped_refptr<ShaderTranslatorInterface> GetTranslator(GLenum type) override;
+  scoped_refptr<ShaderTranslatorInterface> GetOrCreateTranslator(GLenum type);
 
   void SetIgnoreCachedStateForTest(bool ignore) override;
   void SetForceShaderNameHashingForTest(bool force) override;
@@ -10753,10 +10754,15 @@
 
 scoped_refptr<ShaderTranslatorInterface> GLES2DecoderImpl::GetTranslator(
     GLenum type) {
+  return type == GL_VERTEX_SHADER ? vertex_translator_ : fragment_translator_;
+}
+
+scoped_refptr<ShaderTranslatorInterface>
+GLES2DecoderImpl::GetOrCreateTranslator(GLenum type) {
   if (!InitializeShaderTranslator()) {
     return nullptr;
   }
-  return type == GL_VERTEX_SHADER ? vertex_translator_ : fragment_translator_;
+  return GetTranslator(type);
 }
 
 void GLES2DecoderImpl::DoCompileShader(GLuint client_id) {
@@ -10768,7 +10774,7 @@
 
   scoped_refptr<ShaderTranslatorInterface> translator;
   if (!feature_info_->disable_shader_translator())
-      translator = GetTranslator(shader->shader_type());
+    translator = GetOrCreateTranslator(shader->shader_type());
 
   const Shader::TranslatedShaderSourceType source_type =
       feature_info_->feature_flags().angle_translated_shader_source ?
diff --git a/gpu/command_buffer/tests/fuzzer_main.cc b/gpu/command_buffer/tests/fuzzer_main.cc
index eb35e653..92c2b50 100644
--- a/gpu/command_buffer/tests/fuzzer_main.cc
+++ b/gpu/command_buffer/tests/fuzzer_main.cc
@@ -348,6 +348,10 @@
 
     decoder_->set_max_bucket_size(8 << 20);
     context_group->buffer_manager()->set_max_buffer_size(8 << 20);
+    return decoder_->MakeCurrent();
+  }
+
+  void ResetDecoder() {
     // Keep a reference to the translators, which keeps them in the cache even
     // after the decoder is reset. They are expensive to initialize, but they
     // don't keep state.
@@ -358,10 +362,6 @@
     translator = decoder_->GetTranslator(GL_FRAGMENT_SHADER);
     if (translator)
       translator->AddRef();
-    return decoder_->MakeCurrent();
-  }
-
-  void ResetDecoder() {
     decoder_->Destroy(true);
     decoder_.reset();
     if (recreate_context_) {
diff --git a/ios/build/bots/chromium.mac/ios-simulator-eg.json b/ios/build/bots/chromium.mac/ios-simulator-eg.json
index 9490c2a0..077ef21e 100644
--- a/ios/build/bots/chromium.mac/ios-simulator-eg.json
+++ b/ios/build/bots/chromium.mac/ios-simulator-eg.json
@@ -66,6 +66,13 @@
       "xctest": true
     },
     {
+      "app": "ios_chrome_bookmarks_egtests",
+      "device type": "iPhone 6s",
+      "os": "11.0",
+      "xcode version": "9.0",
+      "xctest": true
+    },
+    {
       "app": "ios_chrome_web_egtests",
       "device type": "iPhone 6s",
       "os": "11.0",
@@ -138,6 +145,13 @@
       "xctest": true
     },
     {
+      "app": "ios_chrome_bookmarks_egtests",
+      "device type": "iPad Air 2",
+      "os": "11.0",
+      "xcode version": "9.0",
+      "xctest": true
+    },
+    {
       "app": "ios_chrome_web_egtests",
       "device type": "iPad Air 2",
       "os": "11.0",
diff --git a/ios/build/bots/tests/eg_tests.json b/ios/build/bots/tests/eg_tests.json
index 6ad30e1..fa5aaf8 100644
--- a/ios/build/bots/tests/eg_tests.json
+++ b/ios/build/bots/tests/eg_tests.json
@@ -8,6 +8,10 @@
       "xctest": true
     },
     {
+      "app": "ios_chrome_bookmarks_egtests",
+      "xctest": true
+    },
+    {
       "app": "ios_chrome_web_egtests",
       "xctest": true
     },
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 244db35..c6a7828 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -128,6 +128,7 @@
     "//ios/chrome/browser/ui/fullscreen",
     "//ios/chrome/browser/ui/history:history_base_feature",
     "//ios/chrome/browser/ui/main:feature_flags",
+    "//ios/chrome/browser/ui/toolbar:feature",
     "//ios/chrome/browser/ui/toolbar/public:toolbar_base_feature",
     "//ios/chrome/common",
     "//ios/components/io_thread",
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS
index 7cb984f..8a6df2c88 100644
--- a/ios/chrome/browser/DEPS
+++ b/ios/chrome/browser/DEPS
@@ -102,6 +102,7 @@
   "+net",
   "+rlz/features",
   "+services/metrics",
+  "+services/service_manager",
   "+third_party/breakpad/breakpad/src/client/ios",
   "+third_party/breakpad/breakpad/src/common",
   "+third_party/brotli",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index a7e2f46..e2f2fd9 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -45,6 +45,7 @@
 #import "ios/chrome/browser/ui/history/history_base_feature.h"
 #include "ios/chrome/browser/ui/main/main_feature_flags.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
+#import "ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/web/public/features.h"
diff --git a/ios/chrome/browser/component_updater/BUILD.gn b/ios/chrome/browser/component_updater/BUILD.gn
index d510f0e..5036bc9d 100644
--- a/ios/chrome/browser/component_updater/BUILD.gn
+++ b/ios/chrome/browser/component_updater/BUILD.gn
@@ -15,5 +15,6 @@
     "//ios/chrome/browser/google",
     "//ios/chrome/common",
     "//ios/web",
+    "//services/service_manager/public/cpp",
   ]
 }
diff --git a/ios/chrome/browser/component_updater/ios_component_updater_configurator.cc b/ios/chrome/browser/component_updater/ios_component_updater_configurator.cc
index f1e6447..f88bfa0 100644
--- a/ios/chrome/browser/component_updater/ios_component_updater_configurator.cc
+++ b/ios/chrome/browser/component_updater/ios_component_updater_configurator.cc
@@ -6,17 +6,18 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "base/version.h"
 #include "components/component_updater/configurator_impl.h"
 #include "components/update_client/activity_data_service.h"
-#include "components/update_client/out_of_process_patcher.h"
 #include "components/update_client/update_query_params.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/google/google_brand.h"
 #include "ios/chrome/common/channel_info.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 namespace component_updater {
 
@@ -43,7 +44,7 @@
   std::string ExtraRequestParams() const override;
   std::string GetDownloadPreference() const override;
   net::URLRequestContextGetter* RequestContext() const override;
-  scoped_refptr<update_client::OutOfProcessPatcher> CreateOutOfProcessPatcher()
+  std::unique_ptr<service_manager::Connector> CreateServiceManagerConnector()
       const override;
   bool EnabledDeltas() const override;
   bool EnabledComponentUpdates() const override;
@@ -133,8 +134,8 @@
   return configurator_impl_.RequestContext();
 }
 
-scoped_refptr<update_client::OutOfProcessPatcher>
-IOSConfigurator::CreateOutOfProcessPatcher() const {
+std::unique_ptr<service_manager::Connector>
+IOSConfigurator::CreateServiceManagerConnector() const {
   return nullptr;
 }
 
diff --git a/ios/chrome/browser/payments/ios_payment_instrument.h b/ios/chrome/browser/payments/ios_payment_instrument.h
index 7adde13..4d81b429 100644
--- a/ios/chrome/browser/payments/ios_payment_instrument.h
+++ b/ios/chrome/browser/payments/ios_payment_instrument.h
@@ -57,11 +57,12 @@
   void RecordUse() override;
   base::string16 GetLabel() const override;
   base::string16 GetSublabel() const override;
-  bool IsValidForModifier(
-      const std::vector<std::string>& supported_methods,
-      const std::vector<std::string>& supported_networks,
-      const std::set<autofill::CreditCard::CardType>& supported_types,
-      bool supported_types_specified) const override;
+  bool IsValidForModifier(const std::vector<std::string>& methods,
+                          bool supported_networks_specified,
+                          const std::set<std::string>& supported_networks,
+                          bool supported_types_specified,
+                          const std::set<autofill::CreditCard::CardType>&
+                              supported_types) const override;
 
   // Given that the icon for the iOS payment instrument can only be determined
   // at run-time, the icon is obtained using this UIImage object rather than
diff --git a/ios/chrome/browser/payments/ios_payment_instrument.mm b/ios/chrome/browser/payments/ios_payment_instrument.mm
index ff3d0e2..cec618fa 100644
--- a/ios/chrome/browser/payments/ios_payment_instrument.mm
+++ b/ios/chrome/browser/payments/ios_payment_instrument.mm
@@ -90,14 +90,14 @@
 }
 
 bool IOSPaymentInstrument::IsValidForModifier(
-    const std::vector<std::string>& supported_methods,
-    const std::vector<std::string>& supported_networks,
-    const std::set<autofill::CreditCard::CardType>& supported_types,
-    bool supported_types_specified) const {
+    const std::vector<std::string>& methods,
+    bool supported_networks_specified,
+    const std::set<std::string>& supported_networks,
+    bool supported_types_specified,
+    const std::set<autofill::CreditCard::CardType>& supported_types) const {
   // This instrument only matches url-based payment method identifiers that
   // are equal to the instrument's method name.
-  if (std::find(supported_methods.begin(), supported_methods.end(),
-                method_name_) == supported_methods.end())
+  if (std::find(methods.begin(), methods.end(), method_name_) == methods.end())
     return false;
 
   // TODO(crbug.com/602666): Determine if the native payment app supports
diff --git a/ios/chrome/browser/payments/payment_request.mm b/ios/chrome/browser/payments/payment_request.mm
index 34ee7ab..98cdfe0a 100644
--- a/ios/chrome/browser/payments/payment_request.mm
+++ b/ios/chrome/browser/payments/payment_request.mm
@@ -301,23 +301,25 @@
   }
 
   for (const auto& modifier : web_payment_request_.details.modifiers) {
-    std::vector<std::string> supported_networks;
-    std::set<autofill::CreditCard::CardType> supported_types;
+    std::set<std::string> supported_card_networks_set;
+    std::set<autofill::CreditCard::CardType> supported_card_types_set;
     // The following 4 variables are unused.
     std::set<std::string> unused_basic_card_specified_networks;
-    std::set<std::string> unused_supported_card_networks_set;
+    std::vector<std::string> unused_supported_card_networks;
     std::vector<GURL> unused_url_payment_method_identifiers;
     std::set<std::string> unused_payment_method_identifiers;
-    PopulateValidatedMethodData({modifier.method_data}, &supported_networks,
-                                &unused_basic_card_specified_networks,
-                                &unused_supported_card_networks_set,
-                                &supported_types,
-                                &unused_url_payment_method_identifiers,
-                                &unused_payment_method_identifiers);
+    PopulateValidatedMethodData(
+        {modifier.method_data}, &unused_supported_card_networks,
+        &unused_basic_card_specified_networks, &supported_card_networks_set,
+        &supported_card_types_set, &unused_url_payment_method_identifiers,
+        &unused_payment_method_identifiers);
 
     if (selected_instrument->IsValidForModifier(
-            modifier.method_data.supported_methods, supported_networks,
-            supported_types, !modifier.method_data.supported_types.empty())) {
+            modifier.method_data.supported_methods,
+            !modifier.method_data.supported_networks.empty(),
+            supported_card_networks_set,
+            !modifier.method_data.supported_types.empty(),
+            supported_card_types_set)) {
       return &modifier;
     }
   }
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index 917cb8f..3330978a 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -59,6 +59,7 @@
     "//base",
     "//base:i18n",
     "//ios/chrome/browser",
+    "//ios/chrome/browser/ui/toolbar:feature",
     "//ios/chrome/browser/ui/toolbar/public:toolbar_base_feature",
     "//ios/web",
     "//ui/base",
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 5397195..38ccd95a 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -171,7 +171,6 @@
 #import "ios/chrome/browser/ui/tabs/requirements/tab_strip_constants.h"
 #import "ios/chrome/browser/ui/tabs/requirements/tab_strip_presentation.h"
 #import "ios/chrome/browser/ui/tabs/tab_strip_legacy_coordinator.h"
-#import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
 #include "ios/chrome/browser/ui/toolbar/toolbar_coordinator.h"
 #include "ios/chrome/browser/ui/toolbar/toolbar_model_delegate_ios.h"
 #include "ios/chrome/browser/ui/toolbar/toolbar_model_ios.h"
@@ -1310,7 +1309,7 @@
   [self installFakeStatusBar];
   [self buildToolbarAndTabStrip];
   [self setUpViewLayout];
-  if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+  if (IsSafeAreaCompatibleToolbarEnabled()) {
     [self addConstraintsToToolbar];
   }
   // If the tab model and browser state are valid, finish initialization.
@@ -1334,7 +1333,7 @@
   if (IsIPhoneX()) {
     [self setUpViewLayout];
   }
-  if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+  if (IsSafeAreaCompatibleToolbarEnabled()) {
     // TODO(crbug.com/778236): Check if this call can be removed once the
     // Toolbar is a contained ViewController.
     [_toolbarCoordinator.toolbarViewController viewSafeAreaInsetsDidChange];
@@ -2057,7 +2056,7 @@
   CGRect toolbarFrame = _toolbarCoordinator.toolbarViewController.view.frame;
   toolbarFrame.origin = CGPointMake(0, minY);
   toolbarFrame.size.width = widthOfView;
-  if (!base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+  if (!IsSafeAreaCompatibleToolbarEnabled()) {
     [_toolbarCoordinator.toolbarViewController.view setFrame:toolbarFrame];
   }
 
@@ -4828,12 +4827,12 @@
     } else if ([_findBarController isFindInPageShown]) {
       [self.view insertSubview:_toolbarCoordinator.toolbarViewController.view
                   belowSubview:[_findBarController view]];
-      if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+      if (IsSafeAreaCompatibleToolbarEnabled()) {
         [self addConstraintsToToolbar];
       }
     } else {
       [self.view addSubview:_toolbarCoordinator.toolbarViewController.view];
-      if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+      if (IsSafeAreaCompatibleToolbarEnabled()) {
         [self addConstraintsToToolbar];
       }
     }
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm b/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm
index 73b54ad..f95a1e3 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm
@@ -12,7 +12,6 @@
 #import "ios/chrome/browser/ui/ntp/google_landing_data_source.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_header_constants.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.h"
-#import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_utils.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_snapshot_providing.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
@@ -62,7 +61,7 @@
 
   [self addSubview:[_toolbarController view]];
 
-  if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+  if (IsSafeAreaCompatibleToolbarEnabled()) {
     [self addConstraintsToToolbar];
   } else {
     CGRect toolbarFrame = self.bounds;
@@ -170,7 +169,7 @@
 
 - (void)safeAreaInsetsDidChange {
   [super safeAreaInsetsDidChange];
-  if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+  if (IsSafeAreaCompatibleToolbarEnabled()) {
     _toolbarController.heightConstraint.constant =
         ToolbarHeightWithTopOfScreenOffset(
             [_toolbarController statusBarOffset]);
@@ -198,7 +197,7 @@
 - (void)reparentToolbarController {
   DCHECK(![[_toolbarController view] isDescendantOfView:self]);
   [self addSubview:[_toolbarController view]];
-  if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+  if (IsSafeAreaCompatibleToolbarEnabled()) {
     [self addConstraintsToToolbar];
   }
 }
diff --git a/ios/chrome/browser/ui/stack_view/stack_view_controller.mm b/ios/chrome/browser/ui/stack_view/stack_view_controller.mm
index 2a65278..f5859672 100644
--- a/ios/chrome/browser/ui/stack_view/stack_view_controller.mm
+++ b/ios/chrome/browser/ui/stack_view/stack_view_controller.mm
@@ -769,7 +769,7 @@
   [self.view addSubview:[_toolbarController view]];
   [_toolbarController didMoveToParentViewController:self];
 
-  if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+  if (IsSafeAreaCompatibleToolbarEnabled()) {
     [[_toolbarController view].leadingAnchor
         constraintEqualToAnchor:self.view.leadingAnchor]
         .active = YES;
@@ -807,7 +807,7 @@
   }
   [self.view addSubview:_scrollView];
 
-  if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+  if (IsSafeAreaCompatibleToolbarEnabled()) {
     [_scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
     [NSLayoutConstraint activateConstraints:@[
       [_scrollView.topAnchor
@@ -836,7 +836,7 @@
 
 - (void)viewSafeAreaInsetsDidChange {
   [super viewSafeAreaInsetsDidChange];
-  if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+  if (IsSafeAreaCompatibleToolbarEnabled()) {
     [_toolbarController heightConstraint].constant =
         ToolbarHeightWithTopOfScreenOffset(
             [_toolbarController statusBarOffset]);
@@ -860,7 +860,7 @@
     // Calls like -viewportSizeWasChanged should instead be called in
     // viewDidLayoutSubviews, but since stack_view_controller is going away in
     // the near future, it's easier to put this here instead of refactoring.
-    if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+    if (IsSafeAreaCompatibleToolbarEnabled()) {
       [self.view layoutIfNeeded];
     }
 
@@ -1714,7 +1714,7 @@
   CGRect currentCardFrame =
       AlignRectOriginAndSizeToPixels(LayoutRectGetRect(currentCardLayout));
 
-  if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+  if (IsSafeAreaCompatibleToolbarEnabled()) {
     // Forces a layout because the views may not yet be positioned correctly
     // due to a screen rotation.
     [self.view layoutIfNeeded];
@@ -2016,7 +2016,7 @@
   [_activeCardSet.displayView
       insertSubview:self.transitionToolbarController.view
        aboveSubview:_activeCardSet.currentCard.view];
-  if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar) &&
+  if (IsSafeAreaCompatibleToolbarEnabled() &&
       self.transitionToolbarController && _activeCardSet.currentCard.view) {
     [self.transitionToolbarController.view.leadingAnchor
         constraintEqualToAnchor:_activeCardSet.displayView.leadingAnchor]
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
index 882c229..1ec8881 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
@@ -202,6 +202,17 @@
                               forProtocol:@protocol(BrowserCommands)];
     [_dispatcher startDispatchingToTarget:endpoint
                               forProtocol:@protocol(ApplicationCommands)];
+    // -startDispatchingToTarget:forProtocol: doesn't pick up protocols the
+    // passed protocol conforms to, so ApplicationSettingsCommands is explicitly
+    // dispatched to the endpoint as well. Since this is potentially
+    // fragile, DCHECK that it should still work (if the endpoint is nonnull).
+    DCHECK(
+        !endpoint ||
+        [endpoint conformsToProtocol:@protocol(ApplicationSettingsCommands)]);
+    [_dispatcher
+        startDispatchingToTarget:endpoint
+                     forProtocol:@protocol(ApplicationSettingsCommands)];
+
     // self.dispatcher shouldn't be used in this init method, so duplicate the
     // typecast to pass dispatcher into child objects.
     id<ApplicationCommands, BrowserCommands> passableDispatcher =
diff --git a/ios/chrome/browser/ui/toolbar/BUILD.gn b/ios/chrome/browser/ui/toolbar/BUILD.gn
index 206c8db..984a3fb 100644
--- a/ios/chrome/browser/ui/toolbar/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/BUILD.gn
@@ -115,6 +115,17 @@
   ]
 }
 
+source_set("feature") {
+  sources = [
+    "toolbar_private_base_feature.h",
+    "toolbar_private_base_feature.mm",
+  ]
+  deps = [
+    "//base",
+  ]
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
+
 source_set("resource_macros") {
   sources = [
     "toolbar_resource_macros.h",
diff --git a/ios/chrome/browser/ui/toolbar/public/BUILD.gn b/ios/chrome/browser/ui/toolbar/public/BUILD.gn
index 4d5aae0..cb89be53 100644
--- a/ios/chrome/browser/ui/toolbar/public/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/public/BUILD.gn
@@ -27,4 +27,5 @@
   deps = [
     "//base",
   ]
+  configs += [ "//build/config/compiler:enable_arc" ]
 }
diff --git a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h
index 5096d3c..4f3b0c3 100644
--- a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h
+++ b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h
@@ -7,9 +7,6 @@
 
 #include "base/feature_list.h"
 
-// Feature to choose whether the toolbar respects the safe area.
-extern const base::Feature kSafeAreaCompatibleToolbar;
-
 // Feature to choose whether the toolbar uses UIViewPropertyAnimators.
 extern const base::Feature kPropertyAnimationsToolbar;
 
diff --git a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.mm b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.mm
index 22c4fa2..7aa4482 100644
--- a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.mm
+++ b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.mm
@@ -4,8 +4,9 @@
 
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
 
-const base::Feature kSafeAreaCompatibleToolbar{
-    "SafeAreaCompatibleToolbar", base::FEATURE_DISABLED_BY_DEFAULT};
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
 
 extern const base::Feature kPropertyAnimationsToolbar{
     "PropertyAnimationsToolbar", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/toolbar/public/toolbar_utils.mm b/ios/chrome/browser/ui/toolbar/public/toolbar_utils.mm
index 3e002a7..322fcb7 100644
--- a/ios/chrome/browser/ui/toolbar/public/toolbar_utils.mm
+++ b/ios/chrome/browser/ui/toolbar/public/toolbar_utils.mm
@@ -6,7 +6,6 @@
 
 #include "base/feature_list.h"
 #include "base/logging.h"
-#import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_constants.h"
 #import "ios/chrome/browser/ui/ui_util.h"
 
@@ -15,7 +14,7 @@
 #endif
 
 CGFloat ToolbarHeightWithTopOfScreenOffset(CGFloat status_bar_offset) {
-  DCHECK(base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar));
+  DCHECK(IsSafeAreaCompatibleToolbarEnabled());
   InterfaceIdiom idiom = IsIPadIdiom() ? IPAD_IDIOM : IPHONE_IDIOM;
   CGRect frame = kToolbarFrame[idiom];
   if (idiom == IPHONE_IDIOM) {
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
index fcd81a7..4aceb9b 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
@@ -21,7 +21,6 @@
 #import "ios/chrome/browser/ui/image_util.h"
 #import "ios/chrome/browser/ui/reversed_animation.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
-#import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_controller+protected.h"
 #include "ios/chrome/browser/ui/toolbar/toolbar_resource_macros.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_tools_menu_button.h"
@@ -159,7 +158,7 @@
     }
 
     self.view = [[ToolbarView alloc] initWithFrame:viewFrame];
-    if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+    if (IsSafeAreaCompatibleToolbarEnabled()) {
       [self.view setTranslatesAutoresizingMaskIntoConstraints:NO];
     }
 
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.h b/ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.h
new file mode 100644
index 0000000..fb16e7c
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.h
@@ -0,0 +1,15 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_PRIVATE_BASE_FEATURE_H_
+#define IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_PRIVATE_BASE_FEATURE_H_
+
+#include "base/feature_list.h"
+
+// Feature to choose whether the toolbar respects the safe area.
+// Do not use it directly, uses the IsSafeAreaCompatibleToolbarEnabled()
+// function instead.
+extern const base::Feature kSafeAreaCompatibleToolbar;
+
+#endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_PRIVATE_BASE_FEATURE_H_
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.mm b/ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.mm
new file mode 100644
index 0000000..889e5ee
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.mm
@@ -0,0 +1,12 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+const base::Feature kSafeAreaCompatibleToolbar{
+    "SafeAreaCompatibleToolbar", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_view.mm b/ios/chrome/browser/ui/toolbar/toolbar_view.mm
index 453fb84..da7df372 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_view.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_view.mm
@@ -4,8 +4,8 @@
 
 #import "ios/chrome/browser/ui/toolbar/toolbar_view.h"
 
-#import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_view_delegate.h"
+#include "ios/chrome/browser/ui/ui_util.h"
 
 @implementation ToolbarView
 
@@ -16,7 +16,7 @@
 - (instancetype)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
   if (self) {
-    if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+    if (IsSafeAreaCompatibleToolbarEnabled()) {
       // The minimal width of the toolbar.
       // Must be less than or equal to the smallest UIWindow size Chrome can
       // be in, which as of M64 is 320.
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
index ef8d37d..1f88e59 100644
--- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
@@ -2444,7 +2444,7 @@
   CGRect frame = [self view].frame;
   CGFloat oldWidth = frame.size.width;
   frame.size.width = width;
-  if (!base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar))
+  if (!IsSafeAreaCompatibleToolbarEnabled())
     [self view].frame = frame;
 
   UIGraphicsBeginImageContextWithOptions(frame.size, NO, 0.0);
@@ -2453,8 +2453,7 @@
   UIGraphicsEndImageContext();
 
   // If self.view is offscreen during render, UIKit sets views' origin to 0,0.
-  if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar) &&
-      frame.origin.y != 0) {
+  if (IsSafeAreaCompatibleToolbarEnabled() && frame.origin.y != 0) {
     CGRect fixFrame = [self view].frame;
     fixFrame.origin.y = frame.origin.y;
     [self view].frame = fixFrame;
@@ -2472,7 +2471,7 @@
   DCHECK_EQ(frame.size.height, [self view].frame.size.height);
 
   frame.size.width = oldWidth;
-  if (!base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+  if (!IsSafeAreaCompatibleToolbarEnabled()) {
     [self view].frame = frame;
   }
 
@@ -2575,7 +2574,7 @@
 - (void)viewSafeAreaInsetsDidChange {
   [super viewSafeAreaInsetsDidChange];
   if (!IsIPadIdiom()) {
-    if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+    if (IsSafeAreaCompatibleToolbarEnabled()) {
       // The clipping view's height is supposed to match the toolbar's height.
       // The clipping view can't match the toolbar's height with autoresizing
       // masks because the clipping view is not a direct child of the toolbar.
diff --git a/ios/chrome/browser/ui/ui_util.h b/ios/chrome/browser/ui/ui_util.h
index e7c6ddac..592e4be 100644
--- a/ios/chrome/browser/ui/ui_util.h
+++ b/ios/chrome/browser/ui/ui_util.h
@@ -39,6 +39,10 @@
 // Returns true if the device is an iPhone X.
 bool IsIPhoneX();
 
+// Returns whether the feature to force the toolbar to respect the safe area is
+// enabled.
+bool IsSafeAreaCompatibleToolbarEnabled();
+
 // Returns the height of the status bar, accounting for orientation.
 CGFloat StatusBarHeight();
 
diff --git a/ios/chrome/browser/ui/ui_util.mm b/ios/chrome/browser/ui/ui_util.mm
index 208f6679..28fe597 100644
--- a/ios/chrome/browser/ui/ui_util.mm
+++ b/ios/chrome/browser/ui/ui_util.mm
@@ -10,6 +10,7 @@
 #include "base/feature_list.h"
 #include "base/logging.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
+#import "ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ui/base/device_form_factor.h"
 #include "ui/gfx/ios/uikit_util.h"
@@ -61,12 +62,17 @@
           CGRectGetHeight([[UIScreen mainScreen] nativeBounds]) == 2436);
 }
 
+bool IsSafeAreaCompatibleToolbarEnabled() {
+  return IsIPhoneX() &&
+         base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar);
+}
+
 CGFloat StatusBarHeight() {
   // This is a temporary solution until usage of StatusBarHeight has been
   // replaced with topLayoutGuide.
 
   if (IsIPhoneX()) {
-    if (base::FeatureList::IsEnabled(kSafeAreaCompatibleToolbar)) {
+    if (IsSafeAreaCompatibleToolbarEnabled()) {
       CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
       return CGRectGetHeight(statusBarFrame);
     } else {
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn
index 57b330b..f9b00a8 100644
--- a/ios/chrome/test/earl_grey/BUILD.gn
+++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -7,6 +7,7 @@
 group("all_tests") {
   testonly = true
   deps = [
+    ":ios_chrome_bookmarks_egtests",
     ":ios_chrome_device_check_egtests",
     ":ios_chrome_external_url_egtests",
     ":ios_chrome_flaky_egtests",
@@ -47,6 +48,12 @@
   ]
 }
 
+chrome_ios_eg_test("ios_chrome_bookmarks_egtests") {
+  deps = [
+    "//ios/chrome/browser/ui/bookmarks:eg_tests",
+  ]
+}
+
 chrome_ios_eg_test("ios_chrome_settings_egtests") {
   deps = [
     "//ios/chrome/browser/ui/settings:eg_tests",
@@ -58,7 +65,6 @@
     "//ios/chrome/browser/ui:eg_tests",
     "//ios/chrome/browser/ui/activity_services:eg_tests",
     "//ios/chrome/browser/ui/alert_coordinator:eg_tests",
-    "//ios/chrome/browser/ui/bookmarks:eg_tests",
     "//ios/chrome/browser/ui/content_suggestions:eg_tests",
     "//ios/chrome/browser/ui/dialogs:eg_tests",
     "//ios/chrome/browser/ui/find_bar:eg_tests",
@@ -104,6 +110,7 @@
     "//ios/chrome/app/application_delegate:application_delegate_internal",
 
     # Depends on all EarlGrey test suites to create multitasking tests suite.
+    ":ios_chrome_bookmarks_egtests_deps_group",
     ":ios_chrome_integration_egtests_deps_group",
     ":ios_chrome_settings_egtests_deps_group",
     ":ios_chrome_ui_egtests_deps_group",
@@ -138,6 +145,7 @@
 
     # Depends on all EarlGrey test suites to run all the FLAKY_ tests found.
     # When adding a new test application, please follow the same pattern.
+    ":ios_chrome_bookmarks_egtests_deps_group",
     ":ios_chrome_integration_egtests_deps_group",
     ":ios_chrome_settings_egtests_deps_group",
     ":ios_chrome_ui_egtests_deps_group",
diff --git a/ios/third_party/material_internationalization_ios/BUILD.gn b/ios/third_party/material_internationalization_ios/BUILD.gn
index 179d69d..f20ab98 100644
--- a/ios/third_party/material_internationalization_ios/BUILD.gn
+++ b/ios/third_party/material_internationalization_ios/BUILD.gn
@@ -11,17 +11,7 @@
   visibility = [ ":material_internationalization_ios" ]
 }
 
-ios_info_plist("info_plist") {
-  info_plist = "src/Sources/Info.plist"
-  executable_name = "MDFInternationalization"
-  extra_substitutions = [
-    "PRODUCT_BUNDLE_IDENTIFIER=$ios_app_bundle_id_prefix.$chromium_bundle_id.$executable_name",
-    "CURRENT_PROJECT_VERSION=1.0",
-  ]
-}
-
 ios_framework_bundle("material_internationalization_ios") {
-  info_plist_target = ":info_plist"
   output_name = "MDFInternationalization"
   sources = [
     "src/Sources/MDFInternationalization.h",
@@ -52,4 +42,14 @@
     "//build/config/compiler:no_chromium_code",
     "//build/config/gcc:symbol_visibility_default",
   ]
+
+  _project_version = "1.0"
+  _bundle_identifier =
+      "$ios_app_bundle_id_prefix.$chromium_bundle_id.$output_name"
+
+  info_plist = "src/Sources/Info.plist"
+  extra_substitutions = [
+    "PRODUCT_BUNDLE_IDENTIFIER=$_bundle_identifier",
+    "CURRENT_PROJECT_VERSION=$_project_version",
+  ]
 }
diff --git a/ios/web/web_state/web_view_internal_creation_util.mm b/ios/web/web_state/web_view_internal_creation_util.mm
index ee5393f..595b141 100644
--- a/ios/web/web_state/web_view_internal_creation_util.mm
+++ b/ios/web/web_state/web_view_internal_creation_util.mm
@@ -57,11 +57,6 @@
   // reasonable value.
   web_view.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
 
-  if (@available(iOS 11.0, *)) {
-    web_view.scrollView.contentInsetAdjustmentBehavior =
-        UIScrollViewContentInsetAdjustmentNever;
-  }
-
   if (context_menu_delegate) {
     CRWContextMenuController* context_menu_controller = [
         [CRWContextMenuController alloc] initWithWebView:web_view
diff --git a/ipc/ipc_mojo_perftest.cc b/ipc/ipc_mojo_perftest.cc
index df5e966..299c1f29 100644
--- a/ipc/ipc_mojo_perftest.cc
+++ b/ipc/ipc_mojo_perftest.cc
@@ -337,14 +337,11 @@
     mojo::MessagePipeHandle mp_handle(mp);
     mojo::ScopedMessagePipeHandle scoped_mp(mp_handle);
 
+    LockThreadAffinity thread_locker(kSharedCore);
     // In single process mode, this is running in a task and by default other
     // tasks (in particular, the binding) won't run. To keep the single process
     // and multi-process code paths the same, enable nestable tasks.
-    base::MessageLoop::ScopedNestableTaskAllower nest_loop(
-        base::MessageLoop::current());
-
-    LockThreadAffinity thread_locker(kSharedCore);
-    base::RunLoop run_loop;
+    base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
     ReflectorImpl impl(std::move(scoped_mp), run_loop.QuitWhenIdleClosure());
     run_loop.Run();
     return 0;
@@ -508,14 +505,11 @@
     mojo::MessagePipeHandle mp_handle(mp);
     mojo::ScopedMessagePipeHandle scoped_mp(mp_handle);
 
+    LockThreadAffinity thread_locker(kSharedCore);
     // In single process mode, this is running in a task and by default other
     // tasks (in particular, the binding) won't run. To keep the single process
     // and multi-process code paths the same, enable nestable tasks.
-    base::MessageLoop::ScopedNestableTaskAllower nest_loop(
-        base::MessageLoop::current());
-
-    LockThreadAffinity thread_locker(kSharedCore);
-    base::RunLoop run_loop;
+    base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
     InterfacePassingTestDriverImpl impl(std::move(scoped_mp),
                                         run_loop.QuitWhenIdleClosure());
     run_loop.Run();
diff --git a/ipc/ipc_sync_channel.cc b/ipc/ipc_sync_channel.cc
index dd636b5..eca1d76 100644
--- a/ipc/ipc_sync_channel.cc
+++ b/ipc/ipc_sync_channel.cc
@@ -682,9 +682,7 @@
 }
 
 void SyncChannel::WaitForReplyWithNestedMessageLoop(SyncContext* context) {
-  base::MessageLoop::ScopedNestableTaskAllower allow(
-      base::MessageLoop::current());
-  base::RunLoop nested_loop;
+  base::RunLoop nested_loop(base::RunLoop::Type::kNestableTasksAllowed);
   ReceivedSyncMsgQueue::NestedSendDoneWatcher watcher(context, &nested_loop);
   nested_loop.Run();
 }
diff --git a/media/base/audio_decoder_config.cc b/media/base/audio_decoder_config.cc
index 2792e2d..27bf7ad 100644
--- a/media/base/audio_decoder_config.cc
+++ b/media/base/audio_decoder_config.cc
@@ -17,7 +17,8 @@
       channel_layout_(CHANNEL_LAYOUT_UNSUPPORTED),
       samples_per_second_(0),
       bytes_per_frame_(0),
-      codec_delay_(0) {}
+      codec_delay_(0),
+      should_discard_decoder_delay_(true) {}
 
 AudioDecoderConfig::AudioDecoderConfig(
     AudioCodec codec,
@@ -55,6 +56,8 @@
   // |bytes_per_frame_| will be overwritten in SetChannelsForDiscrete()
   channels_ = ChannelLayoutToChannelCount(channel_layout_);
   bytes_per_frame_ = channels_ * bytes_per_channel_;
+
+  should_discard_decoder_delay_ = true;
 }
 
 AudioDecoderConfig::~AudioDecoderConfig() {}
@@ -67,8 +70,7 @@
          samples_per_second_ > 0 &&
          samples_per_second_ <= limits::kMaxSampleRate &&
          sample_format_ != kUnknownSampleFormat &&
-         seek_preroll_ >= base::TimeDelta() &&
-         codec_delay_ >= 0;
+         seek_preroll_ >= base::TimeDelta() && codec_delay_ >= 0;
 }
 
 bool AudioDecoderConfig::Matches(const AudioDecoderConfig& config) const {
@@ -80,7 +82,9 @@
           (encryption_scheme().Matches(config.encryption_scheme())) &&
           (sample_format() == config.sample_format()) &&
           (seek_preroll() == config.seek_preroll()) &&
-          (codec_delay() == config.codec_delay()));
+          (codec_delay() == config.codec_delay()) &&
+          (should_discard_decoder_delay() ==
+           config.should_discard_decoder_delay()));
 }
 
 std::string AudioDecoderConfig::AsHumanReadableString() const {
@@ -94,7 +98,8 @@
     << " seek_preroll: " << seek_preroll().InMilliseconds() << "ms"
     << " codec_delay: " << codec_delay() << " has extra data? "
     << (extra_data().empty() ? "false" : "true") << " encrypted? "
-    << (is_encrypted() ? "true" : "false");
+    << (is_encrypted() ? "true" : "false") << " discard decoder delay? "
+    << (should_discard_decoder_delay() ? "true" : "false");
   return s.str();
 }
 
diff --git a/media/base/audio_decoder_config.h b/media/base/audio_decoder_config.h
index ab759ce..a4328af 100644
--- a/media/base/audio_decoder_config.h
+++ b/media/base/audio_decoder_config.h
@@ -94,6 +94,14 @@
   // useful for decryptors that decrypts an encrypted stream to a clear stream.
   void SetIsEncrypted(bool is_encrypted);
 
+  bool should_discard_decoder_delay() const {
+    return should_discard_decoder_delay_;
+  }
+
+  void disable_discard_decoder_delay() {
+    should_discard_decoder_delay_ = false;
+  }
+
  private:
   AudioCodec codec_;
   SampleFormat sample_format_;
@@ -114,6 +122,10 @@
   // as padding added during encoding.
   int codec_delay_;
 
+  // Indicates if a decoder should implicitly discard decoder delay without it
+  // being explicitly marked in discard padding.
+  bool should_discard_decoder_delay_;
+
   // Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler
   // generated copy constructor and assignment operator. Since the extra data is
   // typically small, the performance impact is minimal.
diff --git a/media/filters/ffmpeg_audio_decoder.cc b/media/filters/ffmpeg_audio_decoder.cc
index d97d6162..ee895e0 100644
--- a/media/filters/ffmpeg_audio_decoder.cc
+++ b/media/filters/ffmpeg_audio_decoder.cc
@@ -307,6 +307,9 @@
   codec_context_->get_buffer2 = GetAudioBufferImpl;
   codec_context_->refcounted_frames = 1;
 
+  if (!config.should_discard_decoder_delay())
+    codec_context_->flags2 |= AV_CODEC_FLAG2_SKIP_MANUAL;
+
   if (config.codec() == kCodecOpus)
     codec_context_->request_sample_fmt = AV_SAMPLE_FMT_FLT;
 
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index e6d435b..5d8e0ae 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -402,6 +402,9 @@
       audio_config.Initialize(codec, sample_format, channel_layout,
                               sample_per_second, extra_data, scheme,
                               base::TimeDelta(), 0);
+      if (codec == kCodecAAC)
+        audio_config.disable_discard_decoder_delay();
+
       DVLOG(1) << "audio_track_id=" << audio_track_id
                << " config=" << audio_config.AsHumanReadableString();
       if (!audio_config.IsValidConfig()) {
diff --git a/media/formats/mpeg/mpeg_audio_stream_parser_base.cc b/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
index bc453a24..20eacf26 100644
--- a/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
+++ b/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
@@ -210,6 +210,8 @@
     config_.Initialize(audio_codec_, kSampleFormatF32, channel_layout,
                        sample_rate, extra_data, Unencrypted(),
                        base::TimeDelta(), codec_delay_);
+    if (audio_codec_ == kCodecAAC)
+      config_.disable_discard_decoder_delay();
 
     base::TimeDelta base_timestamp;
     if (timestamp_helper_)
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index b13676ea..1618cd1 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -1544,7 +1544,8 @@
 
 TEST_P(MSEPipelineIntegrationTest, ADTS) {
   MockMediaSource source("sfx.adts", kADTS, kAppendWholeFile);
-  EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));
+  EXPECT_EQ(PIPELINE_OK,
+            StartPipelineWithMediaSource(&source, kHashed, nullptr));
   source.EndOfStream();
 
   EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
@@ -1554,6 +1555,9 @@
   Play();
 
   EXPECT_TRUE(WaitUntilOnEnded());
+
+  // Verify that nothing was stripped.
+  EXPECT_HASH_EQ("0.46,1.72,4.26,4.57,3.39,1.53,", GetAudioHash());
 }
 
 TEST_P(MSEPipelineIntegrationTest, ADTS_TimestampOffset) {
@@ -1584,7 +1588,7 @@
   EXPECT_EQ(592, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
 
   // Verify preroll is stripped.
-  EXPECT_HASH_EQ("-0.25,0.67,0.04,0.14,-0.49,-0.41,", GetAudioHash());
+  EXPECT_HASH_EQ("-1.76,-1.35,-0.72,0.70,1.24,0.52,", GetAudioHash());
 }
 
 TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_MP3) {
@@ -1598,6 +1602,17 @@
   EXPECT_HASH_EQ("1.30,2.72,4.56,5.08,3.74,2.03,", GetAudioHash());
 }
 
+TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_ADTS) {
+  ASSERT_EQ(PIPELINE_OK, Start("sfx.adts", kHashed));
+
+  Play();
+
+  ASSERT_TRUE(WaitUntilOnEnded());
+
+  // Verify codec delay and preroll are stripped.
+  EXPECT_HASH_EQ("1.80,1.66,2.31,3.26,4.46,3.36,", GetAudioHash());
+}
+
 TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_FlacInMp4) {
   ASSERT_EQ(PIPELINE_OK, Start("sfx-flac.mp4", kHashed));
   Play();
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index 5eead70..e06d838f 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -39,6 +39,8 @@
 #include "net/log/net_log_event_type.h"
 #include "net/log/net_log_source.h"
 #include "net/log/net_log_source_type.h"
+#include "net/quic/chromium/bidirectional_stream_quic_impl.h"
+#include "net/quic/chromium/quic_http_stream.h"
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/client_socket_pool.h"
 #include "net/socket/client_socket_pool_manager.h"
@@ -1087,18 +1089,22 @@
       return result;
 
     if (stream_type_ == HttpStreamRequest::BIDIRECTIONAL_STREAM) {
-      bidirectional_stream_impl_ =
-          quic_request_.CreateBidirectionalStreamImpl();
-      if (!bidirectional_stream_impl_) {
+      std::unique_ptr<QuicChromiumClientSession::Handle> session =
+          quic_request_.ReleaseSessionHandle();
+      if (!session) {
         // Quic session is closed before stream can be created.
         return ERR_CONNECTION_CLOSED;
       }
+      bidirectional_stream_impl_.reset(
+          new BidirectionalStreamQuicImpl(std::move(session)));
     } else {
-      stream_ = quic_request_.CreateStream();
-      if (!stream_) {
+      std::unique_ptr<QuicChromiumClientSession::Handle> session =
+          quic_request_.ReleaseSessionHandle();
+      if (!session) {
         // Quic session is closed before stream can be created.
         return ERR_CONNECTION_CLOSED;
       }
+      stream_.reset(new QuicHttpStream(std::move(session)));
     }
     next_state_ = STATE_NONE;
     return OK;
diff --git a/net/quic/chromium/quic_network_transaction_unittest.cc b/net/quic/chromium/quic_network_transaction_unittest.cc
index 52a4cbff..016b0a6 100644
--- a/net/quic/chromium/quic_network_transaction_unittest.cc
+++ b/net/quic/chromium/quic_network_transaction_unittest.cc
@@ -42,6 +42,7 @@
 #include "net/quic/chromium/mock_crypto_client_stream_factory.h"
 #include "net/quic/chromium/mock_quic_data.h"
 #include "net/quic/chromium/quic_chromium_alarm_factory.h"
+#include "net/quic/chromium/quic_http_stream.h"
 #include "net/quic/chromium/quic_http_utils.h"
 #include "net/quic/chromium/quic_stream_factory_peer.h"
 #include "net/quic/chromium/quic_test_packet_maker.h"
diff --git a/net/quic/chromium/quic_stream_factory.cc b/net/quic/chromium/quic_stream_factory.cc
index c02bd29..71daa9f 100644
--- a/net/quic/chromium/quic_stream_factory.cc
+++ b/net/quic/chromium/quic_stream_factory.cc
@@ -33,11 +33,9 @@
 #include "net/cert/cert_verifier.h"
 #include "net/cert/ct_verifier.h"
 #include "net/dns/host_resolver.h"
-#include "net/http/bidirectional_stream_impl.h"
 #include "net/log/net_log_capture_mode.h"
 #include "net/log/net_log_event_type.h"
 #include "net/log/net_log_source_type.h"
-#include "net/quic/chromium/bidirectional_stream_quic_impl.h"
 #include "net/quic/chromium/crypto/channel_id_chromium.h"
 #include "net/quic/chromium/crypto/proof_verifier_chromium.h"
 #include "net/quic/chromium/properties_based_quic_server_info.h"
@@ -46,6 +44,7 @@
 #include "net/quic/chromium/quic_chromium_packet_reader.h"
 #include "net/quic/chromium/quic_chromium_packet_writer.h"
 #include "net/quic/chromium/quic_crypto_client_stream_factory.h"
+#include "net/quic/chromium/quic_http_stream.h"
 #include "net/quic/chromium/quic_server_info.h"
 #include "net/quic/core/crypto/proof_verifier.h"
 #include "net/quic/core/crypto/quic_random.h"
@@ -633,19 +632,12 @@
   return factory_->GetTimeDelayForWaitingJob(server_id_);
 }
 
-std::unique_ptr<HttpStream> QuicStreamRequest::CreateStream() {
+std::unique_ptr<QuicChromiumClientSession::Handle>
+QuicStreamRequest::ReleaseSessionHandle() {
   if (!session_ || !session_->IsConnected())
     return nullptr;
 
-  return std::make_unique<QuicHttpStream>(std::move(session_));
-}
-
-std::unique_ptr<BidirectionalStreamImpl>
-QuicStreamRequest::CreateBidirectionalStreamImpl() {
-  if (!session_ || !session_->IsConnected())
-    return nullptr;
-
-  return std::make_unique<BidirectionalStreamQuicImpl>(std::move(session_));
+  return std::move(session_);
 }
 
 QuicStreamFactory::QuicStreamFactory(
diff --git a/net/quic/chromium/quic_stream_factory.h b/net/quic/chromium/quic_stream_factory.h
index fc0c343..10151d05 100644
--- a/net/quic/chromium/quic_stream_factory.h
+++ b/net/quic/chromium/quic_stream_factory.h
@@ -32,7 +32,6 @@
 #include "net/quic/chromium/network_connection.h"
 #include "net/quic/chromium/quic_chromium_client_session.h"
 #include "net/quic/chromium/quic_clock_skew_detector.h"
-#include "net/quic/chromium/quic_http_stream.h"
 #include "net/quic/core/quic_client_push_promise_index.h"
 #include "net/quic/core/quic_config.h"
 #include "net/quic/core/quic_crypto_stream.h"
@@ -67,7 +66,6 @@
 class QuicStreamFactory;
 class SocketPerformanceWatcherFactory;
 class TransportSecurityState;
-class BidirectionalStreamImpl;
 
 namespace test {
 class QuicStreamFactoryPeer;
@@ -97,7 +95,7 @@
   NETWORK_NOTIFICATION_MAX
 };
 
-// Encapsulates a pending request for a QuicHttpStream.
+// Encapsulates a pending request for a QuicChromiumClientSession.
 // If the request is still pending when it is destroyed, it will
 // cancel the request with the factory.
 class NET_EXPORT_PRIVATE QuicStreamRequest {
@@ -125,9 +123,8 @@
   // returns the amount of time waiting job should be delayed.
   base::TimeDelta GetTimeDelayForWaitingJob() const;
 
-  std::unique_ptr<HttpStream> CreateStream();
-
-  std::unique_ptr<BidirectionalStreamImpl> CreateBidirectionalStreamImpl();
+  // Releases the handle to the QUIC session retrieved as a result of Request().
+  std::unique_ptr<QuicChromiumClientSession::Handle> ReleaseSessionHandle();
 
   // Sets |session_|.
   void SetSession(std::unique_ptr<QuicChromiumClientSession::Handle> session);
@@ -149,8 +146,7 @@
   DISALLOW_COPY_AND_ASSIGN(QuicStreamRequest);
 };
 
-// A factory for creating new QuicHttpStreams on top of a pool of
-// QuicChromiumClientSessions.
+// A factory for fetching QuicChromiumClientSessions.
 class NET_EXPORT_PRIVATE QuicStreamFactory
     : public NetworkChangeNotifier::IPAddressObserver,
       public NetworkChangeNotifier::NetworkObserver,
@@ -223,7 +219,7 @@
   bool CanUseExistingSession(const QuicServerId& server_id,
                              const HostPortPair& destination);
 
-  // Creates a new QuicHttpStream to |host_port_pair| which will be
+  // Fetches a QuicChromiumClientSession to |host_port_pair| which will be
   // owned by |request|.
   // If a matching session already exists, this method will return OK.  If no
   // matching session exists, this will return ERR_IO_PENDING and will invoke
diff --git a/net/quic/chromium/quic_stream_factory_fuzzer.cc b/net/quic/chromium/quic_stream_factory_fuzzer.cc
index 30cc6f0..026d5a4 100644
--- a/net/quic/chromium/quic_stream_factory_fuzzer.cc
+++ b/net/quic/chromium/quic_stream_factory_fuzzer.cc
@@ -13,6 +13,7 @@
 #include "net/http/http_server_properties_impl.h"
 #include "net/http/transport_security_state.h"
 #include "net/quic/chromium/mock_crypto_client_stream_factory.h"
+#include "net/quic/chromium/quic_http_stream.h"
 #include "net/quic/chromium/test_task_runner.h"
 #include "net/quic/test_tools/mock_clock.h"
 #include "net/quic/test_tools/mock_random.h"
@@ -115,9 +116,11 @@
                   env->net_log, &net_error_details, callback.callback());
 
   callback.WaitForResult();
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
-  if (!stream.get())
+  std::unique_ptr<QuicChromiumClientSession::Handle> session =
+      request.ReleaseSessionHandle();
+  if (!session)
     return 0;
+  std::unique_ptr<HttpStream> stream(new QuicHttpStream(std::move(session)));
 
   HttpRequestInfo request_info;
   request_info.method = kMethod;
diff --git a/net/quic/chromium/quic_stream_factory_test.cc b/net/quic/chromium/quic_stream_factory_test.cc
index c5e1de6..1694b1a 100644
--- a/net/quic/chromium/quic_stream_factory_test.cc
+++ b/net/quic/chromium/quic_stream_factory_test.cc
@@ -27,6 +27,7 @@
 #include "net/quic/chromium/mock_crypto_client_stream_factory.h"
 #include "net/quic/chromium/mock_quic_data.h"
 #include "net/quic/chromium/properties_based_quic_server_info.h"
+#include "net/quic/chromium/quic_http_stream.h"
 #include "net/quic/chromium/quic_http_utils.h"
 #include "net/quic/chromium/quic_server_info.h"
 #include "net/quic/chromium/quic_stream_factory_peer.h"
@@ -237,6 +238,15 @@
     Initialize();
   }
 
+  std::unique_ptr<HttpStream> CreateStream(QuicStreamRequest* request) {
+    std::unique_ptr<QuicChromiumClientSession::Handle> session =
+        request->ReleaseSessionHandle();
+    if (!session || !session->IsConnected())
+      return nullptr;
+
+    return std::make_unique<QuicHttpStream>(std::move(session));
+  }
+
   bool HasActiveSession(const HostPortPair& host_port_pair) {
     QuicServerId server_id(host_port_pair, PRIVACY_MODE_DISABLED);
     return QuicStreamFactoryPeer::HasActiveSession(factory_.get(), server_id);
@@ -286,7 +296,7 @@
                               &net_error_details_, callback_.callback()));
 
     EXPECT_THAT(callback_.WaitForResult(), IsOk());
-    std::unique_ptr<HttpStream> stream = request.CreateStream();
+    std::unique_ptr<HttpStream> stream = CreateStream(&request);
     EXPECT_TRUE(stream.get());
     stream.reset();
 
@@ -430,7 +440,7 @@
     // posted by QuicChromiumClientSession::MigrateToSocket().
     base::RunLoop().RunUntilIdle();
 
-    std::unique_ptr<HttpStream> stream = request.CreateStream();
+    std::unique_ptr<HttpStream> stream = CreateStream(&request);
     EXPECT_TRUE(stream.get());
 
     // Cause QUIC stream to be created.
@@ -759,7 +769,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   QuicStreamRequest request2(factory_.get());
@@ -767,7 +777,7 @@
                                  /*cert_verify_flags=*/0, url_, "GET", net_log_,
                                  &net_error_details_, callback_.callback()));
   // Will reset stream 3.
-  stream = request2.CreateStream();
+  stream = CreateStream(&request2);
 
   EXPECT_TRUE(stream.get());
 
@@ -777,7 +787,7 @@
   EXPECT_EQ(OK, request3.Request(host_port_pair_, version_, privacy_mode_,
                                  /*cert_verify_flags=*/0, url_, "GET", net_log_,
                                  &net_error_details_, callback_.callback()));
-  stream = request3.CreateStream();  // Will reset stream 5.
+  stream = CreateStream(&request3);  // Will reset stream 5.
   stream.reset();                    // Will reset stream 7.
 
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
@@ -805,7 +815,7 @@
                                 /*cert_verify_flags=*/0, url_, "GET", net_log_,
                                 &net_error_details_, callback_.callback()));
 
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
   EXPECT_TRUE(socket_data.AllWriteDataConsumed());
@@ -832,7 +842,7 @@
                                 /*cert_verify_flags=*/0, url_, "POST", net_log_,
                                 &net_error_details_, callback_.callback()));
 
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
   EXPECT_TRUE(socket_data.AllWriteDataConsumed());
@@ -855,7 +865,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
@@ -917,7 +927,7 @@
   EXPECT_TRUE(http_server_properties_.GetSupportsQuic(&last_address));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
@@ -951,7 +961,7 @@
   IPAddress last_address;
   EXPECT_FALSE(http_server_properties_.GetSupportsQuic(&last_address));
 
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
@@ -986,7 +996,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
@@ -1017,7 +1027,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
@@ -1048,7 +1058,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
@@ -1074,7 +1084,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
@@ -1104,7 +1114,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
@@ -1146,7 +1156,7 @@
   EXPECT_EQ(OK, request.Request(host_port_pair_, version_, privacy_mode_,
                                 /*cert_verify_flags=*/0, url_, "GET", net_log_,
                                 &net_error_details_, callback_.callback()));
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   TestCompletionCallback callback;
@@ -1155,7 +1165,7 @@
             request2.Request(server2, version_, privacy_mode_,
                              /*cert_verify_flags=*/0, url2_, "GET", net_log_,
                              &net_error_details_, callback.callback()));
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   EXPECT_EQ(GetActiveSession(host_port_pair_), GetActiveSession(server2));
@@ -1206,7 +1216,7 @@
                              /*cert_verify_flags=*/0, url2_, "GET", net_log_,
                              &net_error_details_, callback.callback()));
   EXPECT_EQ(OK, callback.WaitForResult());
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
@@ -1239,7 +1249,7 @@
   EXPECT_EQ(OK, request.Request(host_port_pair_, version_, privacy_mode_,
                                 /*cert_verify_flags=*/0, url_, "GET", net_log_,
                                 &net_error_details_, callback_.callback()));
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   TestCompletionCallback callback;
@@ -1248,7 +1258,7 @@
             request2.Request(server2, version_, privacy_mode_,
                              /*cert_verify_flags=*/0, url2_, "GET", net_log_,
                              &net_error_details_, callback.callback()));
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   factory_->OnSessionGoingAway(GetActiveSession(host_port_pair_));
@@ -1261,7 +1271,7 @@
             request3.Request(server2, version_, privacy_mode_,
                              /*cert_verify_flags=*/0, url2_, "GET", net_log_,
                              &net_error_details_, callback3.callback()));
-  std::unique_ptr<HttpStream> stream3 = request3.CreateStream();
+  std::unique_ptr<HttpStream> stream3 = CreateStream(&request3);
   EXPECT_TRUE(stream3.get());
 
   EXPECT_TRUE(HasActiveSession(server2));
@@ -1294,7 +1304,7 @@
   EXPECT_EQ(OK, request.Request(server1, version_, privacy_mode_,
                                 /*cert_verify_flags=*/0, url_, "GET", net_log_,
                                 &net_error_details_, callback_.callback()));
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   TestCompletionCallback callback;
@@ -1303,7 +1313,7 @@
             request2.Request(server2, version_, privacy_mode_,
                              /*cert_verify_flags=*/0, url2_, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   EXPECT_EQ(GetActiveSession(server1), GetActiveSession(server2));
@@ -1339,7 +1349,7 @@
   EXPECT_EQ(OK, request.Request(server1, version_, privacy_mode_,
                                 /*cert_verify_flags=*/0, url_, "GET", net_log_,
                                 &net_error_details_, callback_.callback()));
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   TestCompletionCallback callback;
@@ -1348,7 +1358,7 @@
             request2.Request(server2, version_, privacy_mode_,
                              /*cert_verify_flags=*/0, url2_, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   EXPECT_EQ(GetActiveSession(server1), GetActiveSession(server2));
@@ -1395,7 +1405,7 @@
   EXPECT_EQ(OK, request.Request(server1, version_, privacy_mode_,
                                 /*cert_verify_flags=*/0, url_, "GET", net_log_,
                                 &net_error_details_, callback_.callback()));
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   TestCompletionCallback callback;
@@ -1404,7 +1414,7 @@
             request2.Request(server2, version_, privacy_mode_,
                              /*cert_verify_flags=*/0, url2_, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   EXPECT_NE(GetActiveSession(server1), GetActiveSession(server2));
@@ -1437,7 +1447,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Mark the session as going away.  Ensure that while it is still alive
@@ -1456,7 +1466,7 @@
                              /*cert_verify_flags=*/0, url_, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   EXPECT_TRUE(HasActiveSession(host_port_pair_));
@@ -1503,7 +1513,7 @@
     } else {
       EXPECT_THAT(rv, IsOk());
     }
-    std::unique_ptr<HttpStream> stream = request.CreateStream();
+    std::unique_ptr<HttpStream> stream = CreateStream(&request);
     EXPECT_TRUE(stream);
     EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
                                            net_log_, CompletionCallback()));
@@ -1514,7 +1524,7 @@
   EXPECT_EQ(OK, request.Request(host_port_pair_, version_, privacy_mode_,
                                 /*cert_verify_flags=*/0, url_, "GET", net_log_,
                                 &net_error_details_, CompletionCallback()));
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream);
   EXPECT_EQ(ERR_IO_PENDING,
             stream->InitializeStream(&request_info, DEFAULT_PRIORITY, net_log_,
@@ -1595,7 +1605,7 @@
   EXPECT_EQ(OK, request2.Request(host_port_pair_, version_, privacy_mode_,
                                  /*cert_verify_flags=*/0, url_, "GET", net_log_,
                                  &net_error_details_, callback_.callback()));
-  std::unique_ptr<HttpStream> stream = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request2);
 
   EXPECT_TRUE(stream.get());
   stream.reset();
@@ -1628,7 +1638,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   HttpRequestInfo request_info;
   EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
                                          net_log_, CompletionCallback()));
@@ -1648,7 +1658,7 @@
                              &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  stream = request2.CreateStream();
+  stream = CreateStream(&request2);
   stream.reset();  // Will reset stream 3.
 
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
@@ -1712,7 +1722,7 @@
   EXPECT_FALSE(HasActiveJob(host_port_pair_, privacy_mode_));
 
   // Create QuicHttpStream.
-  std::unique_ptr<HttpStream> stream = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request2);
   EXPECT_TRUE(stream.get());
   stream.reset();
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
@@ -1772,7 +1782,7 @@
   EXPECT_FALSE(HasActiveJob(host_port_pair_, privacy_mode_));
 
   // Create QuicHttpStream.
-  std::unique_ptr<HttpStream> stream = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request2);
   EXPECT_TRUE(stream.get());
   stream.reset();
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
@@ -1805,7 +1815,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   HttpRequestInfo request_info;
   EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
                                          net_log_, CompletionCallback()));
@@ -1829,7 +1839,7 @@
                              &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  stream = request2.CreateStream();
+  stream = CreateStream(&request2);
   stream.reset();  // Will reset stream 3.
 
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
@@ -1858,7 +1868,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   HttpRequestInfo request_info;
   EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
                                          net_log_, CompletionCallback()));
@@ -1876,7 +1886,7 @@
   EXPECT_EQ(OK, request2.Request(host_port_pair_, version_, privacy_mode_,
                                  /*cert_verify_flags=*/0, url_, "GET", net_log_,
                                  &net_error_details_, callback_.callback()));
-  stream = request2.CreateStream();
+  stream = CreateStream(&request2);
 
   stream.reset();
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
@@ -1920,7 +1930,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -1987,7 +1997,7 @@
                              /*cert_verify_flags=*/0, url_, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   EXPECT_TRUE(HasActiveSession(host_port_pair_));
@@ -2050,7 +2060,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -2112,7 +2122,7 @@
                              /*cert_verify_flags=*/0, url_, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   EXPECT_TRUE(HasActiveSession(host_port_pair_));
@@ -2160,7 +2170,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -2218,7 +2228,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created, but marked as non-migratable.
@@ -2267,7 +2277,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -2319,7 +2329,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created, but marked as non-migratable.
@@ -2367,7 +2377,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -2415,7 +2425,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Ensure that session is alive and active.
@@ -2453,7 +2463,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Ensure that session is alive and active.
@@ -2495,7 +2505,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -2571,7 +2581,7 @@
                              /*cert_verify_flags=*/0, url_, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   EXPECT_TRUE(HasActiveSession(host_port_pair_));
@@ -2618,7 +2628,7 @@
   EXPECT_EQ(OK, request1.Request(server1, version_, privacy_mode_,
                                  /*cert_verify_flags=*/0, url_, "GET", net_log_,
                                  &net_error_details_, callback_.callback()));
-  std::unique_ptr<HttpStream> stream1 = request1.CreateStream();
+  std::unique_ptr<HttpStream> stream1 = CreateStream(&request1);
   EXPECT_TRUE(stream1.get());
 
   // Create request and QuicHttpStream to create session2.
@@ -2627,7 +2637,7 @@
             request2.Request(server2, version_, privacy_mode_,
                              /*cert_verify_flags=*/0, url2_, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   QuicChromiumClientSession* session1 = GetActiveSession(server1);
@@ -2713,7 +2723,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -2777,7 +2787,7 @@
                              /*cert_verify_flags=*/0, url_, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   EXPECT_TRUE(HasActiveSession(host_port_pair_));
@@ -2838,7 +2848,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -2904,7 +2914,7 @@
                              /*cert_verify_flags=*/0, url_, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   EXPECT_TRUE(HasActiveSession(host_port_pair_));
@@ -2957,7 +2967,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -3009,7 +3019,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created, but marked as non-migratable.
@@ -3061,7 +3071,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -3119,7 +3129,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_EQ(OK, callback_.WaitForResult());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -3208,7 +3218,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_EQ(OK, callback_.WaitForResult());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -3297,7 +3307,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_EQ(OK, callback_.WaitForResult());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created, but marked as non-migratable.
@@ -3361,7 +3371,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_EQ(OK, callback_.WaitForResult());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -3440,7 +3450,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_EQ(OK, callback_.WaitForResult());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -3520,7 +3530,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_EQ(OK, callback_.WaitForResult());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -3618,7 +3628,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_EQ(OK, callback_.WaitForResult());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -3717,7 +3727,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_EQ(OK, callback_.WaitForResult());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -3798,7 +3808,7 @@
                              /*cert_verify_flags=*/0, url_, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   EXPECT_TRUE(HasActiveSession(host_port_pair_));
@@ -3850,7 +3860,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_EQ(OK, callback_.WaitForResult());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -3939,7 +3949,7 @@
                              /*cert_verify_flags=*/0, url_, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   EXPECT_TRUE(HasActiveSession(host_port_pair_));
@@ -4004,7 +4014,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -4067,7 +4077,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_EQ(OK, callback_.WaitForResult());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -4210,7 +4220,7 @@
                             /*cert_verify_flags=*/0, url_, "GET", net_log_,
                             &net_error_details_, callback_.callback()));
   EXPECT_EQ(OK, callback_.WaitForResult());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Cause QUIC stream to be created.
@@ -4265,7 +4275,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   HttpRequestInfo request_info;
   EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
                                          net_log_, CompletionCallback()));
@@ -4285,7 +4295,7 @@
                              &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  stream = request2.CreateStream();
+  stream = CreateStream(&request2);
   stream.reset();  // Will reset stream 3.
 
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
@@ -4318,7 +4328,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   HttpRequestInfo request_info;
   EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
                                          net_log_, CompletionCallback()));
@@ -4339,7 +4349,7 @@
                              &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  stream = request2.CreateStream();
+  stream = CreateStream(&request2);
   stream.reset();  // Will reset stream 3.
 
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
@@ -4447,7 +4457,7 @@
   // the CancelWaitForDataReady task hasn't been posted.
   ASSERT_EQ(0u, runner_->GetPostedTasks().size());
 
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
   EXPECT_TRUE(socket_data.AllWriteDataConsumed());
@@ -4494,7 +4504,7 @@
   EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
             session->connection()->ping_timeout());
 
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
   HttpRequestInfo request_info;
   EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
@@ -4526,7 +4536,7 @@
   EXPECT_EQ(QuicTime::Delta::FromSeconds(10),
             session2->connection()->ping_timeout());
 
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
   EXPECT_EQ(OK, stream2->InitializeStream(&request_info, DEFAULT_PRIORITY,
                                           net_log_, CompletionCallback()));
@@ -4591,7 +4601,7 @@
 
   EXPECT_EQ(OK, callback_.WaitForResult());
 
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   // Restore |race_cert_verification|.
@@ -4645,7 +4655,7 @@
   // yielded the read.
   EXPECT_EQ(1u, observer.executed_count());
 
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_FALSE(stream.get());  // Session is already closed.
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
   EXPECT_TRUE(socket_data.AllWriteDataConsumed());
@@ -4691,7 +4701,7 @@
   // yielded the read.
   EXPECT_EQ(1u, observer.executed_count());
 
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_FALSE(stream.get());  // Session is already closed.
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
   EXPECT_TRUE(socket_data.AllWriteDataConsumed());
@@ -4714,7 +4724,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get()));
@@ -4761,7 +4771,7 @@
                             &net_error_details_, callback_.callback()));
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = request.CreateStream();
+  std::unique_ptr<HttpStream> stream = CreateStream(&request);
   EXPECT_TRUE(stream.get());
 
   EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get()));
@@ -4790,7 +4800,7 @@
   EXPECT_EQ(index->GetPromised(kDefaultUrl), nullptr);
 
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   EXPECT_TRUE(socket_data1.AllReadDataConsumed());
@@ -4821,7 +4831,7 @@
                              /*cert_verify_flags=*/0, url_, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream1 = request1.CreateStream();
+  std::unique_ptr<HttpStream> stream1 = CreateStream(&request1);
   EXPECT_TRUE(stream1.get());
   EXPECT_TRUE(HasActiveSession(host_port_pair_));
 
@@ -4831,7 +4841,7 @@
   EXPECT_EQ(OK, request2.Request(destination2, version_, privacy_mode_,
                                  /*cert_verify_flags=*/0, url_, "GET", net_log_,
                                  &net_error_details_, callback2.callback()));
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   QuicChromiumClientSession::Handle* session1 =
@@ -4977,7 +4987,7 @@
                              &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
 
-  std::unique_ptr<HttpStream> stream1 = request1.CreateStream();
+  std::unique_ptr<HttpStream> stream1 = CreateStream(&request1);
   EXPECT_TRUE(stream1.get());
   EXPECT_TRUE(HasActiveSession(origin1_));
 
@@ -4987,7 +4997,7 @@
   EXPECT_EQ(OK, request2.Request(destination, version_, privacy_mode_,
                                  /*cert_verify_flags=*/0, url2, "GET", net_log_,
                                  &net_error_details_, callback2.callback()));
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   QuicChromiumClientSession::Handle* session1 =
@@ -5048,7 +5058,7 @@
                              /*cert_verify_flags=*/0, url1, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
   EXPECT_EQ(OK, callback_.WaitForResult());
-  std::unique_ptr<HttpStream> stream1 = request1.CreateStream();
+  std::unique_ptr<HttpStream> stream1 = CreateStream(&request1);
   EXPECT_TRUE(stream1.get());
   EXPECT_TRUE(HasActiveSession(origin1_));
 
@@ -5059,7 +5069,7 @@
                              /*cert_verify_flags=*/0, url2, "GET", net_log_,
                              &net_error_details_, callback2.callback()));
   EXPECT_EQ(OK, callback2.WaitForResult());
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   // |request2| does not pool to the first session, because PrivacyMode does not
@@ -5131,7 +5141,7 @@
                              /*cert_verify_flags=*/0, url1, "GET", net_log_,
                              &net_error_details_, callback_.callback()));
   EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream1 = request1.CreateStream();
+  std::unique_ptr<HttpStream> stream1 = CreateStream(&request1);
   EXPECT_TRUE(stream1.get());
   EXPECT_TRUE(HasActiveSession(origin1_));
 
@@ -5142,7 +5152,7 @@
                              /*cert_verify_flags=*/0, url2, "GET", net_log_,
                              &net_error_details_, callback2.callback()));
   EXPECT_THAT(callback2.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream2 = request2.CreateStream();
+  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
   EXPECT_TRUE(stream2.get());
 
   // |request2| does not pool to the first session, because the certificate does
diff --git a/ppapi/api/dev/pp_print_settings_dev.idl b/ppapi/api/dev/pp_print_settings_dev.idl
index fafcc08..010d1b8c 100644
--- a/ppapi/api/dev/pp_print_settings_dev.idl
+++ b/ppapi/api/dev/pp_print_settings_dev.idl
@@ -12,7 +12,8 @@
   PP_PRINTORIENTATION_NORMAL         = 0,
   PP_PRINTORIENTATION_ROTATED_90_CW  = 1,
   PP_PRINTORIENTATION_ROTATED_180    = 2,
-  PP_PRINTORIENTATION_ROTATED_90_CCW = 3
+  PP_PRINTORIENTATION_ROTATED_90_CCW = 3,
+  PP_PRINTORIENTATION_ROTATED_LAST = PP_PRINTORIENTATION_ROTATED_90_CCW
 };
 
 [assert_size(4)]
@@ -27,7 +28,8 @@
 enum PP_PrintScalingOption_Dev {
   PP_PRINTSCALINGOPTION_NONE = 0,
   PP_PRINTSCALINGOPTION_FIT_TO_PRINTABLE_AREA = 1,
-  PP_PRINTSCALINGOPTION_SOURCE_SIZE = 2
+  PP_PRINTSCALINGOPTION_SOURCE_SIZE = 2,
+  PP_PRINTSCALINGOPTION_LAST = PP_PRINTSCALINGOPTION_SOURCE_SIZE
 };
 
 [assert_size(60)]
diff --git a/ppapi/api/dev/pp_video_dev.idl b/ppapi/api/dev/pp_video_dev.idl
index 1c70342..8138fdbe 100644
--- a/ppapi/api/dev/pp_video_dev.idl
+++ b/ppapi/api/dev/pp_video_dev.idl
@@ -19,6 +19,7 @@
 [assert_size(4)]
 enum PP_VideoDecoder_Profile {
   PP_VIDEODECODER_PROFILE_UNKNOWN = -1,
+  PP_VIDEODECODER_PROFILE_FIRST = PP_VIDEODECODER_PROFILE_UNKNOWN,
   PP_VIDEODECODER_H264PROFILE_NONE = 0,
   PP_VIDEODECODER_H264PROFILE_BASELINE = 1,
   PP_VIDEODECODER_H264PROFILE_MAIN = 2,
@@ -31,7 +32,8 @@
   PP_VIDEODECODER_H264PROFILE_SCALABLEHIGH = 9,
   PP_VIDEODECODER_H264PROFILE_STEREOHIGH = 10,
   PP_VIDEODECODER_H264PROFILE_MULTIVIEWHIGH = 11,
-  PP_VIDEODECODER_VP8PROFILE_ANY = 12
+  PP_VIDEODECODER_VP8PROFILE_ANY = 12,
+  PP_VIDEODECODER_PROFILE_LAST = PP_VIDEODECODER_VP8PROFILE_ANY
 };
 
 /**
@@ -106,6 +108,7 @@
    * An operation was attempted during an incompatible decoder state.
    */
   PP_VIDEODECODERERROR_ILLEGAL_STATE = 1,
+  PP_VIDEODECODERERROR_FIRST = PP_VIDEODECODERERROR_ILLEGAL_STATE,
 
   /**
    * Invalid argument was passed to an API method.
@@ -122,5 +125,6 @@
    * failures include GPU hardware failures, GPU driver failures, GPU library
    * failures, browser programming errors, and so on.
    */
-  PP_VIDEODECODERERROR_PLATFORM_FAILURE = 4
+  PP_VIDEODECODERERROR_PLATFORM_FAILURE = 4,
+  PP_VIDEODECODERERROR_LAST = PP_VIDEODECODERERROR_PLATFORM_FAILURE
 };
diff --git a/ppapi/api/dev/ppb_truetype_font_dev.idl b/ppapi/api/dev/ppb_truetype_font_dev.idl
index 8a3ff2b..962096f2 100644
--- a/ppapi/api/dev/ppb_truetype_font_dev.idl
+++ b/ppapi/api/dev/ppb_truetype_font_dev.idl
@@ -30,7 +30,8 @@
   PP_TRUETYPEFONTFAMILY_SANSSERIF = 1,
   PP_TRUETYPEFONTFAMILY_CURSIVE = 2,
   PP_TRUETYPEFONTFAMILY_FANTASY = 3,
-  PP_TRUETYPEFONTFAMILY_MONOSPACE = 4
+  PP_TRUETYPEFONTFAMILY_MONOSPACE = 4,
+  PP_TRUETYPEFONTFAMILY_LAST = PP_TRUETYPEFONTFAMILY_MONOSPACE
 };
 
 /**
@@ -39,7 +40,8 @@
 [assert_size(4)]
 enum PP_TrueTypeFontStyle_Dev {
   PP_TRUETYPEFONTSTYLE_NORMAL = 0,
-  PP_TRUETYPEFONTSTYLE_ITALIC = 1
+  PP_TRUETYPEFONTSTYLE_ITALIC = 1,
+  PP_TRUETYPEFONTSTYLE_LAST = PP_TRUETYPEFONTSTYLE_ITALIC
 };
 
 /**
@@ -48,6 +50,7 @@
 [assert_size(4)]
 enum PP_TrueTypeFontWeight_Dev {
   PP_TRUETYPEFONTWEIGHT_THIN = 100,
+  PP_TRUETYPEFONTWEIGHT_FIRST = PP_TRUETYPEFONTWEIGHT_THIN,
   PP_TRUETYPEFONTWEIGHT_ULTRALIGHT = 200,
   PP_TRUETYPEFONTWEIGHT_LIGHT = 300,
   PP_TRUETYPEFONTWEIGHT_NORMAL = 400,
@@ -55,7 +58,8 @@
   PP_TRUETYPEFONTWEIGHT_SEMIBOLD = 600,
   PP_TRUETYPEFONTWEIGHT_BOLD = 700,
   PP_TRUETYPEFONTWEIGHT_ULTRABOLD = 800,
-  PP_TRUETYPEFONTWEIGHT_HEAVY = 900
+  PP_TRUETYPEFONTWEIGHT_HEAVY = 900,
+  PP_TRUETYPEFONTWEIGHT_LAST = PP_TRUETYPEFONTWEIGHT_HEAVY
 };
 
 /**
@@ -71,7 +75,8 @@
   PP_TRUETYPEFONTWIDTH_SEMIEXPANDED = 5,
   PP_TRUETYPEFONTWIDTH_EXPANDED = 6,
   PP_TRUETYPEFONTWIDTH_EXTRAEXPANDED = 7,
-  PP_TRUETYPEFONTWIDTH_ULTRAEXPANDED = 8
+  PP_TRUETYPEFONTWIDTH_ULTRAEXPANDED = 8,
+  PP_TRUETYPEFONTWIDTH_LAST = PP_TRUETYPEFONTWIDTH_ULTRAEXPANDED
 };
 
 /**
@@ -97,7 +102,8 @@
   PP_TRUETYPEFONTCHARSET_RUSSIAN = 204,
   PP_TRUETYPEFONTCHARSET_THAI = 222,
   PP_TRUETYPEFONTCHARSET_EASTEUROPE = 238,
-  PP_TRUETYPEFONTCHARSET_OEM = 255
+  PP_TRUETYPEFONTCHARSET_OEM = 255,
+  PP_TRUETYPEFONTCHARSET_LAST = PP_TRUETYPEFONTCHARSET_OEM
 };
 
 /**
diff --git a/ppapi/api/ppb_audio_config.idl b/ppapi/api/ppb_audio_config.idl
index fd4cef4f..13aef2b 100644
--- a/ppapi/api/ppb_audio_config.idl
+++ b/ppapi/api/ppb_audio_config.idl
@@ -35,7 +35,8 @@
 enum PP_AudioSampleRate {
   PP_AUDIOSAMPLERATE_NONE = 0,
   PP_AUDIOSAMPLERATE_44100 = 44100,
-  PP_AUDIOSAMPLERATE_48000 = 48000
+  PP_AUDIOSAMPLERATE_48000 = 48000,
+  PP_AUDIOSAMPLERATE_LAST = PP_AUDIOSAMPLERATE_48000
 } ;
 
 
diff --git a/ppapi/api/ppb_image_data.idl b/ppapi/api/ppb_image_data.idl
index 8e1d09dc..db85c34 100644
--- a/ppapi/api/ppb_image_data.idl
+++ b/ppapi/api/ppb_image_data.idl
@@ -49,7 +49,8 @@
 [assert_size(4)]
 enum PP_ImageDataFormat {
   PP_IMAGEDATAFORMAT_BGRA_PREMUL,
-  PP_IMAGEDATAFORMAT_RGBA_PREMUL
+  PP_IMAGEDATAFORMAT_RGBA_PREMUL,
+  PP_IMAGEDATAFORMAT_LAST = PP_IMAGEDATAFORMAT_RGBA_PREMUL
 };
 
 /**
diff --git a/ppapi/api/ppb_input_event.idl b/ppapi/api/ppb_input_event.idl
index 43dd134..a1334ec 100644
--- a/ppapi/api/ppb_input_event.idl
+++ b/ppapi/api/ppb_input_event.idl
@@ -21,6 +21,7 @@
 [assert_size(4)]
 enum PP_InputEvent_Type {
   PP_INPUTEVENT_TYPE_UNDEFINED = -1,
+  PP_INPUTEVENT_TYPE_FIRST = PP_INPUTEVENT_TYPE_UNDEFINED,
 
   /**
    * Notification that a mouse button was pressed.
@@ -175,7 +176,8 @@
    *
    * Register for this event using the PP_INPUTEVENT_CLASS_TOUCH class.
    */
-  PP_INPUTEVENT_TYPE_TOUCHCANCEL = 18
+  PP_INPUTEVENT_TYPE_TOUCHCANCEL = 18,
+  PP_INPUTEVENT_TYPE_LAST = PP_INPUTEVENT_TYPE_TOUCHCANCEL
 };
 
 /**
@@ -212,9 +214,11 @@
 [assert_size(4)]
 enum PP_InputEvent_MouseButton {
   PP_INPUTEVENT_MOUSEBUTTON_NONE   = -1,
+  PP_INPUTEVENT_MOUSEBUTTON_FIRST  = PP_INPUTEVENT_MOUSEBUTTON_NONE,
   PP_INPUTEVENT_MOUSEBUTTON_LEFT   = 0,
   PP_INPUTEVENT_MOUSEBUTTON_MIDDLE = 1,
-  PP_INPUTEVENT_MOUSEBUTTON_RIGHT  = 2
+  PP_INPUTEVENT_MOUSEBUTTON_RIGHT  = 2,
+  PP_INPUTEVENT_MOUSEBUTTON_LAST   = PP_INPUTEVENT_MOUSEBUTTON_RIGHT
 };
 
 [assert_size(4)]
diff --git a/ppapi/api/ppb_text_input_controller.idl b/ppapi/api/ppb_text_input_controller.idl
index 63a9b19..36ee7d5 100644
--- a/ppapi/api/ppb_text_input_controller.idl
+++ b/ppapi/api/ppb_text_input_controller.idl
@@ -34,7 +34,8 @@
   PP_TEXTINPUT_TYPE_EMAIL = 4,
   PP_TEXTINPUT_TYPE_NUMBER = 5,
   PP_TEXTINPUT_TYPE_TELEPHONE = 6,
-  PP_TEXTINPUT_TYPE_URL = 7
+  PP_TEXTINPUT_TYPE_URL = 7,
+  PP_TEXTINPUT_TYPE_LAST = PP_TEXTINPUT_TYPE_URL
 };
 
 /**
diff --git a/ppapi/api/private/pp_private_font_charset.idl b/ppapi/api/private/pp_private_font_charset.idl
index 36e605a0..8e8c3e22 100644
--- a/ppapi/api/private/pp_private_font_charset.idl
+++ b/ppapi/api/private/pp_private_font_charset.idl
@@ -23,5 +23,6 @@
   PP_PRIVATEFONTCHARSET_RUSSIAN = 204,
   PP_PRIVATEFONTCHARSET_THAI = 222,
   PP_PRIVATEFONTCHARSET_EASTEUROPE = 238,
-  PP_PRIVATEFONTCHARSET_OEM = 255
+  PP_PRIVATEFONTCHARSET_OEM = 255,
+  PP_PRIVATEFONTCHARSET_LAST = PP_PRIVATEFONTCHARSET_OEM
 };
diff --git a/ppapi/api/private/ppb_flash.idl b/ppapi/api/private/ppb_flash.idl
index f16cbc9..1138bca 100644
--- a/ppapi/api/private/ppb_flash.idl
+++ b/ppapi/api/private/ppb_flash.idl
@@ -50,6 +50,7 @@
    * failed.
    */
   PP_FLASHSETTING_3DENABLED = 1,
+  PP_FLASHSETTING_FIRST = PP_FLASHSETTING_3DENABLED,
 
   /**
    * Specifies if the given instance is in private/incognito/off-the-record mode
@@ -92,7 +93,8 @@
    *
    * This should only be enabled if PP_FLASHSETTING_STAGE3DENABLED is true.
    */
-  PP_FLASHSETTING_STAGE3DBASELINEENABLED = 7
+  PP_FLASHSETTING_STAGE3DBASELINEENABLED = 7,
+  PP_FLASHSETTING_LAST = PP_FLASHSETTING_STAGE3DBASELINEENABLED
 };
 
 /**
diff --git a/ppapi/api/private/ppp_flash_browser_operations.idl b/ppapi/api/private/ppp_flash_browser_operations.idl
index d067fbf..eb1e9625 100644
--- a/ppapi/api/private/ppp_flash_browser_operations.idl
+++ b/ppapi/api/private/ppp_flash_browser_operations.idl
@@ -16,7 +16,8 @@
 [assert_size(4)]
 enum PP_Flash_BrowserOperations_SettingType {
   PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_CAMERAMIC = 0,
-  PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_PEERNETWORKING = 1
+  PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_PEERNETWORKING = 1,
+  PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_LAST = PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_PEERNETWORKING
 };
 
 [assert_size(4)]
@@ -25,7 +26,8 @@
   PP_FLASH_BROWSEROPERATIONS_PERMISSION_DEFAULT = 0,
   PP_FLASH_BROWSEROPERATIONS_PERMISSION_ALLOW = 1,
   PP_FLASH_BROWSEROPERATIONS_PERMISSION_BLOCK = 2,
-  PP_FLASH_BROWSEROPERATIONS_PERMISSION_ASK = 3
+  PP_FLASH_BROWSEROPERATIONS_PERMISSION_ASK = 3,
+  PP_FLASH_BROWSEROPERATIONS_PERMISSION_LAST = PP_FLASH_BROWSEROPERATIONS_PERMISSION_ASK
 };
 
 struct PP_Flash_BrowserOperations_SiteSetting {
diff --git a/ppapi/c/dev/pp_print_settings_dev.h b/ppapi/c/dev/pp_print_settings_dev.h
index 1253190..67c37b2 100644
--- a/ppapi/c/dev/pp_print_settings_dev.h
+++ b/ppapi/c/dev/pp_print_settings_dev.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From dev/pp_print_settings_dev.idl modified Fri Jan 16 13:30:14 2015. */
+/* From dev/pp_print_settings_dev.idl modified Wed Oct 25 09:45:07 2017. */
 
 #ifndef PPAPI_C_DEV_PP_PRINT_SETTINGS_DEV_H_
 #define PPAPI_C_DEV_PP_PRINT_SETTINGS_DEV_H_
@@ -29,7 +29,8 @@
   PP_PRINTORIENTATION_NORMAL = 0,
   PP_PRINTORIENTATION_ROTATED_90_CW = 1,
   PP_PRINTORIENTATION_ROTATED_180 = 2,
-  PP_PRINTORIENTATION_ROTATED_90_CCW = 3
+  PP_PRINTORIENTATION_ROTATED_90_CCW = 3,
+  PP_PRINTORIENTATION_ROTATED_LAST = PP_PRINTORIENTATION_ROTATED_90_CCW
 } PP_PrintOrientation_Dev;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_PrintOrientation_Dev, 4);
 
@@ -44,7 +45,8 @@
 typedef enum {
   PP_PRINTSCALINGOPTION_NONE = 0,
   PP_PRINTSCALINGOPTION_FIT_TO_PRINTABLE_AREA = 1,
-  PP_PRINTSCALINGOPTION_SOURCE_SIZE = 2
+  PP_PRINTSCALINGOPTION_SOURCE_SIZE = 2,
+  PP_PRINTSCALINGOPTION_LAST = PP_PRINTSCALINGOPTION_SOURCE_SIZE
 } PP_PrintScalingOption_Dev;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_PrintScalingOption_Dev, 4);
 /**
diff --git a/ppapi/c/dev/pp_video_dev.h b/ppapi/c/dev/pp_video_dev.h
index 75ee21a..d90c47b1d 100644
--- a/ppapi/c/dev/pp_video_dev.h
+++ b/ppapi/c/dev/pp_video_dev.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From dev/pp_video_dev.idl modified Tue Apr 30 14:58:38 2013. */
+/* From dev/pp_video_dev.idl modified Tue Oct 24 13:14:42 2017. */
 
 #ifndef PPAPI_C_DEV_PP_VIDEO_DEV_H_
 #define PPAPI_C_DEV_PP_VIDEO_DEV_H_
@@ -33,6 +33,7 @@
  */
 typedef enum {
   PP_VIDEODECODER_PROFILE_UNKNOWN = -1,
+  PP_VIDEODECODER_PROFILE_FIRST = PP_VIDEODECODER_PROFILE_UNKNOWN,
   PP_VIDEODECODER_H264PROFILE_NONE = 0,
   PP_VIDEODECODER_H264PROFILE_BASELINE = 1,
   PP_VIDEODECODER_H264PROFILE_MAIN = 2,
@@ -45,7 +46,8 @@
   PP_VIDEODECODER_H264PROFILE_SCALABLEHIGH = 9,
   PP_VIDEODECODER_H264PROFILE_STEREOHIGH = 10,
   PP_VIDEODECODER_H264PROFILE_MULTIVIEWHIGH = 11,
-  PP_VIDEODECODER_VP8PROFILE_ANY = 12
+  PP_VIDEODECODER_VP8PROFILE_ANY = 12,
+  PP_VIDEODECODER_PROFILE_LAST = PP_VIDEODECODER_VP8PROFILE_ANY
 } PP_VideoDecoder_Profile;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_VideoDecoder_Profile, 4);
 /**
@@ -129,6 +131,7 @@
    * An operation was attempted during an incompatible decoder state.
    */
   PP_VIDEODECODERERROR_ILLEGAL_STATE = 1,
+  PP_VIDEODECODERERROR_FIRST = PP_VIDEODECODERERROR_ILLEGAL_STATE,
   /**
    * Invalid argument was passed to an API method.
    */
@@ -142,7 +145,8 @@
    * failures include GPU hardware failures, GPU driver failures, GPU library
    * failures, browser programming errors, and so on.
    */
-  PP_VIDEODECODERERROR_PLATFORM_FAILURE = 4
+  PP_VIDEODECODERERROR_PLATFORM_FAILURE = 4,
+  PP_VIDEODECODERERROR_LAST = PP_VIDEODECODERERROR_PLATFORM_FAILURE
 } PP_VideoDecodeError_Dev;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_VideoDecodeError_Dev, 4);
 /**
diff --git a/ppapi/c/dev/ppb_truetype_font_dev.h b/ppapi/c/dev/ppb_truetype_font_dev.h
index 1511ca4..ad50be5 100644
--- a/ppapi/c/dev/ppb_truetype_font_dev.h
+++ b/ppapi/c/dev/ppb_truetype_font_dev.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From dev/ppb_truetype_font_dev.idl modified Tue Oct 15 05:52:52 2013. */
+/* From dev/ppb_truetype_font_dev.idl modified Tue Oct 24 12:47:58 2017. */
 
 #ifndef PPAPI_C_DEV_PPB_TRUETYPE_FONT_DEV_H_
 #define PPAPI_C_DEV_PPB_TRUETYPE_FONT_DEV_H_
@@ -46,7 +46,8 @@
   PP_TRUETYPEFONTFAMILY_SANSSERIF = 1,
   PP_TRUETYPEFONTFAMILY_CURSIVE = 2,
   PP_TRUETYPEFONTFAMILY_FANTASY = 3,
-  PP_TRUETYPEFONTFAMILY_MONOSPACE = 4
+  PP_TRUETYPEFONTFAMILY_MONOSPACE = 4,
+  PP_TRUETYPEFONTFAMILY_LAST = PP_TRUETYPEFONTFAMILY_MONOSPACE
 } PP_TrueTypeFontFamily_Dev;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_TrueTypeFontFamily_Dev, 4);
 
@@ -55,7 +56,8 @@
  */
 typedef enum {
   PP_TRUETYPEFONTSTYLE_NORMAL = 0,
-  PP_TRUETYPEFONTSTYLE_ITALIC = 1
+  PP_TRUETYPEFONTSTYLE_ITALIC = 1,
+  PP_TRUETYPEFONTSTYLE_LAST = PP_TRUETYPEFONTSTYLE_ITALIC
 } PP_TrueTypeFontStyle_Dev;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_TrueTypeFontStyle_Dev, 4);
 
@@ -64,6 +66,7 @@
  */
 typedef enum {
   PP_TRUETYPEFONTWEIGHT_THIN = 100,
+  PP_TRUETYPEFONTWEIGHT_FIRST = PP_TRUETYPEFONTWEIGHT_THIN,
   PP_TRUETYPEFONTWEIGHT_ULTRALIGHT = 200,
   PP_TRUETYPEFONTWEIGHT_LIGHT = 300,
   PP_TRUETYPEFONTWEIGHT_NORMAL = 400,
@@ -71,7 +74,8 @@
   PP_TRUETYPEFONTWEIGHT_SEMIBOLD = 600,
   PP_TRUETYPEFONTWEIGHT_BOLD = 700,
   PP_TRUETYPEFONTWEIGHT_ULTRABOLD = 800,
-  PP_TRUETYPEFONTWEIGHT_HEAVY = 900
+  PP_TRUETYPEFONTWEIGHT_HEAVY = 900,
+  PP_TRUETYPEFONTWEIGHT_LAST = PP_TRUETYPEFONTWEIGHT_HEAVY
 } PP_TrueTypeFontWeight_Dev;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_TrueTypeFontWeight_Dev, 4);
 
@@ -87,7 +91,8 @@
   PP_TRUETYPEFONTWIDTH_SEMIEXPANDED = 5,
   PP_TRUETYPEFONTWIDTH_EXPANDED = 6,
   PP_TRUETYPEFONTWIDTH_EXTRAEXPANDED = 7,
-  PP_TRUETYPEFONTWIDTH_ULTRAEXPANDED = 8
+  PP_TRUETYPEFONTWIDTH_ULTRAEXPANDED = 8,
+  PP_TRUETYPEFONTWIDTH_LAST = PP_TRUETYPEFONTWIDTH_ULTRAEXPANDED
 } PP_TrueTypeFontWidth_Dev;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_TrueTypeFontWidth_Dev, 4);
 
@@ -113,7 +118,8 @@
   PP_TRUETYPEFONTCHARSET_RUSSIAN = 204,
   PP_TRUETYPEFONTCHARSET_THAI = 222,
   PP_TRUETYPEFONTCHARSET_EASTEUROPE = 238,
-  PP_TRUETYPEFONTCHARSET_OEM = 255
+  PP_TRUETYPEFONTCHARSET_OEM = 255,
+  PP_TRUETYPEFONTCHARSET_LAST = PP_TRUETYPEFONTCHARSET_OEM
 } PP_TrueTypeFontCharset_Dev;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_TrueTypeFontCharset_Dev, 4);
 /**
diff --git a/ppapi/c/ppb_audio_config.h b/ppapi/c/ppb_audio_config.h
index 87f861b..29d33e3 100644
--- a/ppapi/c/ppb_audio_config.h
+++ b/ppapi/c/ppb_audio_config.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From ppb_audio_config.idl modified Fri Jan 24 16:19:35 2014. */
+/* From ppb_audio_config.idl modified Mon Oct 23 15:24:19 2017. */
 
 #ifndef PPAPI_C_PPB_AUDIO_CONFIG_H_
 #define PPAPI_C_PPB_AUDIO_CONFIG_H_
@@ -49,7 +49,8 @@
 typedef enum {
   PP_AUDIOSAMPLERATE_NONE = 0,
   PP_AUDIOSAMPLERATE_44100 = 44100,
-  PP_AUDIOSAMPLERATE_48000 = 48000
+  PP_AUDIOSAMPLERATE_48000 = 48000,
+  PP_AUDIOSAMPLERATE_LAST = PP_AUDIOSAMPLERATE_48000
 } PP_AudioSampleRate;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_AudioSampleRate, 4);
 /**
diff --git a/ppapi/c/ppb_image_data.h b/ppapi/c/ppb_image_data.h
index fb091d7b..75894dc 100644
--- a/ppapi/c/ppb_image_data.h
+++ b/ppapi/c/ppb_image_data.h
@@ -63,7 +63,8 @@
  */
 typedef enum {
   PP_IMAGEDATAFORMAT_BGRA_PREMUL,
-  PP_IMAGEDATAFORMAT_RGBA_PREMUL
+  PP_IMAGEDATAFORMAT_RGBA_PREMUL,
+  PP_IMAGEDATAFORMAT_LAST = PP_IMAGEDATAFORMAT_RGBA_PREMUL
 } PP_ImageDataFormat;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_ImageDataFormat, 4);
 /**
diff --git a/ppapi/c/ppb_input_event.h b/ppapi/c/ppb_input_event.h
index bcf23c51..0801b42 100644
--- a/ppapi/c/ppb_input_event.h
+++ b/ppapi/c/ppb_input_event.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From ppb_input_event.idl modified Wed May 24 10:14:53 2017. */
+/* From ppb_input_event.idl modified Tue Oct 24 12:49:54 2017. */
 
 #ifndef PPAPI_C_PPB_INPUT_EVENT_H_
 #define PPAPI_C_PPB_INPUT_EVENT_H_
@@ -55,6 +55,7 @@
  */
 typedef enum {
   PP_INPUTEVENT_TYPE_UNDEFINED = -1,
+  PP_INPUTEVENT_TYPE_FIRST = PP_INPUTEVENT_TYPE_UNDEFINED,
   /**
    * Notification that a mouse button was pressed.
    *
@@ -190,7 +191,8 @@
    *
    * Register for this event using the PP_INPUTEVENT_CLASS_TOUCH class.
    */
-  PP_INPUTEVENT_TYPE_TOUCHCANCEL = 18
+  PP_INPUTEVENT_TYPE_TOUCHCANCEL = 18,
+  PP_INPUTEVENT_TYPE_LAST = PP_INPUTEVENT_TYPE_TOUCHCANCEL
 } PP_InputEvent_Type;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_InputEvent_Type, 4);
 
@@ -225,9 +227,11 @@
  */
 typedef enum {
   PP_INPUTEVENT_MOUSEBUTTON_NONE = -1,
+  PP_INPUTEVENT_MOUSEBUTTON_FIRST = PP_INPUTEVENT_MOUSEBUTTON_NONE,
   PP_INPUTEVENT_MOUSEBUTTON_LEFT = 0,
   PP_INPUTEVENT_MOUSEBUTTON_MIDDLE = 1,
-  PP_INPUTEVENT_MOUSEBUTTON_RIGHT = 2
+  PP_INPUTEVENT_MOUSEBUTTON_RIGHT = 2,
+  PP_INPUTEVENT_MOUSEBUTTON_LAST = PP_INPUTEVENT_MOUSEBUTTON_RIGHT
 } PP_InputEvent_MouseButton;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_InputEvent_MouseButton, 4);
 
diff --git a/ppapi/c/ppb_text_input_controller.h b/ppapi/c/ppb_text_input_controller.h
index 43b88ac..7c8d219b 100644
--- a/ppapi/c/ppb_text_input_controller.h
+++ b/ppapi/c/ppb_text_input_controller.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From ppb_text_input_controller.idl modified Thu Aug  1 09:30:48 2013. */
+/* From ppb_text_input_controller.idl modified Mon Oct 23 15:30:39 2017. */
 
 #ifndef PPAPI_C_PPB_TEXT_INPUT_CONTROLLER_H_
 #define PPAPI_C_PPB_TEXT_INPUT_CONTROLLER_H_
@@ -52,7 +52,8 @@
   PP_TEXTINPUT_TYPE_EMAIL = 4,
   PP_TEXTINPUT_TYPE_NUMBER = 5,
   PP_TEXTINPUT_TYPE_TELEPHONE = 6,
-  PP_TEXTINPUT_TYPE_URL = 7
+  PP_TEXTINPUT_TYPE_URL = 7,
+  PP_TEXTINPUT_TYPE_LAST = PP_TEXTINPUT_TYPE_URL
 } PP_TextInput_Type;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_TextInput_Type, 4);
 /**
diff --git a/ppapi/c/private/pp_private_font_charset.h b/ppapi/c/private/pp_private_font_charset.h
index 300be93..28d6f6e 100644
--- a/ppapi/c/private/pp_private_font_charset.h
+++ b/ppapi/c/private/pp_private_font_charset.h
@@ -40,7 +40,8 @@
   PP_PRIVATEFONTCHARSET_RUSSIAN = 204,
   PP_PRIVATEFONTCHARSET_THAI = 222,
   PP_PRIVATEFONTCHARSET_EASTEUROPE = 238,
-  PP_PRIVATEFONTCHARSET_OEM = 255
+  PP_PRIVATEFONTCHARSET_OEM = 255,
+  PP_PRIVATEFONTCHARSET_LAST = PP_PRIVATEFONTCHARSET_OEM
 } PP_PrivateFontCharset;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_PrivateFontCharset, 4);
 /**
diff --git a/ppapi/c/private/ppb_flash.h b/ppapi/c/private/ppb_flash.h
index c1c4c93..f0fc8ed 100644
--- a/ppapi/c/private/ppb_flash.h
+++ b/ppapi/c/private/ppb_flash.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From private/ppb_flash.idl modified Thu Apr 18 15:06:12 2013. */
+/* From private/ppb_flash.idl modified Tue Oct 24 12:52:30 2017. */
 
 #ifndef PPAPI_C_PRIVATE_PPB_FLASH_H_
 #define PPAPI_C_PRIVATE_PPB_FLASH_H_
@@ -71,6 +71,7 @@
    * failed.
    */
   PP_FLASHSETTING_3DENABLED = 1,
+  PP_FLASHSETTING_FIRST = PP_FLASHSETTING_3DENABLED,
   /**
    * Specifies if the given instance is in private/incognito/off-the-record mode
    * (returns true) or "regular" mode (returns false). Returns an undefined
@@ -107,7 +108,8 @@
    *
    * This should only be enabled if PP_FLASHSETTING_STAGE3DENABLED is true.
    */
-  PP_FLASHSETTING_STAGE3DBASELINEENABLED = 7
+  PP_FLASHSETTING_STAGE3DBASELINEENABLED = 7,
+  PP_FLASHSETTING_LAST = PP_FLASHSETTING_STAGE3DBASELINEENABLED
 } PP_FlashSetting;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_FlashSetting, 4);
 
diff --git a/ppapi/c/private/ppp_flash_browser_operations.h b/ppapi/c/private/ppp_flash_browser_operations.h
index 2f8803b5..9bfc838 100644
--- a/ppapi/c/private/ppp_flash_browser_operations.h
+++ b/ppapi/c/private/ppp_flash_browser_operations.h
@@ -4,7 +4,7 @@
  */
 
 /* From private/ppp_flash_browser_operations.idl,
- *   modified Fri Aug 22 11:10:06 2014.
+ *   modified Wed Oct 25 09:44:49 2017.
  */
 
 #ifndef PPAPI_C_PRIVATE_PPP_FLASH_BROWSER_OPERATIONS_H_
@@ -35,7 +35,9 @@
  */
 typedef enum {
   PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_CAMERAMIC = 0,
-  PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_PEERNETWORKING = 1
+  PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_PEERNETWORKING = 1,
+  PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_LAST =
+    PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_PEERNETWORKING
 } PP_Flash_BrowserOperations_SettingType;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_Flash_BrowserOperations_SettingType, 4);
 
@@ -44,7 +46,9 @@
   PP_FLASH_BROWSEROPERATIONS_PERMISSION_DEFAULT = 0,
   PP_FLASH_BROWSEROPERATIONS_PERMISSION_ALLOW = 1,
   PP_FLASH_BROWSEROPERATIONS_PERMISSION_BLOCK = 2,
-  PP_FLASH_BROWSEROPERATIONS_PERMISSION_ASK = 3
+  PP_FLASH_BROWSEROPERATIONS_PERMISSION_ASK = 3,
+  PP_FLASH_BROWSEROPERATIONS_PERMISSION_LAST =
+    PP_FLASH_BROWSEROPERATIONS_PERMISSION_ASK
 } PP_Flash_BrowserOperations_Permission;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_Flash_BrowserOperations_Permission, 4);
 /**
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index 263c383b..84b3843 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -93,7 +93,7 @@
 
 IPC_ENUM_TRAITS_MAX_VALUE(ppapi::TCPSocketVersion,
                           ppapi::TCP_SOCKET_VERSION_1_1_OR_ABOVE)
-IPC_ENUM_TRAITS(PP_AudioSampleRate)
+IPC_ENUM_TRAITS_MAX_VALUE(PP_AudioSampleRate, PP_AUDIOSAMPLERATE_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_BlendMode, PP_BLENDMODE_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_CdmExceptionCode, PP_CDMEXCEPTIONCODE_MAX)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_CdmKeyStatus, PP_CDMKEYSTATUS_MAX)
@@ -102,38 +102,54 @@
 IPC_ENUM_TRAITS_MAX_VALUE(PP_DecryptorStreamType, PP_DECRYPTORSTREAMTYPE_MAX)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_FileSystemType, PP_FILESYSTEMTYPE_ISOLATED)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_FileType, PP_FILETYPE_OTHER)
-IPC_ENUM_TRAITS(PP_Flash_BrowserOperations_Permission)
-IPC_ENUM_TRAITS(PP_Flash_BrowserOperations_SettingType)
-IPC_ENUM_TRAITS(PP_FlashSetting)
+IPC_ENUM_TRAITS_MAX_VALUE(PP_Flash_BrowserOperations_Permission,
+                          PP_FLASH_BROWSEROPERATIONS_PERMISSION_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(PP_Flash_BrowserOperations_SettingType,
+                          PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_LAST)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(PP_FlashSetting,
+                              PP_FLASHSETTING_FIRST,
+                              PP_FLASHSETTING_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_HdcpVersion, PP_HDCPVERSION_MAX)
-IPC_ENUM_TRAITS(PP_ImageDataFormat)
+IPC_ENUM_TRAITS_MAX_VALUE(PP_ImageDataFormat, PP_IMAGEDATAFORMAT_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_InitDataType, PP_INITDATATYPE_MAX)
-IPC_ENUM_TRAITS(PP_InputEvent_MouseButton)
-IPC_ENUM_TRAITS(PP_InputEvent_Type)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(PP_InputEvent_MouseButton,
+                              PP_INPUTEVENT_MOUSEBUTTON_FIRST,
+                              PP_INPUTEVENT_MOUSEBUTTON_LAST)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(PP_InputEvent_Type,
+                              PP_INPUTEVENT_TYPE_FIRST,
+                              PP_INPUTEVENT_TYPE_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_IsolatedFileSystemType_Private,
                           PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_NetAddressFamily_Private,
                           PP_NETADDRESSFAMILY_PRIVATE_IPV6)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_NetworkList_State, PP_NETWORKLIST_STATE_UP)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_NetworkList_Type, PP_NETWORKLIST_TYPE_CELLULAR)
-IPC_ENUM_TRAITS(PP_PrintOrientation_Dev)
+IPC_ENUM_TRAITS_MAX_VALUE(PP_PrintOrientation_Dev,
+                          PP_PRINTORIENTATION_ROTATED_LAST)
 IPC_ENUM_TRAITS(PP_PrintOutputFormat_Dev)
-IPC_ENUM_TRAITS(PP_PrintScalingOption_Dev)
+IPC_ENUM_TRAITS_MAX_VALUE(PP_PrintScalingOption_Dev, PP_PRINTSCALINGOPTION_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_PrivateDuplexMode_Dev, PP_PRIVATEDUPLEXMODE_LAST)
-IPC_ENUM_TRAITS(PP_PrivateFontCharset)
+IPC_ENUM_TRAITS_MAX_VALUE(PP_PrivateFontCharset, PP_PRIVATEFONTCHARSET_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_SessionType, PP_SESSIONTYPE_MAX)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_TCPSocket_Option,
                           PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE)
-IPC_ENUM_TRAITS(PP_TextInput_Type)
-IPC_ENUM_TRAITS(PP_TrueTypeFontFamily_Dev)
-IPC_ENUM_TRAITS(PP_TrueTypeFontStyle_Dev)
-IPC_ENUM_TRAITS(PP_TrueTypeFontWeight_Dev)
-IPC_ENUM_TRAITS(PP_TrueTypeFontWidth_Dev)
-IPC_ENUM_TRAITS(PP_TrueTypeFontCharset_Dev)
+IPC_ENUM_TRAITS_MAX_VALUE(PP_TextInput_Type, PP_TEXTINPUT_TYPE_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(PP_TrueTypeFontFamily_Dev, PP_TRUETYPEFONTFAMILY_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(PP_TrueTypeFontStyle_Dev, PP_TRUETYPEFONTSTYLE_LAST)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(PP_TrueTypeFontWeight_Dev,
+                              PP_TRUETYPEFONTWEIGHT_FIRST,
+                              PP_TRUETYPEFONTWEIGHT_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(PP_TrueTypeFontWidth_Dev, PP_TRUETYPEFONTWIDTH_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(PP_TrueTypeFontCharset_Dev,
+                          PP_TRUETYPEFONTCHARSET_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_UDPSocket_Option,
                           PP_UDPSOCKET_OPTION_MULTICAST_TTL)
-IPC_ENUM_TRAITS(PP_VideoDecodeError_Dev)
-IPC_ENUM_TRAITS(PP_VideoDecoder_Profile)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(PP_VideoDecodeError_Dev,
+                              PP_VIDEODECODERERROR_FIRST,
+                              PP_VIDEODECODERERROR_LAST)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(PP_VideoDecoder_Profile,
+                              PP_VIDEODECODER_PROFILE_FIRST,
+                              PP_VIDEODECODER_PROFILE_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_VideoFrame_Format, PP_VIDEOFRAME_FORMAT_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_HardwareAcceleration, PP_HARDWAREACCELERATION_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(PP_AudioProfile, PP_AUDIOPROFILE_MAX)
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 974d3da..498c19a 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -2274,16 +2274,13 @@
     "isolated_scripts": [
       {
         "args": [
-          "system_health.memory_mobile",
+          "heap_profiling.mobile.disabled",
           "-v",
-          "--upload-results",
           "--output-format=chartjson",
-          "--browser=android-chromium",
-          "--story-filter=load:search:google",
-          "--extra-browser-args=\"--enable-heap-profiling\""
+          "--browser=android-chromium"
         ],
         "isolate_name": "telemetry_perf_tests",
-        "name": "system_health.memory_mobile",
+        "name": "heap_profiling.mobile.disabled",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2292,7 +2289,56 @@
               "device_type": "hammerhead"
             }
           ],
-          "hard_timeout": 960
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "heap_profiling.mobile.native",
+          "-v",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "heap_profiling.mobile.native",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "KTU84P",
+              "device_type": "hammerhead"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
+        }
+      },
+      {
+        "args": [
+          "heap_profiling.mobile.pseudo",
+          "-v",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "heap_profiling.mobile.pseudo",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "KTU84P",
+              "device_type": "hammerhead"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600
         }
       }
     ]
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 2f8ed19..9701a5a 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -3457,6 +3457,12 @@
       "ui_base_unittests"
     ]
   },
+  "Fuchsia ARM64 Cast Audio": {
+    "additional_compile_targets": [
+      "cast_shell",
+      "cast_test_lists"
+    ]
+  },
   "Fuchsia x64": {
     "additional_compile_targets": [
       "base_unittests",
@@ -3525,6 +3531,12 @@
       }
     ]
   },
+  "Fuchsia x64 Cast Audio": {
+    "additional_compile_targets": [
+      "cast_shell",
+      "cast_test_lists"
+    ]
+  },
   "Linux Builder": {
     "additional_compile_targets": [
       "all"
diff --git a/testing/buildbot/filters/mojo.fyi.mash.browser_tests.filter b/testing/buildbot/filters/mojo.fyi.mash.browser_tests.filter
index 41a6277..02ff14f 100644
--- a/testing/buildbot/filters/mojo.fyi.mash.browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.mash.browser_tests.filter
@@ -43,6 +43,34 @@
 SystemTrayClientTest.*
 VolumeControllerTest.*
 
+# Tests from //chrome/browser/ui/views.
+AutofillPopupBaseViewTest.*
+AutofillPopupViewViewsTest.*
+BookmarkBubbleSignInDelegateTest.*
+BrowserTestParam.*
+BrowserViewFocusTest.*
+BrowserViewTest.*
+CertificateSelectorTest.*
+CollectedCookiesViewsTest.*
+ConstrainedWindowViewTest.*
+ExtensionUninstallDialogViewBrowserTest.*
+ImeWindowBrowserTest.*
+KeyboardAccessTest.*
+LocationIconViewBrowserTest.*
+MediaRouterUIBrowserTest.*
+NavigationAccessibilityTest.*
+OmniboxViewViewsTest.*
+SSLClientCertificateSelectorTest.*
+StarViewTest.*
+TabScrubberTest.*
+TaskManagerViewTest.*
+TranslateBubbleViewBrowserTest.*
+TranslateLanguageBrowserTest.*
+TryChromeDialogBrowserTest.*
+TryChromeDialogBrowserTestBase.*
+WebDialogBrowserTest.*
+WebNotificationTrayTest.*
+
 # Tests from elsewhere.
 BrowserDialogTest.*
 CastSessionBrowserTest.*
diff --git a/testing/buildbot/filters/mojo.fyi.mus.content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.mus.content_browsertests.filter
index 07f7ade..87d4a98 100644
--- a/testing/buildbot/filters/mojo.fyi.mus.content_browsertests.filter
+++ b/testing/buildbot/filters/mojo.fyi.mus.content_browsertests.filter
@@ -108,3 +108,7 @@
 -TouchSelectionForCrossProcessFramesTests/TouchSelectionControllerClientAuraSiteIsolationTest.BasicSelectionIsolatedScrollMainframe/1
 -WheelScrollLatchingBrowserTest.WheelEventTarget
 -WheelScrollLatchingDisabledBrowserTest.WheelEventTarget
+
+# TODO(sky): these two fail on the bot, figure out why.
+-SitePerProcessBrowserTest.ScrollElementIntoView
+-FindRequestManagerTests/FindRequestManagerTest.NavigateFrame/1
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index faed6fd7..1a81fd0 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -1,253 +1,123 @@
 # These tests currently fail when run with --enable-features=NetworkService
 # See https://crbug.com/769401
 
-# Crashed tests that haven't been categorized.
--DicePrepareMigrationBrowserTest.Signin
--DicePrepareMigrationBrowserTest.Signout
--ExtensionsA11yTestFixture.BASIC_EXTENSIONS_region
--WebViewTests/WebViewSurfaceSynchronizationTest.AutosizeBeforeNavigation/0
--WebViewTests/WebViewSurfaceSynchronizationTest.AutosizeBeforeNavigation/1
--WebViewTests/WebViewSurfaceSynchronizationTest.AutosizeRemoveAttributes/0
--WebViewTests/WebViewSurfaceSynchronizationTest.AutosizeRemoveAttributes/1
--WebViewTests/WebViewSurfaceSynchronizationTest.AutoSizeHeight/0
--WebViewTests/WebViewSurfaceSynchronizationTest.AutoSizeHeight/1
--WebViewTests/WebViewSurfaceSynchronizationTest.AutoSize/1
--WebViewTests/WebViewSurfaceSynchronizationTest.AutoSize/0
-
-# Timed out tests that haven't been categorized.
+# Uncategorized timeouts or test failures.
 -ActivityLogApiTest.TriggerEvent
--AllUrlsApiTest.RegularExtensions
--AllUrlsApiTest.WhitelistedExtension
--AppApiTest.ClientRedirectToAppFromExtension
--AppApiTest.ServerRedirectToAppFromExtension
--AppBackgroundPageApiTest.Basic
--AppBackgroundPageApiTest.NoJsBackgroundPage
--AppBackgroundPageApiTest.NoJsManifestBackgroundPage
--AppBackgroundPageApiTest.OpenThenClose
--AppBackgroundPageApiTest.OpenTwoBackgroundPages
--AppBackgroundPageApiTest.OpenTwoPagesWithManifest
+-AdsPageLoadMetricsObserverBrowserTest.DocOverwritesNavigation
+-AdsPageLoadMetricsObserverBrowserTest.SubresourceFilter
 -AppBackgroundPageNaClTest.BackgroundKeepaliveActive
--AppEventPageTest.OnSuspendNoApiUse
--AppEventPageTest.OnSuspendUseStorageApi
--AppViewTests/AppViewTest.KillGuestWithInvalidInstanceID/0
--AppViewTests/AppViewTest.KillGuestWithInvalidInstanceID/1
--AppViewTests/AppViewTest.TestAppViewEmbedSelfShouldFail/0
--AppViewTests/AppViewTest.TestAppViewEmbedSelfShouldFail/1
--AppViewTests/AppViewTest.TestAppViewGoodDataShouldSucceed/0
--AppViewTests/AppViewTest.TestAppViewGoodDataShouldSucceed/1
--AppViewTests/AppViewTest.TestAppViewMultipleConnects/0
--AppViewTests/AppViewTest.TestAppViewMultipleConnects/1
--AppViewTests/AppViewTest.TestAppViewRefusedDataShouldFail/0
--AppViewTests/AppViewTest.TestAppViewRefusedDataShouldFail/1
--AppViewTests/AppViewTest.TestAppViewWithUndefinedDataShouldSucceed/0
--AppViewTests/AppViewTest.TestAppViewWithUndefinedDataShouldSucceed/1
--AppWindowAPITest.TestCloseEvent
--AppWindowAPITest.TestCreate
--AppWindowAPITest.TestFrameColors
--AppWindowAPITest.TestSingleton
--AppWindowAPITest.TestVisibleOnAllWorkspaces
--AppWindowApiTest.AlphaEnabledHasPermissions
--AppWindowApiTest.AlphaEnabledInStable
--AppWindowApiTest.AlphaEnabledNoPermissions
--AppWindowApiTest.AlphaEnabledWrongFrameType
--AppWindowApiTest.AlwaysOnTopNoPermissions
--AppWindowApiTest.AlwaysOnTopWithOldPermissions
--AppWindowApiTest.AlwaysOnTopWithPermissions
--AppWindowApiTest.Get
--AppWindowApiTest.SetShapeHasPerm
--AppWindowApiTest.SetShapeNoPerm
--AppWindowApiTest.VisibleOnAllWorkspacesInStable
--AppWindowBrowserTest.FrameInsetsForColoredFrame
--AppWindowBrowserTest.FrameInsetsForNoFrame
--AppWindowRestrictedApisBrowserTest.DocumentApis
--AppWindowRestrictedApisBrowserTest.UnloadEvents
--AutofillPrivateApiTest.GetAddressComponents
--AutofillPrivateApiTest.ValidatePhoneNumbers
--AutomationApiTest.Actions
--AutomationApiTest.BoundsForRange
--AutomationApiTest.CloseTab
--AutomationApiTest.DesktopNotRequested
--AutomationApiTest.DocumentSelection
--AutomationApiTest.Events
--AutomationApiTest.Find
--AutomationApiTest.GetTreeByTabId
--AutomationApiTest.HitTest
--AutomationApiTest.ImageData
--AutomationApiTest.LineStartOffsets
--AutomationApiTest.Location
--AutomationApiTest.Location2
--AutomationApiTest.QuerySelector
--AutomationApiTest.SanityCheck
--AutomationApiTest.TabsAutomationBooleanActions
--AutomationApiTest.TabsAutomationBooleanPermissions
--AutomationApiTest.TabsAutomationHostsPermissions
--AutomationApiTest.TestRendererAccessibilityEnabled
--AutomationApiTest.TreeChange
--AutomationApiTest.TreeChangeIndirect
 -BackgroundXhrTest.HttpAuth
 -BackgroundXhrTest.TlsClientAuth
--BluetoothApiTest.DeviceEvents
--BluetoothApiTest.DeviceInfo
--BluetoothApiTest.DiscoveryCallback
--BluetoothApiTest.DiscoveryInProgress
--BluetoothApiTest.GetDevice
--BluetoothApiTest.GetDevices
--BluetoothApiTest.OnAdapterStateChanged
--BluetoothLowEnergyApiTest.AddressChange
--BluetoothLowEnergyApiTest.CharacteristicProperties
--BluetoothLowEnergyApiTest.CharacteristicValueChanged
--BluetoothLowEnergyApiTest.ConnectInProgress
--BluetoothLowEnergyApiTest.DescriptorValueChanged
--BluetoothLowEnergyApiTest.GattConnection
--BluetoothLowEnergyApiTest.GetCharacteristic
--BluetoothLowEnergyApiTest.GetCharacteristics
--BluetoothLowEnergyApiTest.GetDescriptor
--BluetoothLowEnergyApiTest.GetDescriptors
--BluetoothLowEnergyApiTest.GetIncludedServices
--BluetoothLowEnergyApiTest.GetRemovedCharacteristic
--BluetoothLowEnergyApiTest.GetRemovedDescriptor
--BluetoothLowEnergyApiTest.GetRemovedService
--BluetoothLowEnergyApiTest.GetService
--BluetoothLowEnergyApiTest.GetServices
--BluetoothLowEnergyApiTest.PermissionDenied
--BluetoothLowEnergyApiTest.ReadCharacteristicValue
--BluetoothLowEnergyApiTest.ReadDescriptorValue
--BluetoothLowEnergyApiTest.ReconnectAfterDisconnected
--BluetoothLowEnergyApiTest.ServiceEvents
--BluetoothLowEnergyApiTest.StartStopNotifications
--BluetoothLowEnergyApiTest.UuidPermissionEvents
--BluetoothLowEnergyApiTest.UuidPermissionMethods
--BluetoothLowEnergyApiTest.WriteCharacteristicValue
--BluetoothLowEnergyApiTest.WriteDescriptorValue
--BluetoothPrivateApiTest.CancelPairing
--BluetoothPrivateApiTest.Connect
--BluetoothPrivateApiTest.DisconnectAll
--BluetoothPrivateApiTest.DiscoveryFilter
--BluetoothPrivateApiTest.ForgetDevice
--BluetoothPrivateApiTest.NoBluetoothAdapter
--BluetoothPrivateApiTest.Pair
--BluetoothPrivateApiTest.PasskeyPairing
--BluetoothPrivateApiTest.PincodePairing
--BluetoothPrivateApiTest.SetAdapterState
--BrowserActionApiTest.BadgeBackgroundColor
--BrowserActionApiTest.Basic
--BrowserActionApiTest.BrowserActionAddPopup
--BrowserActionApiTest.BrowserActionOpenPopupOnPopup
--BrowserActionApiTest.BrowserActionPopupWithIframe
--BrowserActionApiTest.BrowserActionRemovePopup
--BrowserActionApiTest.BrowserActionWithRectangularIcon
--BrowserActionApiTest.DynamicBrowserAction
--BrowserActionApiTest.Getters
--BrowserActionApiTest.IncognitoBasic
--BrowserActionApiTest.IncognitoSplit
--BrowserActionApiTest.TabSpecificBrowserActionState
--BrowserActionApiTest.TestTriggerBrowserAction
--BrowserActionsBarBrowserTest.PageActionPopupsTest
+-BrowserNavigatorTest.CloseSingletonTab
+-BrowserNavigatorTest.Disposition_CurrentTab
+-BrowserNavigatorTest.NavigateFromPageToOptionsInNewTab
+-BrowserNonClientFrameViewBrowserTest.InactiveSeparatorColor
+# note: this passes locally but fails on bot.
 -BrowserTest.CancelBeforeUnloadResetsURL
+-BrowserTest.ClearPendingOnFailUnlessNTP
+-BrowserTest.GetSizeForNewRenderView
 -BrowserTest.InterstitialCancelsGuestViewDialogs
+-BrowsingDataRemoverBrowserTest.Cache
 -BrowsingDataRemoverBrowserTest.CookieDeletion
--CastChannelAPITest.TestOpenError
--CastChannelAPITest.TestOpenReceiveClose
--CastChannelAPITest.TestOpenSendClose
--CastChannelAPITest.TestPingTimeout
--CastChannelAPITest.TestPingTimeoutSslVerified
--CastStreamingApiTest.BadLogging
--CastStreamingApiTest.Basics
--CastStreamingApiTest.DestinationNotSet
--CastStreamingApiTest.NullStream
--CastStreamingApiTest.Stats
--CastStreamingApiTest.StopNoStart
--CastStreamingApiTestWithPixelOutput.EndToEnd
--CastStreamingApiTestWithPixelOutput.RtpStreamError
+-BrowsingDataRemoverTransportSecurityStateBrowserTest.ClearTransportSecurityState
+-CaptivePortalBrowserTest.RequestFailsFastTimout
+-CertVerifierBrowserTest.MockCertVerifierSmokeTest
 -ChromeFindRequestManagerTest.FindInPDF
 -ChromeNavigationBrowserTest.CrossSiteRedirectionToPDF
+-ChromeResourceDispatcherHostDelegateBrowserTest.PolicyHeader
+-ChromeResourceDispatcherHostDelegateBrowserTest.PolicyHeaderForRedirect
+-ChromeResourceDispatcherHostDelegateBrowserTest.ThrottlesAddedExactlyOnceToADownloads
+-ChromeResourceDispatcherHostDelegateBrowserTest.ThrottlesAddedExactlyOnceToLargeSniffedDownloads
+-ChromeResourceDispatcherHostDelegateBrowserTest.ThrottlesAddedExactlyOnceToTinySniffedDownloads
+-ChromeSecurityExploitBrowserTest.CreateFilesystemURLInExtensionOrigin
+-ChromeServiceWorkerFetchPPAPIPrivateTest.OtherOrigin
+-ChromeServiceWorkerFetchPPAPIPrivateTest.OtherOriginCORS
+-ChromeServiceWorkerFetchPPAPIPrivateTest.OtherOriginCORSCredentials
+-ChromeServiceWorkerFetchPPAPIPrivateTest.OtherOriginCredentials
+-ChromeServiceWorkerFetchPPAPIPrivateTest.SameOrigin
+-ChromeServiceWorkerFetchPPAPIPrivateTest.SameOriginCORS
+-ChromeServiceWorkerFetchPPAPIPrivateTest.SameOriginCORSCredentials
+-ChromeServiceWorkerFetchPPAPIPrivateTest.SameOriginCredentials
+-ChromeServiceWorkerFetchPPAPITest.SameOrigin
 -ChromeSitePerProcessTest.LaunchExternalProtocolFromSubframe
--ChromeUpdatesEventsApiTest.ChromeUpdates
--ClipboardApiTest.Extension
--ClipboardApiTest.ExtensionNoPermission
--CommandLinePrivateApiTest.Basics
--ComponentCloudPolicyTest.FetchExtensionPolicy
--ComponentCloudPolicyTest.InstallNewExtension
--ComponentCloudPolicyTest.SignOutAndBackIn
--ComponentCloudPolicyTest.UpdateExtensionPolicy
+-ContentFaviconDriverTest.ReloadBypassingCache
 -ContentScriptApiTests/ContentScriptApiTest.CannotScriptTheNewTabPage/0
 -ContentScriptApiTests/ContentScriptApiTest.CannotScriptTheNewTabPage/1
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptAboutBlankAndSrcdoc/0
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptAboutBlankAndSrcdoc/1
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptAboutBlankIframes/0
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptAboutBlankIframes/1
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptAllFrames/0
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptAllFrames/1
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptBypassPageCSP/0
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptBypassPageCSP/1
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptCSSLocalization/0
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptCSSLocalization/1
+-ContentScriptApiTests/ContentScriptApiTest.ContentScriptBlockingScriptsDontRunTwice/0
+-ContentScriptApiTests/ContentScriptApiTest.ContentScriptBlockingScriptsDontRunTwice/1
+-ContentScriptApiTests/ContentScriptApiTest.ContentScriptDuplicateScriptInjection/0
+-ContentScriptApiTests/ContentScriptApiTest.ContentScriptDuplicateScriptInjection/1
 -ContentScriptApiTests/ContentScriptApiTest.ContentScriptExtensionAPIs/0
 -ContentScriptApiTests/ContentScriptApiTest.ContentScriptExtensionAPIs/1
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptExtensionIframe/0
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptExtensionIframe/1
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptExtensionProcess/0
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptExtensionProcess/1
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptFragmentNavigation/0
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptFragmentNavigation/1
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptIgnoreHostPermissions/0
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptIgnoreHostPermissions/1
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptOtherExtensions/0
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptOtherExtensions/1
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptPermissionsApi/0
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptPermissionsApi/1
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptViewSource/0
--ContentScriptApiTests/ContentScriptApiTest.ContentScriptViewSource/1
--ContentScriptApiTests/ContentScriptApiTest.DontInjectContentScriptsInBackgroundPages/0
--ContentScriptApiTests/ContentScriptApiTest.DontInjectContentScriptsInBackgroundPages/1
 -ContentVerifierTest.DotSlashPaths
 -ContentVerifierTest.FailOnDone
 -ContentVerifierTest.FailOnRead
--CrazyExtensionTest.Crazy
--CredentialManagerBrowserTest.StoreSavesPSLMatchedCredential
--CredentialManagerBrowserTest.StoreInUnloadHandler_SameSite_PreestablishedPipe
+-CookiePolicyBrowserTest.AllowFirstPartyCookies
+-CookiePolicyBrowserTest.AllowFirstPartyCookiesRedirect
+-CredentialManagerBrowserTest.CreatePublicKeyCredentialAlgorithmNotSupported
+-CredentialManagerBrowserTest.CreatePublicKeyCredentialNotImplemented
+-CredentialManagerBrowserTest.MojoConnectionRecreatedAfterNavigation
 -CredentialManagerBrowserTest.StoreInUnloadHandler_CrossSite_OnDemandMojoPipe
 -CredentialManagerBrowserTest.StoreInUnloadHandler_CrossSite_PreestablishedPipe
--CredentialManagerBrowserTest.MojoConnectionRecreatedAfterNavigation
--CredentialManagerBrowserTest.CreatePublicKeyCredentialNotImplemented
--CredentialManagerBrowserTest.CreatePublicKeyCredentialAlgorithmNotSupported
--CrossOriginXHR.AllURLs
--CrossOriginXHR.BackgroundPage
--CrossOriginXHR.ContentScript
--CrossOriginXHR.FileAccess
--CrossOriginXHR.NoFileAccess
--DeclarativeApiTest.DeclarativeApi
+-CredentialManagerBrowserTest.StoreInUnloadHandler_SameSite_OnDemandMojoPipe
+-CredentialManagerBrowserTest.StoreInUnloadHandler_SameSite_PreestablishedPipe
+-CredentialManagerBrowserTest.StoreSavesPSLMatchedCredential
+-CrExtensionsCodeSectionTest.Layout
+-CrExtensionsDetailViewTest.ClickableElements
+-CrExtensionsDetailViewTest.IndicatorTest
+-CrExtensionsDetailViewTest.Layout
+-CrExtensionsDetailViewTest.Warnings
+-CrExtensionsErrorPageTest.CodeSection
+-CrExtensionsErrorPageTest.ErrorSelection
+-CrExtensionsErrorPageTest.Layout
+-CrExtensionsItemListTest.Filtering
+-CrExtensionsItemListTest.NoItems
+-CrExtensionsItemListTest.NoSearchResults
+-CrExtensionsItemsTest.ClickableItems
+-CrExtensionsItemsTest.DeveloperState
+-CrExtensionsItemsTest.EnableToggle
+-CrExtensionsItemsTest.NormalState
+-CrExtensionsItemsTest.RemoveButton
+-CrExtensionsItemsTest.SourceIndicator
+-CrExtensionsItemsTest.Warnings
+-CrExtensionsLoadErrorTest.CodeSection
+-CrExtensionsLoadErrorTest.Interaction
+-CrExtensionsManagerTest.ItemOrder
+-CrExtensionsManagerTest.UpdateItemData
+-CrExtensionsManagerTestWithIdQueryParam.NavigationToDetails
+-CrExtensionsManagerTestWithMultipleExtensionTypesInstalled.ChangePages
+-CrExtensionsManagerTestWithMultipleExtensionTypesInstalled.ItemListVisibility
+-CrExtensionsManagerTestWithMultipleExtensionTypesInstalled.SplitItems
+-CrExtensionsNavigationHelperTest.Basic
+-CrExtensionsNavigationHelperTest.Conversion
+-CrExtensionsNavigationHelperTest.PushAndReplaceState
+-CrExtensionsNavigationHelperTest.SupportedRoutes
+-CrExtensionsOptionsDialogTest.Layout
+-CrExtensionsPackDialogTest.Interaction
+-CrExtensionsPackDialogTest.PackError
+-CrExtensionsPackDialogTest.PackSuccess
+-CrExtensionsPackDialogTest.PackWarning
+-CrExtensionsServiceTest.ProfileSettings
+-CrExtensionsServiceTest.ToggleEnable
+-CrExtensionsServiceTest.ToggleIncognito
+-CrExtensionsServiceTest.Uninstall
+-CrExtensionsShortcutTest.Basic
+-CrExtensionsShortcutTest.Layout
+-CrExtensionsSidebarTest.LayoutAndClickHandlers
+-CrExtensionsSidebarTest.SetSelected
+-CrExtensionsToggleRowTest.ToggleRowTest
+-CrExtensionsToolbarTest.ClickHandlers
+-CrExtensionsToolbarTest.Layout
+-CrExtensionsViewManagerTest.EventFiringTest
+-CrExtensionsViewManagerTest.VisibilityTest
+-DataProxyScriptBrowserTest.Verify
 -DeclarativeApiTest.ExtensionLifetimeRulesHandling
 -DeclarativeApiTest.NoTracesAfterUninstalling
 -DeclarativeApiTest.PersistRules
--DeclarativeContentApiTest.CanonicalizesPageStateMatcherCss
--DeclarativeContentApiTest.DisabledForSpanningIncognito
--DeclarativeContentApiTest.DisabledForSplitIncognito
--DeclarativeContentApiTest.EnabledForSpanningIncognito
--DeclarativeContentApiTest.EnabledForSplitIncognito
--DeclarativeContentApiTest.IsBookmarkedRulesEvaluatedOnBookmarkEvents
--DeclarativeContentApiTest.NotBookmarkedRulesEvaluatedOnBookmarkEvents
--DeclarativeContentApiTest.PendingWebContentsClearedOnRemoveRules
--DeclarativeContentApiTest.RemoveAllRulesAfterExtensionUninstall
--DeclarativeContentApiTest.ReusedActionInstance
--DeclarativeContentApiTest.RulesEvaluatedForExistingIncognitoTab
--DeclarativeContentApiTest.RulesEvaluatedOnAddRemove
--DeclarativeContentApiTest.RulesPersistence
 -DeclarativeContentApiTest.UninstallWhileActivePageAction
--DesktopCaptureApiTest.ChooseDesktopMedia
--DevToolsExtensionTest.DevToolsExtensionInDevToolsExtension
--DevToolsExtensionTest.DevToolsExtensionInItself
--DevToolsExtensionTest.DevToolsExtensionSecurityPolicyGrants
--DevToolsExtensionTest.HttpIframeInDevToolsExtensionDevtools
--DevToolsExtensionTest.HttpIframeInDevToolsExtensionSideBarPane
--DevToolsExtensionTest.NonDevToolsExtensionInDevToolsExtension
--DeveloperPrivateApiTest.Basics
--DialAPITest.DeviceListEvents
--DialAPITest.Discovery
--DialAPITest.DiscoveryNoListeners
--DialAPITest.FetchDeviceDescription
--DialAPITest.NonWhitelistedExtension
--DialAPITest.OnError
+-DeclarativeNetRequestBrowserTest.*
+-DeclarativeNetRequestBrowserTest_Packed.BrowserRestart/0
+-DevToolsSanityTest.TestRawHeadersWithRedirectAndHSTS
 -DiceBrowserTest.Reauth
 -DiceBrowserTest.Signin
 -DiceBrowserTest.SignoutAllAccounts
@@ -257,34 +127,15 @@
 -DiceFixAuthErrorsBrowserTest.SigninAccountMismatch
 -DiceMigrationBrowserTest.Signin
 -DiceMigrationBrowserTest.Signout
+-DicePrepareMigrationBrowserTest.Signin
+-DicePrepareMigrationBrowserTest.Signout
 -DisabledSignInIsolationBrowserTest.SyntheticTrial
 -DomainReliabilityBrowserTest.Upload
--DownloadsApiTest.DownloadsApiTest
+-DoNotTrackTest.Redirect
+-DoNotTrackTest.Simple
+-DownloadExtensionTest.DownloadExtensionTest_Download_Basic
+-DownloadExtensionTest.DownloadExtensionTest_Download_Redirect
 -EnabledSignInIsolationBrowserTest.SyntheticTrial
--ErrorConsoleBrowserTest.BadAPIArgumentsRuntimeError
--ErrorConsoleBrowserTest.BadAPIPermissionsRuntimeError
--ErrorConsoleBrowserTest.BadExtensionPage
--ErrorConsoleBrowserTest.BrowserActionRuntimeError
--ErrorConsoleBrowserTest.CatchesLastError
--EventsApiTest.ExtensionUpdateSendsOnInstalledEvent
--EventsApiTest.NewlyIntroducedListener
--EventsApiTest.UpdateDispatchesOnInstalledAfterEnablement
--ExecuteScriptApiTest.ExecuteScriptBadEncoding
--ExecuteScriptApiTest.ExecuteScriptBasic
--ExecuteScriptApiTest.ExecuteScriptByFrameId
--ExecuteScriptApiTest.ExecuteScriptCallback
--ExecuteScriptApiTest.ExecuteScriptFileAfterClose
--ExecuteScriptApiTest.ExecuteScriptFragmentNavigation
--ExecuteScriptApiTest.ExecuteScriptFrameAfterLoad
--ExecuteScriptApiTest.ExecuteScriptInFrame
--ExecuteScriptApiTest.ExecuteScriptPermissions
--ExecuteScriptApiTest.ExecuteScriptRunAt
--ExecuteScriptApiTest.FrameWithHttp204
--ExecuteScriptApiTest.InjectIntoSubframesOnLoad
--ExecuteScriptApiTest.NavigationRaceExecuteScript
--ExecuteScriptApiTest.NavigationRaceJavaScriptURL
--ExecuteScriptApiTest.RemovedFrames
--ExecuteScriptApiTest.UserGesture
 -ExecuteScriptApiTest/DestructiveScriptTest.DOMNodeInserted1/0
 -ExecuteScriptApiTest/DestructiveScriptTest.DOMNodeInserted2/0
 -ExecuteScriptApiTest/DestructiveScriptTest.DOMNodeInserted3/0
@@ -294,176 +145,30 @@
 -ExecuteScriptApiTest/DestructiveScriptTest.MacrotaskRemoval/0
 -ExecuteScriptApiTest/DestructiveScriptTest.MicrotaskRemoval/0
 -ExecuteScriptApiTest/DestructiveScriptTest.SynchronousRemoval/0
+-ExecuteScriptApiTest.ExecuteScriptPermissions
 -ExpectCTBrowserTest.TestDynamicExpectCTHeaderProcessing
 -ExpectCTBrowserTest.TestDynamicExpectCTReporting
--ExperimentalApiTest.PermissionsSucceed
 -ExperimentalAppWindowApiTest.SetIcon
--ExtensionActionRunnerBrowserTest.ActiveScriptsAreDisplayedAndDelayExecution
--ExtensionApiCaptureTest.CaptureVisibleDisabled
--ExtensionApiNewTabTest.Tabs
--ExtensionApiTabTest.HostPermission
--ExtensionApiTabTest.IncognitoDisabledByPref
 -ExtensionApiTabTest.OnUpdatedDiscardedState
--ExtensionApiTabTest.TabAudible
--ExtensionApiTabTest.TabConnect
--ExtensionApiTabTest.TabCrashBrowser
 -ExtensionApiTabTest.TabEvents
--ExtensionApiTabTest.TabHighlight
--ExtensionApiTabTest.TabMove
--ExtensionApiTabTest.TabOpener
--ExtensionApiTabTest.TabOpenerCraziness
--ExtensionApiTabTest.TabPinned
--ExtensionApiTabTest.TabQuery
--ExtensionApiTabTest.TabSize
--ExtensionApiTabTest.TabUpdate
--ExtensionApiTabTest.Tabs2
--ExtensionApiTabTest.TabsOnCreated
 -ExtensionApiTabTest.TabsOnUpdated
 -ExtensionApiTabTest.UpdateWindowResize
--ExtensionApiTest.ActiveTab
--ExtensionApiTest.AlertBasic
--ExtensionApiTest.AlertQueue
--ExtensionApiTest.ApiTest
--ExtensionApiTest.BackgroundScripts
--ExtensionApiTest.BookmarkManager
--ExtensionApiTest.BookmarkManagerEditDisabled
--ExtensionApiTest.Canvas2D
--ExtensionApiTest.ChromeIdentityJsBindings
--ExtensionApiTest.ChromeRuntimeGetPackageDirectoryEntryExtension
--ExtensionApiTest.ChromeRuntimeOpenOptionsPage
--ExtensionApiTest.ChromeRuntimeOpenOptionsPageError
--ExtensionApiTest.ChromeRuntimePrivileged
--ExtensionApiTest.ChromeRuntimeUninstallURL
--ExtensionApiTest.ConfirmQueue
 -ExtensionApiTest.ContentSecurityPolicy
--ExtensionApiTest.ContextMenus
--ExtensionApiTest.ContextMenusFromMultipleContexts
 -ExtensionApiTest.Cookies
--ExtensionApiTest.CookiesEvents
--ExtensionApiTest.CookiesEventsSpanning
--ExtensionApiTest.CookiesNoPermission
 -ExtensionApiTest.Debugger
 -ExtensionApiTest.DefaultContentSecurityPolicy
--ExtensionApiTest.Events
--ExtensionApiTest.EventsAreUnregistered
--ExtensionApiTest.FontSettings
--ExtensionApiTest.FontSettingsIncognito
--ExtensionApiTest.GetIncognitoModeAvailability
--ExtensionApiTest.GetViews
--ExtensionApiTest.I18N
--ExtensionApiTest.MessagingUserGesture
--ExtensionApiTest.Metrics
--ExtensionApiTest.MutationObservers
--ExtensionApiTest.NativeMessagingBasic
--ExtensionApiTest.RequestQuotaInBackgroundPage
 -ExtensionApiTest.SandboxedPages
 -ExtensionApiTest.SandboxedPagesCSP
--ExtensionApiTest.SharedModule
--ExtensionApiTest.SharedModuleLocale
--ExtensionApiTest.Storage
--ExtensionApiTest.Stubs
--ExtensionApiTest.StubsApp
--ExtensionApiTest.SystemIndicator
 -ExtensionApiTest.TemporaryAddressSpoof
--ExtensionApiTest.UserLevelNativeMessaging
--ExtensionApiTest.WebSocket
--ExtensionApiTest.WebViewEventRegistration
--ExtensionApiTest.WindowsCreateVsSiteInstance
--ExtensionApiTestWithManagementPolicy.ContentScriptPolicy
--ExtensionApiTestWithManagementPolicy.ContentScriptPolicyByExtensionId
--ExtensionApiTestWithManagementPolicy.ContentScriptPolicyWildcard
 -ExtensionApiTestWithManagementPolicy.InitiatorProtectedByPolicy
--ExtensionApiTestWithManagementPolicy.OptionalPermissionsPolicyBlocked
+-ExtensionApiTestWithManagementPolicy.UrlProtectedByPolicy
 -ExtensionApiTestWithManagementPolicy.WebRequestProtectedByPolicy
 -ExtensionApiTestWithSwitch.ExtensionDebugger
--ExtensionBrowserTest.BrowserActionDefaultPersistence
--ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded
 -ExtensionBrowserTest.OnlyComponentExtensionsCanAccessChromeThemeUrls
--ExtensionBrowserTest.PageAction
--ExtensionBrowserTest.PageActionCrash25562
--ExtensionBrowserTest.PageActionInPageNavigation
--ExtensionBrowserTest.PageActionRefreshCrash
--ExtensionBrowserTest.RSSMultiRelLink
--ExtensionBrowserTest.TitleLocalizationPageAction
--ExtensionBrowserTest.WebContents
--ExtensionBrowserTest.WindowOpenExtension
--ExtensionBrowserTest.WindowOpenNoPrivileges
--ExtensionBrowsertestUtilTest.ExecuteScriptInBackground
--ExtensionContentSettingsApiTest.Standard
--ExtensionContentSettingsApiTest.UnsupportedDefaultSettings
--ExtensionContextMenuApiTest.HideTopLevelItem
--ExtensionContextMenuApiTest.HideTopLevelSubmenuItemIfHiddenAndChildrenHidden
--ExtensionContextMenuApiTest.HideTopLevelSubmenuItemIfHiddenAndSomeChildrenVisible
--ExtensionContextMenuApiTest.ShowExtensionNamedTopLevelItemIfAllChildrenAreHidden
--ExtensionContextMenuApiTest.ShowExtensionNamedTopLevelItemIfSomeChildrenAreVisible
--ExtensionContextMenuApiTest.ShowMultipleExtensionNamedTopLevelItemsWithChidlren
--ExtensionContextMenuApiTest.ShowOneTopLevelItem
--ExtensionContextMenuApiTest.ShowTopLevelItemIfAllItsChildrenAreHidden
--ExtensionContextMenuApiTest.ShowTopLevelSubmenuItemIfSomeOfChildrenAreVisible
--ExtensionContextMenuBrowserTest.ClickInFrame
--ExtensionContextMenuBrowserTest.Enabled
--ExtensionContextMenuBrowserTest.Frames
--ExtensionContextMenuBrowserTest.IncognitoSplitContextMenuCount
--ExtensionContextMenuBrowserTest.LongTitle
--ExtensionContextMenuBrowserTest.Patterns
--ExtensionContextMenuBrowserTest.Separators
--ExtensionContextMenuBrowserTest.Simple
--ExtensionContextMenuBrowserTest.TargetURLs
--ExtensionContextMenuBrowserTest.TopLevel
--ExtensionContextMenuBrowserTest.UpdateCheckedStateOfFirstRadioItem
--ExtensionContextMenuBrowserTest.UpdateCheckedStateOfNonfirstRadioItem
--ExtensionContextMenuBrowserTest.UpdateOnclick
--ExtensionDisabledGlobalErrorTest.AcceptPermissions
--ExtensionFetchTest.ExtensionCanFetchExtensionResource
--ExtensionIdltestApiTest.IdlCompiler
--ExtensionLoadingTest.RuntimeValidWhileDevToolsOpen
--ExtensionManagementApiBrowserTest.GetAllIncludesTerminated
--ExtensionManagementApiBrowserTest.GetSelfNoPermissions
--ExtensionManagementApiBrowserTest.InstallEvent
--ExtensionManagementApiBrowserTest.LaunchApp
--ExtensionManagementApiBrowserTest.LaunchAppFromBackground
--ExtensionManagementApiBrowserTest.SelfUninstall
--ExtensionManagementApiBrowserTest.SelfUninstallNoPermissions
--ExtensionManagementApiTest.Basics
--ExtensionManagementApiTest.CreateAppShortcut
--ExtensionManagementApiTest.GenerateAppForLink
--ExtensionManagementApiTest.LaunchPanelApp
--ExtensionManagementApiTest.LaunchTabApp
--ExtensionManagementApiTest.LaunchType
--ExtensionManagementApiTest.ManagementPolicyAllowed
--ExtensionManagementApiTest.ManagementPolicyProhibited
--ExtensionManagementApiTest.NoPermission
--ExtensionManagementApiTest.Uninstall
--ExtensionManagementTest.AutoUpdate
--ExtensionManagementTest.AutoUpdateDisabledExtensions
--ExtensionManagementTest.ExternalPolicyRefresh
--ExtensionManagementTest.InstallOlderVersion
--ExtensionManagementTest.InstallThenCancel
--ExtensionMessageBubbleViewBrowserTest.TestUninstallDangerousExtension
--ExtensionModuleApiTest.CognitoFile
--ExtensionModuleApiTest.CognitoNoFile
--ExtensionModuleApiTest.IncognitoFile
--ExtensionModuleApiTest.IncognitoNoFile
+-ExtensionFetchTest.HostCanFetchWebAccessibleExtensionResource
+-ExtensionIconSourceTest.IconsLoaded
+-ExtensionIconSourceTest.IconsLoadedIncognito
 -ExtensionModuleTest.TestModulesAvailable
--ExtensionOptionsApiTests/ExtensionOptionsApiTest.CannotEmbedUsingInvalidExtensionIds/0
--ExtensionOptionsApiTests/ExtensionOptionsApiTest.CannotEmbedUsingInvalidExtensionIds/1
--ExtensionOptionsApiTests/ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions/1
--ExtensionOptionsApiTests/ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions/0
--ExtensionOptionsApiTests/ExtensionOptionsApiTest.ShouldNotEmbedOtherExtensionsOptions/0
--ExtensionOptionsApiTests/ExtensionOptionsApiTest.ShouldNotEmbedOtherExtensionsOptions/1
--ExtensionOverrideTest.OverrideHistory
--ExtensionOverrideTest.OverrideNewTab
--ExtensionOverrideTest.OverrideNewTabMultiple
--ExtensionOverrideTest.OverridingExtensionUnloadedWithPageOpen
--ExtensionOverrideTest.SubframeNavigationInOverridenNTPDoesNotAffectFocus
--ExtensionPageCaptureApiTest.SaveAsMHTML
--ExtensionPreferenceApiTest.Clear
--ExtensionPreferenceApiTest.DataReductionProxy
--ExtensionPreferenceApiTest.OnChange
--ExtensionPreferenceApiTest.OnChangeSplit
--ExtensionPreferenceApiTest.PersistentIncognito
--ExtensionPreferenceApiTest.SessionOnlyIncognito
--ExtensionPreferenceApiTest.Standard
 -ExtensionRequestLimitingThrottleBrowserTest.DoNotThrottleCachedResponse
 -ExtensionRequestLimitingThrottleBrowserTest.DoNotThrottleCachedResponse_NonRedirectCached
 -ExtensionRequestLimitingThrottleBrowserTest.DoNotThrottleCachedResponse_Redirect
@@ -471,31 +176,10 @@
 -ExtensionRequestLimitingThrottleBrowserTest.ThrottleRequest_Redirect
 -ExtensionRequestLimitingThrottleBrowserTest.ThrottleRequest_RedirectCached
 -ExtensionRequestLimitingThrottleCommandLineBrowserTest.ThrottleRequestDisabled
--ExtensionResourceRequestPolicyTest.Audio
--ExtensionResourceRequestPolicyTest.ExtensionCanLoadHostedAppIcons
--ExtensionResourceRequestPolicyTest.Iframe
--ExtensionResourceRequestPolicyTest.Video
--ExtensionSettingsApiTest.ManagedStorage
--ExtensionSettingsApiTest.ManagedStorageDisabled
--ExtensionSettingsApiTest.OnChangedNotificationsBetweenBackgroundPages
--ExtensionSettingsApiTest.SimpleTest
--ExtensionSettingsApiTest.SplitModeIncognito
--ExtensionSettingsApiTest.SyncAndLocalAreasAreSeparate
--ExtensionStorageMonitorTest.DisableForInstalledExtensions
--ExtensionStorageMonitorTest.DoubleInitialThreshold
--ExtensionStorageMonitorTest.ExceedInitialThreshold
--ExtensionStorageMonitorTest.ThrottleNotifications
--ExtensionStorageMonitorTest.UnderThreshold
--ExtensionStorageMonitorTest.UserDisabledNotifications
--ExtensionTabsTest.FilteredEvents
--ExtensionTabsTest.GetAllWindows
--ExtensionTabsTest.GetAllWindowsAllTypes
--ExtensionTabsTest.NoTabsAppWindow
--ExtensionTabsTest.NoTabsEventOnDevTools
--ExtensionTabsTest.UpdateAppWindowSizeConstraint
--ExtensionViewTests/ExtensionViewTest.ShimExtensionAttribute/0
--ExtensionViewTests/ExtensionViewTest.ShimSrcAttribute/0
--ExtensionViewTests/ExtensionViewTest.TestExtensionViewCreationShouldSucceed/0
+-ExtensionResourceRequestPolicyTest.WebAccessibleResources
+-ExtensionsA11yTestFixture.BASIC_EXTENSIONS_region
+-ExtensionTabUtilBrowserTest.OpenSpanningModeExtensionOptionsPageIncognito
+-ExtensionUnloadBrowserTest.UnloadWithContentScripts
 -ExtensionWebRequestApiTest.DeclarativeSendMessage
 -ExtensionWebRequestApiTest.ExtensionRequests
 -ExtensionWebRequestApiTest.HostedAppRequest
@@ -518,153 +202,45 @@
 -ExtensionWebRequestApiTest.WebRequestSimple
 -ExtensionWebRequestApiTest.WebRequestTestOSDD
 -ExtensionWebRequestApiTest.WebRequestTypes
--ExtensionWebRequestApiTest.WebRequestURLFetcherInterception
 -ExtensionWebRequestApiTest.WebRequestUnloadImmediately
+-ExtensionWebRequestApiTest.WebRequestURLFetcherInterception
 -ExtensionWebRequestApiTest.WebRequestWithWithheldPermissions
 -ExtensionWebRequestApiTest.WebSocketRequest
--ExtensionWebRequestApiTest.WebSocketRequestAuthRequired
--ExtensionWebUITest.ReceivesExtensionOptionsOnClose
--ExtensionWindowLastFocusedTest.NoDevtoolsAndAppWindows
--ExtensionWindowLastFocusedTest.NoTabIdForDevToolsAndAppWindows
--ExtensionViewTests/ExtensionViewTest.ShimExtensionAttribute/1
--ExtensionViewTests/ExtensionViewTest.TestExtensionViewCreationShouldSucceed/1
--ExtensionViewTests/ExtensionViewTest.ShimSrcAttribute/1
--ExternallyConnectableMessagingTest.WebConnectableWithTlsChannelIdWithEmptyTlsChannelId
--ExternallyConnectableMessagingTest.WebConnectableWithoutTlsChannelId
--ExternallyConnectableMessagingWithTlsChannelIdTest.WebConnectableWithNonEmptyTlsChannelId
--FileSystemApiTest.FileSystemApiGetDisplayPath
--FileSystemApiTest.FileSystemApiGetDisplayPathPrettify
--FileSystemApiTest.FileSystemApiGetWritableRootEntryTest
--FileSystemApiTest.FileSystemApiGetWritableTest
--FileSystemApiTest.FileSystemApiGetWritableWithWriteTest
--FileSystemApiTest.FileSystemApiInvalidChooseEntryTypeTest
--FileSystemApiTest.FileSystemApiIsWritableTest
--FileSystemApiTest.FileSystemApiIsWritableWithWritePermissionTest
--FileSystemApiTest.FileSystemApiOpenBackgroundTest
--FileSystemApiTest.FileSystemApiOpenCancelTest
--FileSystemApiTest.FileSystemApiOpenDirectoryContainingGraylistTest
--FileSystemApiTest.FileSystemApiOpenDirectoryOnGraylistAndAllowTest
--FileSystemApiTest.FileSystemApiOpenDirectoryOnGraylistTest
--FileSystemApiTest.FileSystemApiOpenDirectorySubdirectoryOfGraylistTest
--FileSystemApiTest.FileSystemApiOpenDirectoryTest
--FileSystemApiTest.FileSystemApiOpenDirectoryWithOnlyWritePermissionTest
--FileSystemApiTest.FileSystemApiOpenDirectoryWithWriteTest
--FileSystemApiTest.FileSystemApiOpenDirectoryWithoutPermissionTest
--FileSystemApiTest.FileSystemApiOpenExistingFileDefaultPathTest
--FileSystemApiTest.FileSystemApiOpenExistingFilePreviousPathDoesNotExistTest
--FileSystemApiTest.FileSystemApiOpenExistingFileTest
--FileSystemApiTest.FileSystemApiOpenExistingFileUsingPreviousPathTest
--FileSystemApiTest.FileSystemApiOpenExistingFileWithWriteTest
--FileSystemApiTest.FileSystemApiOpenMultipleExistingFilesTest
--FileSystemApiTest.FileSystemApiOpenMultipleSuggested
--FileSystemApiTest.FileSystemApiOpenMultipleWritableExistingFilesTest
--FileSystemApiTest.FileSystemApiOpenWritableExistingFileTest
--FileSystemApiTest.FileSystemApiOpenWritableExistingFileWithWriteTest
--FileSystemApiTest.FileSystemApiRestoreDirectoryEntry
--FileSystemApiTest.FileSystemApiRestoreEntry
--FileSystemApiTest.FileSystemApiRetainDirectoryEntry
--FileSystemApiTest.FileSystemApiRetainEntry
--FileSystemApiTest.FileSystemApiSaveBackgroundTest
--FileSystemApiTest.FileSystemApiSaveCancelTest
--FileSystemApiTest.FileSystemApiSaveExistingFileTest
--FileSystemApiTest.FileSystemApiSaveExistingFileWithWriteTest
--FileSystemApiTest.FileSystemApiSaveMultipleFilesTest
--FileSystemApiTest.FileSystemApiSaveNewFileTest
--FileSystemApiTest.FileSystemApiSaveNewFileWithWriteTest
--FileSystemApiTest.RequestFileSystem_NotChromeOS
--FlagOffExtensionActionRunnerBrowserTest.ScriptsExecuteWhenFlagAbsent
+-FeedbackTest.AnonymousUser
+-FeedbackTest.ExtraDiagnostics
+-FeedbackTest.ShowFeedback
+-FeedbackTest.ShowLoginFeedback
+-FileProxyScriptBrowserTest.Verify
 -FlashEmbeds/ChromeContentRendererClientBrowserTest.RewriteYouTubeFlashEmbed/0
 -FlashEmbeds/ChromeContentRendererClientBrowserTest.RewriteYouTubeFlashEmbed/1
 -FlashEmbeds/ChromeContentRendererClientBrowserTest.RewriteYouTubeFlashEmbed/2
 -FlashEmbeds/ChromeContentRendererClientBrowserTest.RewriteYouTubeFlashEmbed/3
 -FlashEmbeds/ChromeContentRendererClientBrowserTest.RewriteYouTubeFlashEmbed/4
+-FlashEmbeds/ChromeContentRendererClientBrowserTest.RewriteYouTubeFlashEmbedObject/0
+-FlashEmbeds/ChromeContentRendererClientBrowserTest.RewriteYouTubeFlashEmbedObject/1
 -FlashEmbeds/ChromeContentRendererClientBrowserTest.RewriteYouTubeFlashEmbedObject/2
 -FlashEmbeds/ChromeContentRendererClientBrowserTest.RewriteYouTubeFlashEmbedObject/3
 -FlashEmbeds/ChromeContentRendererClientBrowserTest.RewriteYouTubeFlashEmbedObject/4
--GcmApiTest.Incognito
--GcmApiTest.OnMessage
--GcmApiTest.OnMessagesDeleted
--GcmApiTest.OnSendError
--GcmApiTest.Register
--GcmApiTest.RegisterValidation
--GcmApiTest.SendMessageData
--GcmApiTest.SendMessageDefaultTTL
--GcmApiTest.SendValidation
--GcmApiTest.Unregister
--HistoryApiTest.Delete
--HistoryApiTest.DeleteProhibited
--HistoryApiTest.GetVisits
--HistoryApiTest.SearchAfterAdd
--ImageWriterPrivateApiTest.TestListDevices
--ImageWriterPrivateApiTest.TestWriteFromFile
--IncognitoApiTest.Incognito
--IncognitoApiTest.IncognitoDisabled
--InlineInstallPrivateApiTestApp.BackgroundInstall
--InlineInstallPrivateApiTestApp.NoGesture
--InlineInstallPrivateApiTestApp.SuccessfulInstall
--InlineInstallPrivateApiTestExtension.OnlyApps
+-FtpProxyScriptBrowserTest.Verify
+-HttpProxyScriptBrowserTest.Verify
 -InlineLoginUISafeIframeBrowserTest.LoadSuccessContinueURL
--InputImeApiTest.BasicApiTest
--InputImeApiTest.SendKeyEventsOnNormalPage
--InputImeApiTest.SendKeyEventsOnSpecialPage
--InstanceIDApiTest.DeleteID
--InstanceIDApiTest.DeleteToken
--InstanceIDApiTest.GetCreationTime
--InstanceIDApiTest.GetID
--InstanceIDApiTest.GetToken
--InstanceIDApiTest.Incognito
+-InProcessBrowserTest.ExternalConnectionFail
+-InstantThemeTest.ThemeBackgroundAccess
+-IsolatedAppTest.CookieIsolation
 -IsolatedAppTest.SubresourceCookieIsolation
--JavaScript/ExtensionBindingsApiTest.AboutBlankIframe/0
--JavaScript/ExtensionBindingsApiTest.ApiEnums/0
--JavaScript/ExtensionBindingsApiTest.EventOverriding/0
--JavaScript/ExtensionBindingsApiTest.ExceptionInHandlerShouldNotCrash/0
--JavaScript/ExtensionBindingsApiTest.ExtensionSubframeGetsBindings/0
--JavaScript/ExtensionBindingsApiTest.InternalAPIsNotOnChromeObject/0
--JavaScript/ExtensionBindingsApiTest.LastError/0
--JavaScript/ExtensionBindingsApiTest.ModuleSystem/0
--JavaScript/ExtensionBindingsApiTest.Nocompile/0
--JavaScript/ExtensionBindingsApiTest.TestEventFilterParsing/0
--JavaScript/ExtensionBindingsApiTest.UnavailableBindingsNeverRegistered/0
--JavaScript/ExtensionBindingsApiTest.UncaughtExceptionLogging/0
--JavaScript/FramesExtensionBindingsApiTest.FramesBeforeNavigation/0
--JavaScriptBindings/ExternallyConnectableMessagingTest.WebConnectableWithTlsChannelIdWithEmptyTlsChannelId/0
--JavaScriptBindings/ExternallyConnectableMessagingTest.WebConnectableWithoutTlsChannelId/0
--JavaScriptBindings/ExternallyConnectableMessagingWithTlsChannelIdTest.WebConnectableWithNonEmptyTlsChannelId/0
--JavaScriptBindings/MessagingApiTest.LargeMessages/0
--JavaScriptBindings/MessagingApiTest.Messaging/0
--JavaScriptBindings/MessagingApiTest.MessagingBackgroundOnly/0
--JavaScriptBindings/MessagingApiTest.MessagingCrash/0
--JavaScriptBindings/MessagingApiTest.MessagingEventURL/0
--JavaScriptBindings/MessagingApiTest.MessagingExternal/0
--JavaScriptBindings/MessagingApiTest.MessagingInterstitial/0
--JavaScriptBindings/MessagingApiTest.MessagingNoBackground/0
--JavaScriptBindings/MessagingApiTest.MessagingOnUnload/0
--JavaScriptBindings/MessagingApiTest.MessagingUserGesture/0
--JavscriptApiTest.JavaScriptURLPermissions
--JavscriptApiTest.JavasScriptEncodedURL
--KeyRotationComponentCloudPolicyTest.Basic
 -LaunchWebAuthFlowFunctionTest.InteractionRequired
 -LaunchWebAuthFlowFunctionTest.InteractiveFirstNavigationSuccess
 -LaunchWebAuthFlowFunctionTest.LoadFailed
 -LaunchWebAuthFlowFunctionTest.NonInteractiveSuccess
 -LaunchWebAuthFlowFunctionTest.UserCloseWindow
--LazyBackgroundPageApiTest.BroadcastEvent
--LazyBackgroundPageApiTest.BrowserActionCreateTab
--LazyBackgroundPageApiTest.BrowserActionCreateTabAfterCallback
--LazyBackgroundPageApiTest.EventDispatchToTab
--LazyBackgroundPageApiTest.EventListenerCleanup
--LazyBackgroundPageApiTest.Filters
--LazyBackgroundPageApiTest.Messaging
 -LazyBackgroundPageApiTest.NaClInBackgroundPage
 -LazyBackgroundPageApiTest.NaClInView
--LazyBackgroundPageApiTest.OnInstalled
--LazyBackgroundPageApiTest.UpdateExtensionsPage
--LazyBackgroundPageApiTest.WaitForDialog
--LazyBackgroundPageApiTest.WaitForNTP
--LazyBackgroundPageApiTest.WaitForRequest
--LazyBackgroundPageApiTest.WaitForView
--LoadAndLaunchPlatformAppBrowserTest.LoadAndLaunchAppChromeNotRunning
 -LocalNTPJavascriptTest.LoadsIframe
+-LocalNTPJavascriptTest.SimpleJavascriptTests
+-LocalNTPVoiceJavascriptTest.MicrophoneTests
+-LocalNTPVoiceJavascriptTest.SpeechTests
+-LocalNTPVoiceJavascriptTest.TextTests
+-LocalNTPVoiceJavascriptTest.ViewTests
 -LoginPromptBrowserTest.AllowCrossdomainPromptForSubframes
 -LoginPromptBrowserTest.BlockCrossdomainPromptForSubresources
 -LoginPromptBrowserTest.CancelLoginInterstitialOnRedirect
@@ -688,34 +264,9 @@
 -LoginPromptBrowserTest.TestCancelAuth_OnNavigation
 -LoginPromptBrowserTest.TestDigestAuth
 -LoginPromptBrowserTest.TestTwoAuths
--MDnsAPITest.ForceDiscovery
--MDnsAPITest.MaxServiceInstancesPerEventConst
--MDnsAPITest.RegisterListener
--MDnsAPITest.RegisterMultipleListeners
--MDnsAPITest.RegisterTooManyListeners
--MediaGalleriesGalleryWatchApiTest.BasicGalleryWatch
--MediaGalleriesGalleryWatchApiTest.CorrectResponseOnModifyingWatchedGallery
--MediaGalleriesGalleryWatchApiTest.RemoveListenerAndModifyGallery
--MediaGalleriesGalleryWatchApiTest.SetupGalleryChangedListenerWithoutWatchers
--MediaGalleriesGalleryWatchApiTest.SetupGalleryWatchWithoutListeners
--MediaGalleriesGalleryWatchApiTest.SetupWatchOnInvalidGallery
--MediaGalleriesPlatformAppBrowserTest.GetMetadata
--MediaGalleriesPlatformAppBrowserTest.MediaGalleriesAccessAttached
--MediaGalleriesPlatformAppBrowserTest.MediaGalleriesDelete
--MediaGalleriesPlatformAppBrowserTest.MediaGalleriesRead
--MediaGalleriesPlatformAppBrowserTest.NoGalleriesCopyTo
--MediaGalleriesPlatformAppBrowserTest.NoGalleriesRead
 -MediaGalleriesPlatformAppBrowserTest.ToURL
 -MediaGalleriesPlatformAppPpapiTest.SendFilesystem
--MessagingApiTest.LargeMessages
--MessagingApiTest.Messaging
--MessagingApiTest.MessagingBackgroundOnly
--MessagingApiTest.MessagingCrash
--MessagingApiTest.MessagingEventURL
--MessagingApiTest.MessagingExternal
--MessagingApiTest.MessagingInterstitial
--MessagingApiTest.MessagingNoBackground
--MessagingApiTest.MessagingOnUnload
+-MediaStreamDevicesControllerTest.ExtensionRequestMicCam
 -MimeHandlerViewTests/MimeHandlerViewTest.Abort/0
 -MimeHandlerViewTests/MimeHandlerViewTest.Abort/1
 -MimeHandlerViewTests/MimeHandlerViewTest.Basic/0
@@ -739,52 +290,20 @@
 -MimeHandlerViewTests/MimeHandlerViewTest.ResizeBeforeAttach/0
 -MimeHandlerViewTests/MimeHandlerViewTest.ResizeBeforeAttach/1
 -MimeHandlerViewTests/MimeHandlerViewTest.SingleRequest/1
--MusicManagerPrivateTest.DeviceIdValueReturned
 -NaClBrowserTestGLibcVcacheExtension.ValidationCacheOfMainNexe
 -NaClBrowserTestNewlibVcacheExtension.ValidationCacheOfMainNexe
--Native/ExtensionBindingsApiTest.AboutBlankIframe/0
--Native/ExtensionBindingsApiTest.ApiEnums/0
--Native/ExtensionBindingsApiTest.EventOverriding/0
--Native/ExtensionBindingsApiTest.ExceptionInHandlerShouldNotCrash/0
--Native/ExtensionBindingsApiTest.ExtensionSubframeGetsBindings/0
--Native/ExtensionBindingsApiTest.InternalAPIsNotOnChromeObject/0
--Native/ExtensionBindingsApiTest.LastError/0
--Native/ExtensionBindingsApiTest.ModuleSystem/0
--Native/ExtensionBindingsApiTest.Nocompile/0
--Native/ExtensionBindingsApiTest.TestEventFilterParsing/0
--Native/ExtensionBindingsApiTest.UnavailableBindingsNeverRegistered/0
--Native/ExtensionBindingsApiTest.UncaughtExceptionLogging/0
--Native/FramesExtensionBindingsApiTest.FramesBeforeNavigation/0
--NativeBindings/ExternallyConnectableMessagingTest.WebConnectableWithTlsChannelIdWithEmptyTlsChannelId/0
--NativeBindings/ExternallyConnectableMessagingTest.WebConnectableWithoutTlsChannelId/0
--NativeBindings/ExternallyConnectableMessagingWithTlsChannelIdTest.WebConnectableWithNonEmptyTlsChannelId/0
--NativeBindings/MessagingApiTest.LargeMessages/0
--NativeBindings/MessagingApiTest.Messaging/0
--NativeBindings/MessagingApiTest.MessagingBackgroundOnly/0
--NativeBindings/MessagingApiTest.MessagingCrash/0
--NativeBindings/MessagingApiTest.MessagingEventURL/0
--NativeBindings/MessagingApiTest.MessagingExternal/0
--NativeBindings/MessagingApiTest.MessagingInterstitial/0
--NativeBindings/MessagingApiTest.MessagingNoBackground/0
--NativeBindings/MessagingApiTest.MessagingOnUnload/0
--NativeBindings/MessagingApiTest.MessagingUserGesture/0
--NativeBindingsApiTest.ContextMenusTest
--NativeBindingsApiTest.DeclarativeEvents
--NativeBindingsApiTest.ErrorsInCallbackTest
 -NativeBindingsApiTest.FileSystemApiGetDisplayPath
--NativeBindingsApiTest.SimpleAppTest
--NativeBindingsApiTest.SimpleEndToEndTest
 -NativeBindingsApiTest.WebRequest
--NavigatingExtensionPopupBrowserTest.DownloadViaPost
--NavigatingExtensionPopupBrowserTest.PageInOtherExtension
--NavigatingExtensionPopupBrowserTest.PageInSameExtension
--NavigatingExtensionPopupBrowserTest.Webpage
 -NetInternalsTest.netInternalsPrerenderViewFail
 -NetInternalsTest.netInternalsSessionBandwidthSucceed
 -NewlibPackagedAppTest.MulticastPermissions
 -NewlibPackagedAppTest.NoSocketPermissions
 -NewlibPackagedAppTest.SocketPermissions
 -NewlibPackagedAppTest.SuccessfulLoad
+-NewTabPageInterceptorTest.204Interception
+-NewTabPageInterceptorTest.404Interception
+-NewTabPageInterceptorTest.FailedRequestInterception
+-NewTabPageInterceptorTest.NoInterception
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.AppCacheHtmlUninitialized/1
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.IssuesIdlePriorityRequests/1
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.Jpeg/1
@@ -798,6 +317,8 @@
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.Prefetch302Redirect/1
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchClientRedirect/1
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchCrossDomain/1
+-NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchHistograms/0
+-NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchHistograms/1
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchHttps/1
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchImage/1
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchLoadFlag/1
@@ -808,67 +329,18 @@
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.ResponseHeaderCSP/1
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.ServiceWorkerIntercept/1
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.SSLSubresourceError/1
--OmniboxApiTest.OnInputEntered
--PDFExtensionClipboardTest.CombinedShiftArrowPresses
--PDFExtensionClipboardTest.CombinedShiftRightArrowPresses
--PDFExtensionClipboardTest.IndividualShiftLeftArrowPresses
--PDFExtensionClipboardTest.IndividualShiftRightArrowPresses
--PDFExtensionLinkClickTest.CtrlLeft
--PDFExtensionLinkClickTest.CtrlShiftLeft
--PDFExtensionLinkClickTest.Middle
--PDFExtensionLinkClickTest.OpenPDFWithReplaceState
--PDFExtensionLinkClickTest.ShiftLeft
--PDFExtensionLinkClickTest.ShiftMiddle
--PDFExtensionTest.Basic
--PDFExtensionTest.BasicPlugin
--PDFExtensionTest.BlockDirectAccess
--PDFExtensionTest.Bookmark
--PDFExtensionTest.Elements
--PDFExtensionTest.EnsurePDFFromLocalFileLoads
--PDFExtensionTest.EnsureSameOriginRepliesAllowed
--PDFExtensionTest.GestureDetector
--PDFExtensionTest.LinkPermissions
--PDFExtensionTest.NavigationOnCorrectTab
--PDFExtensionTest.Navigator
--PDFExtensionTest.OpenFromFTP
--PDFExtensionTest.PageChange
--PDFExtensionTest.ParamsParser
--PDFExtensionTest.PdfAccessibility
--PDFExtensionTest.PdfAccessibilityEnableLater
--PDFExtensionTest.PdfAccessibilityInIframe
--PDFExtensionTest.PdfAccessibilityInOOPIF
--PDFExtensionTest.PdfZoomWithoutBubble
--PDFExtensionTest.RedirectsFailInPlugin
--PDFExtensionTest.TabTitleWithNoTitle
--PDFExtensionTest.TabTitleWithTitle
--PDFExtensionTest.Title
--PDFExtensionTest.ToolbarManager
--PDFExtensionTest.TouchHandling
--PDFExtensionTest.Viewport
--PDFExtensionTest.WhitespaceTitle
--PDFExtensionTest.ZoomManager
--PDFTestFiles/PDFExtensionTest.Load/0
--PDFTestFiles/PDFExtensionTest.Load/1
--PDFTestFiles/PDFExtensionTest.Load/3
--PDFTestFiles/PDFExtensionTest.Load/5
--PDFTestFiles/PDFExtensionTest.Load/8
--PageActionApiTest.AddPopup
--PageActionApiTest.Basic
--PageActionApiTest.Getters
--PageActionApiTest.RemovePopup
--PageActionApiTest.TestTriggerPageAction
+-OutOfProcessPPAPITest.FileRef1
+-OutOfProcessPPAPITest.FileRef2
+-OutOfProcessPPAPITest.URLLoader1
+-OutOfProcessProxyResolverBrowserTest.Verify
 -PageInfoBubbleViewBrowserTest.SiteSettingsLinkWithSiteDetailsEnabledAndNonDefaultPort
+-PageLoadMetricsBrowserTest.ChromeErrorPage
 -PageLoadMetricsBrowserTest.LoadingMetrics
 -PageLoadMetricsBrowserTest.LoadingMetricsFailed
+-PageLoadMetricsBrowserTest.PayloadSize
+-PageLoadMetricsBrowserTest.PayloadSizeChildFrame
 -PasswordManagerBrowserTestBase.BasicAuthSeparateRealms
 -PasswordManagerBrowserTestBase.NoLastLoadGoodLastLoad
--PasswordsPrivateApiTest.ExportPasswords
--PasswordsPrivateApiTest.GetPasswordExceptionList
--PasswordsPrivateApiTest.GetSavedPasswordList
--PasswordsPrivateApiTest.ImportPasswords
--PasswordsPrivateApiTest.RemoveAndUndoRemovePasswordException
--PasswordsPrivateApiTest.RemoveAndUndoRemoveSavedPassword
--PasswordsPrivateApiTest.RequestPlaintextPassword
 -PaymentMethodViewControllerTest.EditButtonOpensEditor
 -PaymentMethodViewControllerTest.OneCardSelected
 -PaymentMethodViewControllerTest.OneCardSelectedOutOfMany
@@ -952,10 +424,11 @@
 -PaymentRequestDebitTest.UnknownCardTypeIsNotPreselected
 -PaymentRequestEmptyUpdateTest.NoCrash
 -PaymentRequestErrorMessageTest.CompleteFail
--PaymentRequestIframeTest.HistoryPushState_UserAborted
--PaymentRequestIframeTest.IframeNavigation_UserAborted
--PaymentRequestIframeTest.IframeNavigation_Completed
 -PaymentRequestIframeTest.HistoryPushState_Completed
+-PaymentRequestIframeTest.HistoryPushState_UserAborted
+-PaymentRequestIframeTest.IframeNavigation_Completed
+-PaymentRequestIframeTest.IframeNavigation_UserAborted
+-PaymentRequestInitiatedCompletionStatusMetricsTest.Aborted_NotShown
 -PaymentRequestJourneyLoggerAllSectionStatsTest.NumberOfSuggestionsShown_Completed
 -PaymentRequestJourneyLoggerAllSectionStatsTest.NumberOfSuggestionsShown_UserAborted
 -PaymentRequestJourneyLoggerMultipleShowTest.ShowSameRequest
@@ -966,14 +439,14 @@
 -PaymentRequestJourneyLoggerNoShippingSectionStatsTest.NumberOfSuggestionsShown_UserAborted
 -PaymentRequestJourneyLoggerNoSupportedPaymentMethodTest.OnlyBobpaySupported
 -PaymentRequestJourneyLoggerSelectedPaymentInstrumentTest.TestSelectedPaymentMethod
--PaymentRequestModifiersTest.NoModifierAppliedIfNoSelectedInstrument
--PaymentRequestModifiersTest.ModifierAppliedIfApplicableSelectedInstrumentWithoutTypeOrNetwork
 -PaymentRequestModifiersTest.ModifierAppliedIfApplicableSelectedInstrumentWithCreditSupportedType
--PaymentRequestModifiersTest.ModifierNotAppliedIfSelectedInstrumentWithDebitSupportedType
 -PaymentRequestModifiersTest.ModifierAppliedIfApplicableSelectedInstrumentWithMatchingNetwork
--PaymentRequestModifiersTest.ModifierNotAppliedIfSelectedInstrumentWithoutMatchingNetwork
+-PaymentRequestModifiersTest.ModifierAppliedIfApplicableSelectedInstrumentWithoutTypeOrNetwork
 -PaymentRequestModifiersTest.ModifierAppliedToBasicCardWithoutTypeOrNetwork
 -PaymentRequestModifiersTest.ModifierAppliedToUnknownTypeWithMatchingNetwork
+-PaymentRequestModifiersTest.ModifierNotAppliedIfSelectedInstrumentWithDebitSupportedType
+-PaymentRequestModifiersTest.ModifierNotAppliedIfSelectedInstrumentWithoutMatchingNetwork
+-PaymentRequestModifiersTest.NoModifierAppliedIfNoSelectedInstrument
 -PaymentRequestNoShippingTest.InactiveBrowserWindow
 -PaymentRequestNoShippingTest.InvalidSSL
 -PaymentRequestNoShippingTest.OpenAndClickCancel
@@ -988,10 +461,10 @@
 -PaymentRequestNoUpdateWithTest.BuyWithoutPromises
 -PaymentRequestOrderSummaryViewControllerTest.OrderSummaryReflectsShippingOption
 -PaymentRequestPaymentAppTest.ShowNotSupportedError
--PaymentRequestPaymentMethodIdentifierTest.BasicCard_NetworkThenBasicCardWithSameNetwork
+-PaymentRequestPaymentMethodIdentifierTest.BasicCard_NetworksSpecified
 -PaymentRequestPaymentMethodIdentifierTest.BasicCard_NetworkThenBasicCard_DifferentList
 -PaymentRequestPaymentMethodIdentifierTest.BasicCard_NetworkThenBasicCard_SameList
--PaymentRequestPaymentMethodIdentifierTest.BasicCard_NetworksSpecified
+-PaymentRequestPaymentMethodIdentifierTest.BasicCard_NetworkThenBasicCardWithSameNetwork
 -PaymentRequestPaymentMethodIdentifierTest.BasicCard_NoNetworksSpecified
 -PaymentRequestPaymentMethodIdentifierTest.MultiplePaymentMethodIdentifiers
 -PaymentRequestPaymentMethodIdentifierTest.Url_Valid
@@ -1028,6 +501,7 @@
 -PaymentRequestShippingAddressInstanceTest.ShouldBeSameInstance
 -PaymentRequestShippingAddressUseStatsTest.RecordUse
 -PaymentRequestShippingOptionViewControllerTest.SelectingVariousShippingOptions
+-PaymentRequestWebContentsManagerTest.MultipleRequests
 -PaymentSheetViewControllerContactDetailsTest.AllClickableRowsPresent
 -PaymentSheetViewControllerContactDetailsTest.AllRowsPresent
 -PaymentSheetViewControllerContactDetailsTest.NoData
@@ -1040,133 +514,100 @@
 -PaymentSheetViewControllerNoShippingTest.SupportedCard
 -PaymentSheetViewControllerNoShippingTest.UnsupportedCard
 -PaymentsRequestVisualTest.InvokeDialog_NoShipping
+-PDFExtensionClipboardTest.CombinedShiftArrowPresses
+-PDFExtensionClipboardTest.CombinedShiftRightArrowPresses
+-PDFExtensionClipboardTest.IndividualShiftLeftArrowPresses
+-PDFExtensionClipboardTest.IndividualShiftRightArrowPresses
+-PDFExtensionLinkClickTest.CtrlLeft
+-PDFExtensionLinkClickTest.CtrlShiftLeft
+-PDFExtensionLinkClickTest.Middle
+-PDFExtensionLinkClickTest.OpenPDFWithReplaceState
+-PDFExtensionLinkClickTest.ShiftLeft
+-PDFExtensionLinkClickTest.ShiftMiddle
+-PDFExtensionTest.Basic
+-PDFExtensionTest.BasicPlugin
+-PDFExtensionTest.BlockDirectAccess
+-PDFExtensionTest.Bookmark
+-PDFExtensionTest.Elements
+-PDFExtensionTest.EnsurePDFFromLocalFileLoads
+-PDFExtensionTest.EnsureSameOriginRepliesAllowed
+-PDFExtensionTest.GestureDetector
+-PDFExtensionTest.LinkPermissions
+-PDFExtensionTest.NavigationOnCorrectTab
+-PDFExtensionTest.Navigator
+-PDFExtensionTest.OpenFromFTP
+-PDFExtensionTest.PageChange
+-PDFExtensionTest.ParamsParser
+-PDFExtensionTest.PdfAccessibility
+-PDFExtensionTest.PdfAccessibilityEnableLater
+-PDFExtensionTest.PdfAccessibilityInIframe
+-PDFExtensionTest.PdfAccessibilityInOOPIF
+-PDFExtensionTest.PdfZoomWithoutBubble
+-PDFExtensionTest.RedirectsFailInPlugin
+-PDFExtensionTest.TabTitleWithNoTitle
+-PDFExtensionTest.TabTitleWithTitle
+-PDFExtensionTest.Title
+-PDFExtensionTest.ToolbarManager
+-PDFExtensionTest.TouchHandling
+-PDFExtensionTest.Viewport
+-PDFExtensionTest.WhitespaceTitle
+-PDFExtensionTest.ZoomManager
 -PdfPluginContextMenuBrowserTest.FullPagePdfHasPageItems
 -PdfPluginContextMenuBrowserTest.IframedPdfHasNoPageItems
--PermissionsApiTest.AlwaysAllowed
--PermissionsApiTest.ExperimentalPermissionsFail
+-PDFTestFiles/PDFExtensionTest.Load/0
+-PDFTestFiles/PDFExtensionTest.Load/1
+-PDFTestFiles/PDFExtensionTest.Load/3
+-PDFTestFiles/PDFExtensionTest.Load/5
+-PDFTestFiles/PDFExtensionTest.Load/8
 -PermissionsApiTest.FaviconPermission
--PermissionsApiTest.HostSubsets
--PermissionsApiTest.OptionalPermissionsAutoConfirm
--PermissionsApiTest.OptionalPermissionsDeny
--PermissionsApiTest.OptionalPermissionsFileAccess
--PermissionsApiTest.OptionalPermissionsGesture
--PermissionsApiTest.OptionalPermissionsGranted
--PermissionsApiTest.OptionalPermissionsRetainGesture
--PermissionsApiTest.OptionalPermissionsUpdatesBindings
--PermissionsApiTest.PermissionsFail
--PlatformAppBrowserTest.ActiveAppsAreRecorded
+-PKPModelClientTest.PKPBypass
+-PKPModelClientTest.PKPEnforced
 -PlatformAppBrowserTest.AppWindowAdjustBoundsToBeVisibleOnScreen
--PlatformAppBrowserTest.AppWindowIframe
--PlatformAppBrowserTest.AppWithContextMenu
--PlatformAppBrowserTest.AppWithContextMenuClicked
--PlatformAppBrowserTest.AppWithContextMenuSelection
--PlatformAppBrowserTest.AppWithContextMenuTextField
--PlatformAppBrowserTest.AppsIgnoreDefaultZoom
--PlatformAppBrowserTest.ChromeRuntimeGetPackageDirectoryEntryApp
--PlatformAppBrowserTest.ComponentAppBackgroundPage
--PlatformAppBrowserTest.ComponentReloadLoadsLazyBackgroundPage
 -PlatformAppBrowserTest.CreateAndCloseAppWindow
--PlatformAppBrowserTest.DisabledWindowProperties
 -PlatformAppBrowserTest.DisallowBackgroundPageNavigation
--PlatformAppBrowserTest.DisallowNavigation
--PlatformAppBrowserTest.DisallowStorage
--PlatformAppBrowserTest.EmptyContextMenu
--PlatformAppBrowserTest.ExtensionWindowingApis
--PlatformAppBrowserTest.FileAccessIsSavedToPrefs
--PlatformAppBrowserTest.InstalledAppWithContextMenu
--PlatformAppBrowserTest.LoadAndLaunchAppChromeRunning
--PlatformAppBrowserTest.LoadAndLaunchAppWithFile
--PlatformAppBrowserTest.Messaging
--PlatformAppBrowserTest.MutationEventsDisabled
--PlatformAppBrowserTest.OnLaunchedEvent
--PlatformAppBrowserTest.OpenLink
--PlatformAppBrowserTest.PlatformAppsOnly
--PlatformAppBrowserTest.ReinstallDataCleanup
--PlatformAppBrowserTest.ReloadRelaunches
--PlatformAppBrowserTest.Restrictions
--PlatformAppBrowserTest.WindowDotPrintShouldBringUpPrintPreview
+-PlatformAppBrowserTest.Isolation
 -PlatformAppDevToolsBrowserTest.ReOpenedWithID
 -PlatformAppDevToolsBrowserTest.ReOpenedWithURL
--PlatformAppNavigationRedirectorBrowserTest.BlankClickInAppIntercepted
--PlatformAppNavigationRedirectorBrowserTest.BlankClickInTabIntercepted
--PlatformAppNavigationRedirectorBrowserTest.ClickInTabIntercepted
--PlatformAppNavigationRedirectorBrowserTest.EntryInOmnibarIntercepted
--PlatformAppNavigationRedirectorBrowserTest.MismatchingBlankClickInAppNotIntercepted
--PlatformAppNavigationRedirectorBrowserTest.MismatchingWindowOpenInAppNotIntercepted
--PlatformAppNavigationRedirectorBrowserTest.PrerenderedClickInTabIntercepted
--PlatformAppNavigationRedirectorBrowserTest.WebviewNavigationNotIntercepted
--PlatformAppNavigationRedirectorBrowserTest.WindowOpenInAppIntercepted
--PlatformAppNavigationRedirectorBrowserTest.WindowOpenInTabIntercepted
--PlatformAppUrlRedirectorBrowserTest.BlankClickInAppIntercepted
--PlatformAppUrlRedirectorBrowserTest.BlankClickInTabIntercepted
--PlatformAppUrlRedirectorBrowserTest.ClickInTabIntercepted
--PlatformAppUrlRedirectorBrowserTest.EntryInOmnibarIntercepted
--PlatformAppUrlRedirectorBrowserTest.MismatchingBlankClickInAppNotIntercepted
--PlatformAppUrlRedirectorBrowserTest.MismatchingWindowOpenInAppNotIntercepted
--PlatformAppUrlRedirectorBrowserTest.PrerenderedClickInTabIntercepted
--PlatformAppUrlRedirectorBrowserTest.WebviewNavigationNotIntercepted
--PlatformAppUrlRedirectorBrowserTest.WindowOpenInAppIntercepted
--PlatformAppUrlRedirectorBrowserTest.WindowOpenInTabIntercepted
--PlatformAppWithFileBrowserTest.GetDisplayPath
--PlatformAppWithFileBrowserTest.LaunchNewFile
--PlatformAppWithFileBrowserTest.LaunchNoFile
--PlatformAppWithFileBrowserTest.LaunchNoType
--PlatformAppWithFileBrowserTest.LaunchWhiteListedExtensionWithFile
--PlatformAppWithFileBrowserTest.LaunchWithDirectory
--PlatformAppWithFileBrowserTest.LaunchWithFile
--PlatformAppWithFileBrowserTest.LaunchWithFileAcceptAnyExtension
--PlatformAppWithFileBrowserTest.LaunchWithFileEmptyExtension
--PlatformAppWithFileBrowserTest.LaunchWithFileEmptyExtensionAcceptAny
--PlatformAppWithFileBrowserTest.LaunchWithFileExtension
--PlatformAppWithFileBrowserTest.LaunchWithFileExtensionAndMimeType
--PlatformAppWithFileBrowserTest.LaunchWithFileWithoutExtension
--PlatformAppWithFileBrowserTest.LaunchWithFileWithoutExtensionAcceptAny
--PlatformAppWithFileBrowserTest.LaunchWithNoIntent
--PlatformAppWithFileBrowserTest.LaunchWithNothing
--PlatformAppWithFileBrowserTest.LaunchWithRelativeFile
--PlatformAppWithFileBrowserTest.LaunchWithSniffableType
--PlatformAppWithFileBrowserTest.LaunchWithWrongEmptyExtension
--PlatformAppWithFileBrowserTest.LaunchWithWrongExtension
--PlatformAppWithFileBrowserTest.LaunchWithWrongType
+-PolicyTest.BookmarkBarEnabled
+-PolicyTest.HomepageLocation
+-PPAPINaClNewlibTest.FileRef1
+-PPAPINaClNewlibTest.FileRef2
+-PPAPINaClNewlibTest.URLLoader1
+-PPAPINaClPNaClNonSfiTest.FileRef1
+# Note: the next 3 tests pass locally but fail on bot.
+-PPAPINaClPNaClNonSfiTest.FileRef2
+-PPAPINaClPNaClNonSfiTest.URLLoader1
+-PredictorBrowserTest.CrossSiteNoReferrerNoPredictionAfterOneNavigation
+-PredictorBrowserTest.CrossSiteRedirectNoPredictionWithPath
+-PredictorBrowserTest.CrossSiteRedirectPredictionWithNoPath
+-PredictorBrowserTest.CrossSiteRedirectPredictionWithNoPathDifferentHostName
 -PredictorBrowserTest.CrossSiteSimplePredictionAfterOneNavigation
+-PredictorBrowserTest.CrossSiteSimplePredictionAfterOneNavigationNoInterceptor
+-PredictorBrowserTest.CrossSiteSimplePredictionAfterTwoNavigations
+-PredictorBrowserTest.CrossSiteSimplePredictionAfterTwoNavigations2
+-PredictorBrowserTest.CrossSiteTwoRedirectsPredictionWithNoPath
+-PredictorBrowserTest.CrossSiteUseOneSocket
+-PredictorBrowserTest.CrossSiteUseThreeSockets
+-PredictorBrowserTest.DoNotEvictRecentlyUsed
 -PredictorBrowserTest.DontPredictBasedOnSubresources
+-PredictorBrowserTest.ForgetBadPrediction
+-PredictorBrowserTest.PreconnectAndFetchCORS
+-PredictorBrowserTest.PreconnectAndFetchNonCORS
 -PredictorBrowserTest.PredictBasedOnSubframeRedirect
+-PredictorBrowserTest.RendererInitiatedNavigationPreconnect
 -PredictorBrowserTest.SubframeCrossSitePrediction
 -PredictorBrowserTest.SubframeInitiatesPreconnects
 -PredictorBrowserTest.SubframeLearning
--PredictorBrowserTest.CrossSiteSimplePredictionAfterTwoNavigations
--PredictorBrowserTest.CrossSiteSimplePredictionAfterTwoNavigations2
--PredictorBrowserTest.CrossSiteRedirectPredictionWithNoPath
--PredictorBrowserTest.CrossSiteRedirectPredictionWithNoPathDifferentHostName
--PredictorBrowserTest.CrossSiteTwoRedirectsPredictionWithNoPath
--PredictorBrowserTest.RendererInitiatedNavigationPreconnect
--PreferencesPrivateApiTest.TestEasyUnlockEvent
 -PrefetchBrowserTestPredictionDisabled.ExperimentDisabled
--ProcessManagementTest.NavigateExtensionTabToWebViaPost
 -ProcessManagementTest.ProcessOverflow
 -ProcessManagerBrowserTest.ExtensionProcessReuse
 -ProcessManagerBrowserTest.NestedURLNavigationsToExtensionAllowed
--ProcessManagerBrowserTest.NestedURLNavigationsToExtensionBlocked
--ProcessManagerBrowserTest.NestedURLNavigationsViaProxyBlocked
--ProcessesApiTest.CannotTerminateBrowserProcess
--ProcessesApiTest.ProcessesApiListeners
+-ProcessMemoryMetricsEmitterTest.FetchAndEmitMetricsWithExtensions
+-ProcessMemoryMetricsEmitterTest.FetchAndEmitMetricsWithExtensionsAndHostReuse
+-ProfileWindowBrowserTest.GuestClearsCookies
 -ProxyBrowserTest.BasicAuthWSConnect
--ProxySettingsApiTest.ProxyAutoSettings
--ProxySettingsApiTest.ProxyBypass
--ProxySettingsApiTest.ProxyDirectSettings
 -ProxySettingsApiTest.ProxyEventsInvalidProxy
--ProxySettingsApiTest.ProxyEventsParseError
--ProxySettingsApiTest.ProxyFixedIndividual
--ProxySettingsApiTest.ProxyFixedIndividualIncognitoOnly
--ProxySettingsApiTest.ProxyFixedIndividualRemove
--ProxySettingsApiTest.ProxyFixedSingle
--ProxySettingsApiTest.ProxyPacData
--ProxySettingsApiTest.ProxyPacDataUrl
--ProxySettingsApiTest.ProxyPacScript
--ProxySettingsApiTest.ProxySystem
--ProxySettingsApiTest.SettingsChangeOnDisableEnable
--ProxySettingsApiTest.SettingsRemovedOnPolicyBlacklist
--ProxySettingsApiTest.SettingsRemovedOnUninstall
+-RegisterProtocolHandlerBrowserTest.CustomHandler
 -RemoteDebuggingTest.RemoteDebugger
 -RepostFormWarningTest.TestLoginAfterRepost
 -ResourcePrefetchPredictorBrowserTest.AlwaysRevalidate
@@ -1181,31 +622,42 @@
 -ResourcePrefetchPredictorBrowserTest.Redirect
 -ResourcePrefetchPredictorBrowserTest.RedirectChain
 -ResourcePrefetchPredictorBrowserTest.Simple
+-ResourcePrefetchPredictorBrowserTest.SubresourceFcpOrder
 -ResourcePrefetchPredictorBrowserTest.TabIdBehavingAsExpected
 -ResourcePrefetchPredictorPrefetchingBrowserTest.Redirect
 -ResourcePrefetchPredictorPrefetchingBrowserTest.Simple
--ResourcesPrivateApiTest.GetStrings
--RuntimeAPIUpdateTest.TerminatedExtensionUpdateHasCorrectPreviousVersion
--SSLUICaptivePortalListResourceBundleTest.Enabled
--SSLUICaptivePortalListResourceBundleTest.Enabled_AuthorityInvalid
--SSLUICaptivePortalListResourceBundleTest.Enabled_DynamicUpdate
--SSLUICaptivePortalListResourceBundleTest.Enabled_NameMismatchAndWeakKey
--SSLUIMITMSoftwareDisabledTest.DisabledWithFinch
--SSLUIMITMSoftwareEnabledTest.CertificateCommonNameMatchOnly_NoMITMSoftwareInterstitial
--SSLUIMITMSoftwareEnabledTest.CertificateOrganizationMatchOnly_NoMITMSoftwareInterstitial
--SSLUIMITMSoftwareEnabledTest.EnabledWithFinch
--SSLUIMITMSoftwareEnabledTest.EnterpriseManaged
--SSLUIMITMSoftwareEnabledTest.IgnoreDynamicUpdateWithSmallVersionId
--SSLUIMITMSoftwareEnabledTest.NonMatchingCertificate_NoMITMSoftwareInterstitial
--SSLUIMITMSoftwareEnabledTest.NotEnterpriseManaged
--SSLUIMITMSoftwareEnabledTest.OverridableError_NoMITMSoftwareInterstitial
--SSLUIMITMSoftwareEnabledTest.TwoCertErrors_NoMITMSoftwareInterstitial
--SSLUIMITMSoftwareEnabledTest.WrongCertError_NoMITMSoftwareInterstitial
+-SafeBrowsingServiceTest.Prefetch
 -SafeBrowsingTriggeredPopupBlockerBrowserTest.NoFeature_AllowCreatingNewWindows
 -SafeBrowsingTriggeredPopupBlockerBrowserTest.NoFeature_NoMessages
--SerialApiTest.SerialFakeHardware
--SerialApiTest.SerialRealHardware
--SerialApiTest.SerialRealHardwareFail
+-SBNavigationObserverBrowserTest.CompleteReferrerChain
+-SBNavigationObserverBrowserTest.DirectDownload
+-SBNavigationObserverBrowserTest.DirectDownloadNoReferrer
+-SBNavigationObserverBrowserTest.DirectDownloadNoReferrerTargetBlank
+-SBNavigationObserverBrowserTest.IPListDedup
+-SBNavigationObserverBrowserTest.MixRedirects
+-SBNavigationObserverBrowserTest.MultiMetaRefreshRedirects
+-SBNavigationObserverBrowserTest.NewTabDownload
+-SBNavigationObserverBrowserTest.NewTabDownloadWithDataURL
+-SBNavigationObserverBrowserTest.PPAPIDownloadWithoutUserGestureOnHostingFrame
+-SBNavigationObserverBrowserTest.PPAPIDownloadWithUserGestureOnHostingFrame
+-SBNavigationObserverBrowserTest.ReferrerAttributionWithinTwoUserGestures
+-SBNavigationObserverBrowserTest.RetargetingAndServerRedirect
+-SBNavigationObserverBrowserTest.ServerRedirect
+-SBNavigationObserverBrowserTest.SingleMetaRefreshRedirect
+-SBNavigationObserverBrowserTest.SingleMetaRefreshRedirectTargetBlank
+-SBNavigationObserverBrowserTest.SubFrameDirectDownload
+-SBNavigationObserverBrowserTest.SubFrameNewTabDownload
+-SBNavigationObserverBrowserTest.TwoServerRedirects
+-SBNavigationObserverBrowserTest.TypeInURLDownload
+-SBNavigationObserverBrowserTest.VerifySanitizeReferrerChain
+-SBNavigationObserverBrowserTest.WindowLocationRedirect
+-SecurityStateTabHelperTest.BrokenHTTPS
+-SecurityStateTabHelperTest.MixedContentWithSHA1Cert
+-SecurityStateTabHelperTest.PasswordSecurityLevelDowngradedOnFilesystemUrl
+-SecurityStateTabHelperTest.PasswordSecurityLevelNotDowngradedOnHttps
+-SecurityStateTabHelperTest.SHA1CertificateBlocked
+-SecurityStateTabHelperTest.SHA1CertificateWarning
+-SecurityStateTabHelperTest.UMALogsVisitsAfterWarning
 -ServiceWorkerAppTest.RegisterAndPostMessage
 -ServiceWorkerBackgroundSyncTestWithJSBindings/ServiceWorkerBackgroundSyncTest.Sync/0
 -ServiceWorkerBackgroundSyncTestWithNativeBindings/ServiceWorkerBackgroundSyncTest.Sync/0
@@ -1228,9 +680,9 @@
 -ServiceWorkerTestWithJSBindings/ServiceWorkerTest.LoadingBackgroundPageBypassesServiceWorker/0
 -ServiceWorkerTestWithJSBindings/ServiceWorkerTest.NotificationAPI/0
 -ServiceWorkerTestWithJSBindings/ServiceWorkerTest.RegisterSucceeds/0
--ServiceWorkerTestWithJSBindings/ServiceWorkerTest.SWServedBackgroundPageReceivesEvent/0
 -ServiceWorkerTestWithJSBindings/ServiceWorkerTest.ServiceWorkerPostsMessageToBackgroundClient/0
 -ServiceWorkerTestWithJSBindings/ServiceWorkerTest.ServiceWorkerSuspensionOnExtensionUnload/0
+-ServiceWorkerTestWithJSBindings/ServiceWorkerTest.SWServedBackgroundPageReceivesEvent/0
 -ServiceWorkerTestWithJSBindings/ServiceWorkerTest.TabsCreate/0
 -ServiceWorkerTestWithJSBindings/ServiceWorkerTest.UpdateRefreshesServiceWorker/0
 -ServiceWorkerTestWithJSBindings/ServiceWorkerTest.WebAccessibleResourcesFetch/0
@@ -1247,85 +699,71 @@
 -ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.LoadingBackgroundPageBypassesServiceWorker/0
 -ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.NotificationAPI/0
 -ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.RegisterSucceeds/0
--ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.SWServedBackgroundPageReceivesEvent/0
 -ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.ServiceWorkerPostsMessageToBackgroundClient/0
 -ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.ServiceWorkerSuspensionOnExtensionUnload/0
+-ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.SWServedBackgroundPageReceivesEvent/0
 -ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.TabsCreate/0
 -ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.UpdateRefreshesServiceWorker/0
 -ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.WebAccessibleResourcesFetch/0
 -ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.WebAccessibleResourcesIframeSrc/0
 -ServiceWorkerTestWithNativeBindings/ServiceWorkerTest.WorkerRefCount/0
--SetIconAPITest.Overview
--SettingsPrivateApiTest.GetAllPrefs
--SettingsPrivateApiTest.GetEnforcedPref
--SettingsPrivateApiTest.GetPref
--SettingsPrivateApiTest.GetRecommendedPref
--SettingsPrivateApiTest.OnPrefsChanged
--SettingsPrivateApiTest.SetPref
 -ShowPageActionWithoutPageActionTest/ShowPageActionWithoutPageActionTest.Test/0
 -ShowPageActionWithoutPageActionTest/ShowPageActionWithoutPageActionTest.Test/1
--SocketApiTest.SocketMulticast
--SocketApiTest.SocketTCPExtension
--SocketApiTest.SocketTCPServerExtension
--SocketApiTest.SocketTCPServerUnbindOnUnload
--SocketApiTest.SocketUDPExtension
--SpeechRecognitionTest.SpeechFromBackgroundPage
--SpeechRecognitionTest.SpeechFromBackgroundPageWithoutPermission
+-SiteDetailsBrowserTest.PlatformAppsNotIsolated
+-SSLUICaptivePortalListResourceBundleTest.Enabled
+-SSLUICaptivePortalListResourceBundleTest.Enabled_AuthorityInvalid
+-SSLUICaptivePortalListResourceBundleTest.Enabled_DynamicUpdate
+-SSLUICaptivePortalListResourceBundleTest.Enabled_NameMismatchAndWeakKey
+-SSLUIMITMSoftwareDisabledTest.DisabledWithFinch
+-SSLUIMITMSoftwareEnabledTest.CertificateCommonNameMatchOnly_NoMITMSoftwareInterstitial
+-SSLUIMITMSoftwareEnabledTest.CertificateOrganizationMatchOnly_NoMITMSoftwareInterstitial
+-SSLUIMITMSoftwareEnabledTest.EnabledWithFinch
+-SSLUIMITMSoftwareEnabledTest.EnterpriseManaged
+-SSLUIMITMSoftwareEnabledTest.IgnoreDynamicUpdateWithSmallVersionId
+-SSLUIMITMSoftwareEnabledTest.NonMatchingCertificate_NoMITMSoftwareInterstitial
+-SSLUIMITMSoftwareEnabledTest.NotEnterpriseManaged
+-SSLUIMITMSoftwareEnabledTest.OverridableError_NoMITMSoftwareInterstitial
+-SSLUIMITMSoftwareEnabledTest.TwoCertErrors_NoMITMSoftwareInterstitial
+-SSLUIMITMSoftwareEnabledTest.WrongCertError_NoMITMSoftwareInterstitial
+-SSLUITest.BadCertFollowedByGoodCert
+-SSLUITestCommittedInterstitials.ErrorPage
+-SSLUITestCommittedInterstitials.ErrorPage
+-SSLUITest.DisplayedContentWithCertErrorsClearedOnNavigation
+-SSLUITestIgnoreLocalhostCertErrors.TestNoInterstitialOnLocalhost
+-SSLUITest.TestBadHTTPSDownload
+-SSLUITest.TestHTTPSOCSPOk
+-SSLUITest.TestHTTPSOCSPRevoked
+-SSLUITest.TestUnsafeContentsWithUserException
+-SSLUITest.TestUnsafeImageWithUserException
+-SSLUIWorkerFetchTest.TestUnsafeContentsInWorkerWithUserException/0
+-SSLUIWorkerFetchTest.TestUnsafeContentsInWorkerWithUserException/1
+-SSLUIWorkerFetchTest.TestUnsafeContentsInWorkerWithUserException/2
+-SSLUIWorkerFetchTest.TestUnsafeContentsInWorkerWithUserException/3
 -StreamsPrivateApiTest.Abort
 -StreamsPrivateApiTest.FileURL
 -StreamsPrivateApiTest.Headers
 -StreamsPrivateApiTest.Navigate
+-StreamsPrivateApiTest.NavigateCrossSite
 -SubresourceFilterBrowserTest.FailedProvisionalLoadInMainframe
+-SuperfishSSLUITest.NoSuperfishRecorded
 -SuperfishSSLUITest.SuperfishInterstitial
 -SuperfishSSLUITest.SuperfishInterstitialDisabled
+-SuperfishSSLUITest.SuperfishRecorded
 -SymantecMessageSSLUITest.ManySubresources
 -SymantecMessageSSLUITest.PostJune2016
 -SymantecMessageSSLUITest.PreJune2016
 -SymantecMessageSSLUITest.Subresource
--SyncFileSystemApiTest.ConflictResolutionPolicy
--SyncFileSystemApiTest.GetServiceStatus
--SyncFileSystemApiTest.GetUsageAndQuota
--SyncFileSystemApiTest.OnFileStatusChanged
--SyncFileSystemApiTest.OnFileStatusChangedDeleted
--SyncFileSystemApiTest.OnServiceStatusChanged
--SyncFileSystemApiTest.RequestFileSystem
--SyncFileSystemApiTest.WriteFileThenGetUsage
--SyncFileSystemTest.AuthorizationTest
--TabCaptureApiPixelTest.EndToEndThroughWebRTC
--TabCaptureApiPixelTest.EndToEndWithoutRemoting
--TabCaptureApiPixelTest.OffscreenTabEndToEnd
--TabCaptureApiPixelTest.OffscreenTabEvilTests
--TabCaptureApiTest.ActiveTabPermission
--TabCaptureApiTest.ApiTests
--TabCaptureApiTest.CaptureInSplitIncognitoMode
--TabCaptureApiTest.Constraints
--TabCaptureApiTest.GetUserMediaTest
--TabCaptureApiTest.GrantForChromePages
--TabCaptureApiTest.MaxOffscreenTabs
--TabCaptureApiTest.TabIndicator
--TtsApiTest.EngineApi
--TtsApiTest.EngineWordCallbacks
--TtsApiTest.LangMatching
+-TabManagerTest.DiscardTabsWithMinimizedAndOccludedWindows
+-TaskManagerBrowserTest.SentDataObserved
+-TaskManagerBrowserTest.TotalSentDataObserved
+-TaskManagerUtilityProcessBrowserTest.UtilityJSHeapMemory
 -TtsApiTest.NetworkSpeechEngine
--TtsApiTest.NoNetworkSpeechEngineWhenOffline
--TtsApiTest.PlatformPauseResume
--TtsApiTest.PlatformPauseSpeakNoEnqueue
--TtsApiTest.PlatformSpeakEnqueue
--TtsApiTest.PlatformSpeakError
--TtsApiTest.PlatformSpeakFinishesImmediately
--TtsApiTest.PlatformSpeakInterrupt
--TtsApiTest.PlatformSpeakOptionalArgs
--TtsApiTest.PlatformSpeakQueueInterrupt
--TtsApiTest.PlatformWordCallbacks
--TtsApiTest.RegisterEngine
--WebNavigationApiTest.Api
+-V4SafeBrowsingServiceTest.Prefetch
 -WebNavigationApiTest.ClientRedirect
 -WebNavigationApiTest.Crash
 -WebNavigationApiTest.CrossProcess
 -WebNavigationApiTest.CrossProcessIframe
 -WebNavigationApiTest.Download
--WebNavigationApiTest.FilteredTest
--WebNavigationApiTest.GetFrame
 -WebNavigationApiTest.History
 -WebNavigationApiTest.IFrame
 -WebNavigationApiTest.OpenTab
@@ -1337,378 +775,70 @@
 -WebNavigationApiTest.TargetBlank
 -WebNavigationApiTest.TargetBlankIncognito
 -WebNavigationApiTest.UserAction
+-WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsEmitsGatheringStateChange
+-WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsGetStatsCallback
+-WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsGetStatsPromise
 -WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsOfferEcdsaAnswerEcdsa
+-WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsOfferEcdsaAnswerRsa
+-WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsOfferRsaAnswerEcdsa
+-WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsOfferRsaAnswerRsa
+-WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificateEcdsa
+-WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificateRsa
 -WebRtcDisableEncryptionFlagBrowserTest.VerifyEncryption
+-WebRtcEventLogApiTest.TestStartTimedWebRtcEventLogging
 -WebRtcFromWebAccessibleResourceTest.GetUserMediaInWebAccessibleResourceFail
 -WebRtcFromWebAccessibleResourceTest.GetUserMediaInWebAccessibleResourceSuccess
+-WebRtcRtpBrowserTest.AddAndRemoveTracksWithIndividualStreams
+-WebRtcRtpBrowserTest.AddAndRemoveTracksWithoutStream
+-WebRtcRtpBrowserTest.AddAndRemoveTracksWithSharedStream
 -WebRtcRtpBrowserTest.GetReceivers
+-WebRtcRtpBrowserTest.GetReceiversSetRemoteDescription
+-WebRtcRtpBrowserTest.GetSenders
+-WebRtcRtpBrowserTest.SwitchRemoteStreamAndBackAgain
+-WebRtcRtpBrowserTest.SwitchRemoteStreamWithoutWaitingForPromisesToResolve
 -WebRtcRtpBrowserTest.TrackAddedToSecondStream
 -WebRtcRtpBrowserTest.TrackSwitchingStream
 -WebSocketBrowserTest.ReuseMainPageBasicAuthCredentialsForWebSocket
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/0
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/1
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/2
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/3
--WebViewScrollGuestContent/WebViewScrollGuestContentTest.OverscrollControllerSeesConsumedScrollsInGuest/0
--WebViewTests/IsolatedOriginWebViewTest.IsolatedOriginInWebview/0
--WebViewTests/IsolatedOriginWebViewTest.IsolatedOriginInWebview/1
--WebViewTests/IsolatedOriginWebViewTest.LoadIsolatedOriginInWebviewAfterLoadingInRegularTab/0
--WebViewTests/IsolatedOriginWebViewTest.LoadIsolatedOriginInWebviewAfterLoadingInRegularTab/1
--WebViewTests/WebViewAccessibilityTest.FocusAccessibility/0
--WebViewTests/WebViewAccessibilityTest.FocusAccessibility/1
--WebViewTests/WebViewAccessibilityTest.LoadWebViewAccessibility/0
--WebViewTests/WebViewAccessibilityTest.LoadWebViewAccessibility/1
--WebViewTests/WebViewDPITest.Shim_TestAutosizeBeforeNavigation/0
--WebViewTests/WebViewDPITest.Shim_TestAutosizeBeforeNavigation/1
--WebViewTests/WebViewDPITest.Shim_TestAutosizeHeight/0
--WebViewTests/WebViewDPITest.Shim_TestAutosizeHeight/1
--WebViewTests/WebViewDPITest.Shim_TestAutosizeRemoveAttributes/0
--WebViewTests/WebViewDPITest.Shim_TestAutosizeRemoveAttributes/1
--WebViewTests/WebViewFocusTest.TouchFocusesEmbedder/0
--WebViewTests/WebViewFocusTest.TouchFocusesEmbedder/1
--WebViewTests/WebViewNewWindowTest.OpenURLFromTab_NewWindow_Abort/0
--WebViewTests/WebViewNewWindowTest.OpenURLFromTab_NewWindow_Abort/1
--WebViewTests/WebViewNewWindowTest.Shim_TestAddContentScriptsWithNewWindowAPI/0
--WebViewTests/WebViewNewWindowTest.Shim_TestAddContentScriptsWithNewWindowAPI/1
--WebViewTests/WebViewNewWindowTest.Shim_TestNewWindow/0
--WebViewTests/WebViewNewWindowTest.Shim_TestNewWindow/1
--WebViewTests/WebViewNewWindowTest.Shim_TestNewWindowNoPreventDefault/0
--WebViewTests/WebViewNewWindowTest.Shim_TestNewWindowNoPreventDefault/1
--WebViewTests/WebViewNewWindowTest.Shim_TestNewWindowNoReferrerLink/0
--WebViewTests/WebViewNewWindowTest.Shim_TestNewWindowNoReferrerLink/1
--WebViewTests/WebViewNewWindowTest.Shim_TestNewWindowTwoListeners/0
--WebViewTests/WebViewNewWindowTest.Shim_TestNewWindowTwoListeners/1
--WebViewTests/WebViewNewWindowTest.Shim_TestWebViewAndEmbedderInNewWindow/0
--WebViewTests/WebViewNewWindowTest.Shim_TestWebViewAndEmbedderInNewWindow/1
--WebViewTests/WebViewNewWindowTest.UserAgent_NewWindow/0
--WebViewTests/WebViewNewWindowTest.UserAgent_NewWindow/1
--WebViewTests/WebViewPluginTest.TestLoadPluginEvent/0
--WebViewTests/WebViewPluginTest.TestLoadPluginEvent/1
+-WebSocketBrowserTest.WebSocketAppliesHSTS
+-WebSocketBrowserTest.WebSocketBasicAuthInHTTPSURL
+-WebSocketBrowserTest.WebSocketBasicAuthInHTTPURL
+-WebstoreInstallerBrowserTest.SimultaneousInstall
 -WebViewTests/WebViewPluginTest.TestLoadPluginInternalResource/0
 -WebViewTests/WebViewPluginTest.TestLoadPluginInternalResource/1
--WebViewTests/WebViewSizeTest.AutoSize/0
--WebViewTests/WebViewSizeTest.AutoSize/1
--WebViewTests/WebViewSizeTest.Shim_TestAutosizeBeforeNavigation/0
--WebViewTests/WebViewSizeTest.Shim_TestAutosizeBeforeNavigation/1
--WebViewTests/WebViewSizeTest.Shim_TestAutosizeHeight/0
--WebViewTests/WebViewSizeTest.Shim_TestAutosizeHeight/1
--WebViewTests/WebViewSizeTest.Shim_TestAutosizeRemoveAttributes/0
--WebViewTests/WebViewSizeTest.Shim_TestAutosizeRemoveAttributes/1
--WebViewTests/WebViewSizeTest.Shim_TestResizeEvents/0
--WebViewTests/WebViewSizeTest.Shim_TestResizeEvents/1
--WebViewTests/WebViewSizeTest.Shim_TestResizeWebviewResizesContent/0
--WebViewTests/WebViewSizeTest.Shim_TestResizeWebviewResizesContent/1
--WebViewTests/WebViewSizeTest.Shim_TestResizeWebviewWithDisplayNoneResizesContent/0
--WebViewTests/WebViewSizeTest.Shim_TestResizeWebviewWithDisplayNoneResizesContent/1
--WebViewTests/WebViewSpeechAPITest.SpeechRecognitionAPI_HasPermissionAllow/0
--WebViewTests/WebViewSpeechAPITest.SpeechRecognitionAPI_HasPermissionAllow/1
--WebViewTests/WebViewSpeechAPITest.SpeechRecognitionAPI_HasPermissionDeny/0
--WebViewTests/WebViewSpeechAPITest.SpeechRecognitionAPI_HasPermissionDeny/1
--WebViewTests/WebViewSpeechAPITest.SpeechRecognitionAPI_NoPermission/0
--WebViewTests/WebViewSpeechAPITest.SpeechRecognitionAPI_NoPermission/1
--WebViewTests/WebViewTest.AcceptTouchEvents/0
--WebViewTests/WebViewTest.AddRemoveWebView_AddRemoveWebView/0
--WebViewTests/WebViewTest.AddRemoveWebView_AddRemoveWebView/1
--WebViewTests/WebViewTest.AllowTransparencyAndAllowScalingPropagate/0
--WebViewTests/WebViewTest.AllowTransparencyAndAllowScalingPropagate/1
--WebViewTests/WebViewTest.AudibilityStatePropagates/0
--WebViewTests/WebViewTest.AudibilityStatePropagates/1
--WebViewTests/WebViewTest.AudioMutesOnAttach/0
--WebViewTests/WebViewTest.AudioMutesOnAttach/1
--WebViewTests/WebViewTest.AudioMutesWhileAttached/0
--WebViewTests/WebViewTest.AudioMutesWhileAttached/1
--WebViewTests/WebViewTest.AudioStateJavascriptAPI/0
--WebViewTests/WebViewTest.AudioStateJavascriptAPI/1
--WebViewTests/WebViewTest.BasicPostMessage/0
--WebViewTests/WebViewTest.BasicPostMessage/1
--WebViewTests/WebViewTest.BlobInWebviewAccessibleResource/0
--WebViewTests/WebViewTest.BlobInWebviewAccessibleResource/1
 -WebViewTests/WebViewTest.ClearData/0
 -WebViewTests/WebViewTest.ClearData/1
 -WebViewTests/WebViewTest.ClearDataCache/0
 -WebViewTests/WebViewTest.ClearDataCache/1
--WebViewTests/WebViewTest.ClearDataTwice/0
--WebViewTests/WebViewTest.ClearDataTwice/1
 -WebViewTests/WebViewTest.ClearPersistentCookies/0
 -WebViewTests/WebViewTest.ClearPersistentCookies/1
 -WebViewTests/WebViewTest.ClearSessionCookies/0
 -WebViewTests/WebViewTest.ClearSessionCookies/1
--WebViewTests/WebViewTest.CloseOnLoadcommit/0
--WebViewTests/WebViewTest.CloseOnLoadcommit/1
--WebViewTests/WebViewTest.ConsoleMessage/0
--WebViewTests/WebViewTest.ConsoleMessage/1
--WebViewTests/WebViewTest.ContentScriptFetch/0
--WebViewTests/WebViewTest.ContentScriptFetch/1
--WebViewTests/WebViewTest.ContextMenuInspectElement/0
--WebViewTests/WebViewTest.ContextMenuInspectElement/1
--WebViewTests/WebViewTest.ContextMenuLanguageSettings/0
--WebViewTests/WebViewTest.ContextMenuLanguageSettings/1
 -WebViewTests/WebViewTest.ContextMenuNavigationInMimeHandlerView/0
 -WebViewTests/WebViewTest.ContextMenuNavigationInMimeHandlerView/1
--WebViewTests/WebViewTest.ContextMenusAPI_Basic/0
--WebViewTests/WebViewTest.ContextMenusAPI_Basic/1
--WebViewTests/WebViewTest.ContextMenusAPI_PreventDefault/0
--WebViewTests/WebViewTest.ContextMenusAPI_PreventDefault/1
 -WebViewTests/WebViewTest.CookieIsolation/0
 -WebViewTests/WebViewTest.CookieIsolation/1
--WebViewTests/WebViewTest.DOMStorageIsolation/0
--WebViewTests/WebViewTest.DOMStorageIsolation/1
--WebViewTests/WebViewTest.Dialog_TestAlertDialog/0
--WebViewTests/WebViewTest.Dialog_TestAlertDialog/1
--WebViewTests/WebViewTest.Dialog_TestConfirmDialogCancel/0
--WebViewTests/WebViewTest.Dialog_TestConfirmDialogCancel/1
--WebViewTests/WebViewTest.Dialog_TestConfirmDialogDefaultCancel/0
--WebViewTests/WebViewTest.Dialog_TestConfirmDialogDefaultCancel/1
--WebViewTests/WebViewTest.Dialog_TestConfirmDialogDefaultGCCancel/0
--WebViewTests/WebViewTest.Dialog_TestConfirmDialogDefaultGCCancel/1
--WebViewTests/WebViewTest.Dialog_TestPromptDialog/0
--WebViewTests/WebViewTest.Dialog_TestPromptDialog/1
--WebViewTests/WebViewTest.DisplayNoneSetSrc/0
--WebViewTests/WebViewTest.DisplayNoneSetSrc/1
 -WebViewTests/WebViewTest.DownloadCookieIsolation/0
 -WebViewTests/WebViewTest.DownloadCookieIsolation/1
 -WebViewTests/WebViewTest.DownloadCookieIsolation_CrossSession/0
 -WebViewTests/WebViewTest.DownloadCookieIsolation_CrossSession/1
 -WebViewTests/WebViewTest.DownloadPermission/0
 -WebViewTests/WebViewTest.DownloadPermission/1
--WebViewTests/WebViewTest.ExecuteScript/0
--WebViewTests/WebViewTest.ExecuteScript/1
--WebViewTests/WebViewTest.FileSystemAPIRequestFromMainThreadAllow/0
--WebViewTests/WebViewTest.FileSystemAPIRequestFromMainThreadAllow/1
--WebViewTests/WebViewTest.FileSystemAPIRequestFromMainThreadDefaultAllow/0
--WebViewTests/WebViewTest.FileSystemAPIRequestFromMainThreadDefaultAllow/1
--WebViewTests/WebViewTest.FileSystemAPIRequestFromMainThreadDeny/0
--WebViewTests/WebViewTest.FileSystemAPIRequestFromMainThreadDeny/1
--WebViewTests/WebViewTest.FileSystemAPIRequestFromSharedWorkerOfMultiWebViewGuestsAllow/0
--WebViewTests/WebViewTest.FileSystemAPIRequestFromSharedWorkerOfMultiWebViewGuestsAllow/1
--WebViewTests/WebViewTest.FileSystemAPIRequestFromSharedWorkerOfMultiWebViewGuestsDefaultAllow/0
--WebViewTests/WebViewTest.FileSystemAPIRequestFromSharedWorkerOfMultiWebViewGuestsDefaultAllow/1
--WebViewTests/WebViewTest.FileSystemAPIRequestFromSharedWorkerOfMultiWebViewGuestsDeny/0
--WebViewTests/WebViewTest.FileSystemAPIRequestFromSharedWorkerOfMultiWebViewGuestsDeny/1
--WebViewTests/WebViewTest.FileSystemAPIRequestFromSharedWorkerOfSingleWebViewGuestAllow/0
--WebViewTests/WebViewTest.FileSystemAPIRequestFromSharedWorkerOfSingleWebViewGuestAllow/1
--WebViewTests/WebViewTest.FileSystemAPIRequestFromSharedWorkerOfSingleWebViewGuestDefaultAllow/0
--WebViewTests/WebViewTest.FileSystemAPIRequestFromSharedWorkerOfSingleWebViewGuestDefaultAllow/1
--WebViewTests/WebViewTest.FileSystemAPIRequestFromSharedWorkerOfSingleWebViewGuestDeny/0
--WebViewTests/WebViewTest.FileSystemAPIRequestFromSharedWorkerOfSingleWebViewGuestDeny/1
--WebViewTests/WebViewTest.FileSystemAPIRequestFromWorkerAllow/0
--WebViewTests/WebViewTest.FileSystemAPIRequestFromWorkerAllow/1
--WebViewTests/WebViewTest.FileSystemAPIRequestFromWorkerDefaultAllow/0
--WebViewTests/WebViewTest.FileSystemAPIRequestFromWorkerDefaultAllow/1
--WebViewTests/WebViewTest.FileSystemAPIRequestFromWorkerDeny/0
--WebViewTests/WebViewTest.FileSystemAPIRequestFromWorkerDeny/1
--WebViewTests/WebViewTest.GeolocationAPICancelGeolocation/0
--WebViewTests/WebViewTest.GeolocationAPICancelGeolocation/1
--WebViewTests/WebViewTest.GeolocationAPIEmbedderHasAccessDeny/0
--WebViewTests/WebViewTest.GeolocationAPIEmbedderHasAccessDeny/1
--WebViewTests/WebViewTest.GeolocationAPIEmbedderHasNoAccessAllow/0
--WebViewTests/WebViewTest.GeolocationAPIEmbedderHasNoAccessAllow/1
--WebViewTests/WebViewTest.GeolocationAPIEmbedderHasNoAccessDeny/0
--WebViewTests/WebViewTest.GeolocationAPIEmbedderHasNoAccessDeny/1
--WebViewTests/WebViewTest.IndexedDBIsolation/0
--WebViewTests/WebViewTest.IndexedDBIsolation/1
--WebViewTests/WebViewTest.InterstitialPage/1
--WebViewTests/WebViewTest.InterstitialPageDetach/0
--WebViewTests/WebViewTest.InterstitialPageDetach/1
--WebViewTests/WebViewTest.InterstitialPageFocusedWidget/1
--WebViewTests/WebViewTest.InterstitialPageRouteEvents/1
--WebViewTests/WebViewTest.InterstitialTeardown/0
--WebViewTests/WebViewTest.InterstitialTeardown/1
--WebViewTests/WebViewTest.LoadWebviewAccessibleResource/0
 -WebViewTests/WebViewTest.LoadWebviewAccessibleResource/1
--WebViewTests/WebViewTest.LoadWebviewInaccessibleResource/0
--WebViewTests/WebViewTest.LoadWebviewInaccessibleResource/1
--WebViewTests/WebViewTest.LoadWebviewInsideIframe/0
--WebViewTests/WebViewTest.LoadWebviewInsideIframe/1
--WebViewTests/WebViewTest.MediaAccessAPIAllow_TestAllow/0
--WebViewTests/WebViewTest.MediaAccessAPIAllow_TestAllow/1
--WebViewTests/WebViewTest.MediaAccessAPIAllow_TestAllowAndThenDeny/0
--WebViewTests/WebViewTest.MediaAccessAPIAllow_TestAllowAndThenDeny/1
--WebViewTests/WebViewTest.MediaAccessAPIAllow_TestAllowAsync/0
--WebViewTests/WebViewTest.MediaAccessAPIAllow_TestAllowAsync/1
--WebViewTests/WebViewTest.MediaAccessAPIAllow_TestAllowTwice/0
--WebViewTests/WebViewTest.MediaAccessAPIAllow_TestAllowTwice/1
--WebViewTests/WebViewTest.MediaAccessAPIAllow_TestCheck/0
--WebViewTests/WebViewTest.MediaAccessAPIAllow_TestCheck/1
--WebViewTests/WebViewTest.MediaAccessAPIDeny_TestDeny/0
--WebViewTests/WebViewTest.MediaAccessAPIDeny_TestDeny/1
--WebViewTests/WebViewTest.MediaAccessAPIDeny_TestDenyThenAllowThrows/0
--WebViewTests/WebViewTest.MediaAccessAPIDeny_TestDenyThenAllowThrows/1
--WebViewTests/WebViewTest.MediaAccessAPIDeny_TestDenyWithPreventDefault/0
--WebViewTests/WebViewTest.MediaAccessAPIDeny_TestDenyWithPreventDefault/1
--WebViewTests/WebViewTest.MediaAccessAPIDeny_TestNoListenersImplyDeny/0
--WebViewTests/WebViewTest.MediaAccessAPIDeny_TestNoListenersImplyDeny/1
--WebViewTests/WebViewTest.MediaAccessAPIDeny_TestNoPreventDefaultImpliesDeny/0
--WebViewTests/WebViewTest.MediaAccessAPIDeny_TestNoPreventDefaultImpliesDeny/1
 -WebViewTests/WebViewTest.NestedGuestContainerBounds/0
--WebViewTests/WebViewTest.NoContentSettingsAPI/0
--WebViewTests/WebViewTest.NoContentSettingsAPI/1
--WebViewTests/WebViewTest.NoPermission/0
--WebViewTests/WebViewTest.NoPermission/1
--WebViewTests/WebViewTest.NoPrerenderer/0
--WebViewTests/WebViewTest.NoPrerenderer/1
--WebViewTests/WebViewTest.OpenURLFromTab_CurrentTab_Abort/0
--WebViewTests/WebViewTest.OpenURLFromTab_CurrentTab_Abort/1
 -WebViewTests/WebViewTest.OpenURLFromTab_CurrentTab_Succeed/0
 -WebViewTests/WebViewTest.OpenURLFromTab_CurrentTab_Succeed/1
--WebViewTests/WebViewTest.ReloadAfterCrash/0
--WebViewTests/WebViewTest.ReloadAfterCrash/1
--WebViewTests/WebViewTest.ReloadEmbedder/0
--WebViewTests/WebViewTest.ReloadEmbedder/1
--WebViewTests/WebViewTest.ReloadWebviewAccessibleResource/0
--WebViewTests/WebViewTest.ReloadWebviewAccessibleResource/1
--WebViewTests/WebViewTest.ScreenCoordinates/0
--WebViewTests/WebViewTest.ScreenCoordinates/1
--WebViewTests/WebViewTest.SelectShowHide/0
--WebViewTests/WebViewTest.SelectShowHide/1
--WebViewTests/WebViewTest.SendMessageToComponentExtensionFromGuest/0
--WebViewTests/WebViewTest.SendMessageToComponentExtensionFromGuest/1
--WebViewTests/WebViewTest.SendMessageToExtensionFromGuest/0
--WebViewTests/WebViewTest.SendMessageToExtensionFromGuest/1
--WebViewTests/WebViewTest.SetPropertyOnDocumentInteractive/0
--WebViewTests/WebViewTest.SetPropertyOnDocumentInteractive/1
--WebViewTests/WebViewTest.SetPropertyOnDocumentReady/0
--WebViewTests/WebViewTest.SetPropertyOnDocumentReady/1
--WebViewTests/WebViewTest.ShimSrcAttribute/0
--WebViewTests/WebViewTest.ShimSrcAttribute/1
--WebViewTests/WebViewTest.Shim_TestAPIMethodExistence/0
--WebViewTests/WebViewTest.Shim_TestAPIMethodExistence/1
--WebViewTests/WebViewTest.Shim_TestAddAndRemoveContentScripts/0
--WebViewTests/WebViewTest.Shim_TestAddAndRemoveContentScripts/1
--WebViewTests/WebViewTest.Shim_TestAddContentScript/0
--WebViewTests/WebViewTest.Shim_TestAddContentScript/1
--WebViewTests/WebViewTest.Shim_TestAddContentScriptToOneWebViewShouldNotInjectToTheOtherWebView/0
--WebViewTests/WebViewTest.Shim_TestAddContentScriptToOneWebViewShouldNotInjectToTheOtherWebView/1
--WebViewTests/WebViewTest.Shim_TestAddContentScriptWithCode/0
--WebViewTests/WebViewTest.Shim_TestAddContentScriptWithCode/1
--WebViewTests/WebViewTest.Shim_TestAddContentScriptWithSameNameShouldOverwriteTheExistingOne/0
--WebViewTests/WebViewTest.Shim_TestAddContentScriptWithSameNameShouldOverwriteTheExistingOne/1
--WebViewTests/WebViewTest.Shim_TestAddMultipleContentScripts/0
--WebViewTests/WebViewTest.Shim_TestAddMultipleContentScripts/1
--WebViewTests/WebViewTest.Shim_TestAddMultipleContentScriptsWithCodeAndCheckGeneratedScriptUrl/0
--WebViewTests/WebViewTest.Shim_TestAddMultipleContentScriptsWithCodeAndCheckGeneratedScriptUrl/1
--WebViewTests/WebViewTest.Shim_TestAllowTransparencyAttribute/0
--WebViewTests/WebViewTest.Shim_TestAllowTransparencyAttribute/1
--WebViewTests/WebViewTest.Shim_TestAssignSrcAfterCrash/0
--WebViewTests/WebViewTest.Shim_TestAssignSrcAfterCrash/1
--WebViewTests/WebViewTest.Shim_TestBlobURL/0
--WebViewTests/WebViewTest.Shim_TestBlobURL/1
--WebViewTests/WebViewTest.Shim_TestCannotMutateEventName/0
--WebViewTests/WebViewTest.Shim_TestCannotMutateEventName/1
--WebViewTests/WebViewTest.Shim_TestChromeExtensionRelativePath/0
--WebViewTests/WebViewTest.Shim_TestChromeExtensionRelativePath/1
--WebViewTests/WebViewTest.Shim_TestChromeExtensionURL/0
--WebViewTests/WebViewTest.Shim_TestChromeExtensionURL/1
--WebViewTests/WebViewTest.Shim_TestCloseNewWindowCleanup/0
--WebViewTests/WebViewTest.Shim_TestCloseNewWindowCleanup/1
--WebViewTests/WebViewTest.Shim_TestContentInitiatedNavigationToDataUrlBlocked/0
--WebViewTests/WebViewTest.Shim_TestContentInitiatedNavigationToDataUrlBlocked/1
--WebViewTests/WebViewTest.Shim_TestContentLoadEvent/0
--WebViewTests/WebViewTest.Shim_TestContentLoadEvent/1
--WebViewTests/WebViewTest.Shim_TestContentLoadEventWithDisplayNone/0
--WebViewTests/WebViewTest.Shim_TestContentLoadEventWithDisplayNone/1
--WebViewTests/WebViewTest.Shim_TestContentScriptExistsAsLongAsWebViewTagExists/0
--WebViewTests/WebViewTest.Shim_TestContentScriptExistsAsLongAsWebViewTagExists/1
--WebViewTests/WebViewTest.Shim_TestContentScriptIsInjectedAfterTerminateAndReloadWebView/0
--WebViewTests/WebViewTest.Shim_TestContentScriptIsInjectedAfterTerminateAndReloadWebView/1
 -WebViewTests/WebViewTest.Shim_TestDeclarativeWebRequestAPI/0
 -WebViewTests/WebViewTest.Shim_TestDeclarativeWebRequestAPI/1
 -WebViewTests/WebViewTest.Shim_TestDeclarativeWebRequestAPISendMessage/0
 -WebViewTests/WebViewTest.Shim_TestDeclarativeWebRequestAPISendMessage/1
 -WebViewTests/WebViewTest.Shim_TestDeclarativeWebRequestAPISendMessageSecondWebView/0
 -WebViewTests/WebViewTest.Shim_TestDeclarativeWebRequestAPISendMessageSecondWebView/1
--WebViewTests/WebViewTest.Shim_TestDestroyOnEventListener/0
--WebViewTests/WebViewTest.Shim_TestDestroyOnEventListener/1
--WebViewTests/WebViewTest.Shim_TestDisabledZoomMode/0
--WebViewTests/WebViewTest.Shim_TestDisabledZoomMode/1
--WebViewTests/WebViewTest.Shim_TestDisplayBlock/0
--WebViewTests/WebViewTest.Shim_TestDisplayBlock/1
--WebViewTests/WebViewTest.Shim_TestDisplayNoneWebviewLoad/0
--WebViewTests/WebViewTest.Shim_TestDisplayNoneWebviewLoad/1
--WebViewTests/WebViewTest.Shim_TestDisplayNoneWebviewRemoveChild/0
--WebViewTests/WebViewTest.Shim_TestDisplayNoneWebviewRemoveChild/1
--WebViewTests/WebViewTest.Shim_TestEventName/0
--WebViewTests/WebViewTest.Shim_TestEventName/1
--WebViewTests/WebViewTest.Shim_TestExecuteScript/0
--WebViewTests/WebViewTest.Shim_TestExecuteScript/1
--WebViewTests/WebViewTest.Shim_TestExecuteScriptFail/0
--WebViewTests/WebViewTest.Shim_TestExecuteScriptFail/1
--WebViewTests/WebViewTest.Shim_TestExecuteScriptIsAbortedWhenWebViewSourceIsInvalid/0
--WebViewTests/WebViewTest.Shim_TestExecuteScriptIsAbortedWhenWebViewSourceIsInvalid/1
--WebViewTests/WebViewTest.Shim_TestFindAPI/0
--WebViewTests/WebViewTest.Shim_TestFindAPI/1
--WebViewTests/WebViewTest.Shim_TestFindAPI_findupdate/0
--WebViewTests/WebViewTest.Shim_TestFindAPI_findupdate/1
--WebViewTests/WebViewTest.Shim_TestFocusWhileFocused/0
--WebViewTests/WebViewTest.Shim_TestFocusWhileFocused/1
--WebViewTests/WebViewTest.Shim_TestGarbageCollect/0
--WebViewTests/WebViewTest.Shim_TestGarbageCollect/1
--WebViewTests/WebViewTest.Shim_TestGetProcessId/0
--WebViewTests/WebViewTest.Shim_TestGetProcessId/1
--WebViewTests/WebViewTest.Shim_TestInlineScriptFromAccessibleResources/0
--WebViewTests/WebViewTest.Shim_TestInlineScriptFromAccessibleResources/1
--WebViewTests/WebViewTest.Shim_TestInvalidChromeExtensionURL/0
--WebViewTests/WebViewTest.Shim_TestInvalidChromeExtensionURL/1
--WebViewTests/WebViewTest.Shim_TestLoadAbortChromeExtensionURLWrongPartition/0
--WebViewTests/WebViewTest.Shim_TestLoadAbortChromeExtensionURLWrongPartition/1
--WebViewTests/WebViewTest.Shim_TestLoadAbortEmptyResponse/0
--WebViewTests/WebViewTest.Shim_TestLoadAbortEmptyResponse/1
--WebViewTests/WebViewTest.Shim_TestLoadAbortIllegalChromeURL/0
--WebViewTests/WebViewTest.Shim_TestLoadAbortIllegalChromeURL/1
--WebViewTests/WebViewTest.Shim_TestLoadAbortIllegalFileURL/0
--WebViewTests/WebViewTest.Shim_TestLoadAbortIllegalFileURL/1
--WebViewTests/WebViewTest.Shim_TestLoadAbortIllegalJavaScriptURL/0
--WebViewTests/WebViewTest.Shim_TestLoadAbortIllegalJavaScriptURL/1
--WebViewTests/WebViewTest.Shim_TestLoadAbortInvalidNavigation/0
--WebViewTests/WebViewTest.Shim_TestLoadAbortInvalidNavigation/1
--WebViewTests/WebViewTest.Shim_TestLoadAbortNonWebSafeScheme/0
--WebViewTests/WebViewTest.Shim_TestLoadAbortNonWebSafeScheme/1
--WebViewTests/WebViewTest.Shim_TestLoadDataAPI/0
--WebViewTests/WebViewTest.Shim_TestLoadDataAPI/1
--WebViewTests/WebViewTest.Shim_TestLoadProgressEvent/0
--WebViewTests/WebViewTest.Shim_TestLoadProgressEvent/1
 -WebViewTests/WebViewTest.Shim_TestLoadStartLoadRedirect/0
 -WebViewTests/WebViewTest.Shim_TestLoadStartLoadRedirect/1
--WebViewTests/WebViewTest.Shim_TestMailtoLink/0
--WebViewTests/WebViewTest.Shim_TestMailtoLink/1
--WebViewTests/WebViewTest.Shim_TestNavOnConsecutiveSrcAttributeChanges/0
--WebViewTests/WebViewTest.Shim_TestNavOnConsecutiveSrcAttributeChanges/1
--WebViewTests/WebViewTest.Shim_TestNavOnSrcAttributeChange/0
--WebViewTests/WebViewTest.Shim_TestNavOnSrcAttributeChange/1
--WebViewTests/WebViewTest.Shim_TestNavigateAfterResize/0
--WebViewTests/WebViewTest.Shim_TestNavigateAfterResize/1
 -WebViewTests/WebViewTest.Shim_TestNavigationToExternalProtocol/0
 -WebViewTests/WebViewTest.Shim_TestNavigationToExternalProtocol/1
--WebViewTests/WebViewTest.Shim_TestNestedCrossOriginSubframes/0
--WebViewTests/WebViewTest.Shim_TestNestedCrossOriginSubframes/1
 -WebViewTests/WebViewTest.Shim_TestNestedSubframes/0
 -WebViewTests/WebViewTest.Shim_TestNestedSubframes/1
--WebViewTests/WebViewTest.Shim_TestOnEventProperty/0
--WebViewTests/WebViewTest.Shim_TestOnEventProperty/1
--WebViewTests/WebViewTest.Shim_TestPartitionChangeAfterNavigation/0
--WebViewTests/WebViewTest.Shim_TestPartitionChangeAfterNavigation/1
--WebViewTests/WebViewTest.Shim_TestPartitionRemovalAfterNavigationFails/0
--WebViewTests/WebViewTest.Shim_TestPartitionRemovalAfterNavigationFails/1
--WebViewTests/WebViewTest.Shim_TestPerOriginZoomMode/0
--WebViewTests/WebViewTest.Shim_TestPerOriginZoomMode/1
--WebViewTests/WebViewTest.Shim_TestPerViewZoomMode/0
--WebViewTests/WebViewTest.Shim_TestPerViewZoomMode/1
--WebViewTests/WebViewTest.Shim_TestReassignSrcAttribute/0
--WebViewTests/WebViewTest.Shim_TestReassignSrcAttribute/1
--WebViewTests/WebViewTest.Shim_TestReload/0
--WebViewTests/WebViewTest.Shim_TestReload/1
--WebViewTests/WebViewTest.Shim_TestReloadAfterTerminate/0
--WebViewTests/WebViewTest.Shim_TestReloadAfterTerminate/1
--WebViewTests/WebViewTest.Shim_TestRemoveSrcAttribute/0
--WebViewTests/WebViewTest.Shim_TestRemoveSrcAttribute/1
--WebViewTests/WebViewTest.Shim_TestRemoveWebviewAfterNavigation/0
--WebViewTests/WebViewTest.Shim_TestRemoveWebviewAfterNavigation/1
--WebViewTests/WebViewTest.Shim_TestRemoveWebviewOnExit/0
--WebViewTests/WebViewTest.Shim_TestRemoveWebviewOnExit/1
--WebViewTests/WebViewTest.Shim_TestRendererNavigationRedirectWhileUnattached/0
--WebViewTests/WebViewTest.Shim_TestRendererNavigationRedirectWhileUnattached/1
--WebViewTests/WebViewTest.Shim_TestTerminateAfterExit/0
--WebViewTests/WebViewTest.Shim_TestTerminateAfterExit/1
 -WebViewTests/WebViewTest.Shim_TestWebRequestAPI/0
 -WebViewTests/WebViewTest.Shim_TestWebRequestAPI/1
 -WebViewTests/WebViewTest.Shim_TestWebRequestAPIAddListener/0
@@ -1725,348 +855,12 @@
 -WebViewTests/WebViewTest.Shim_TestWebRequestAPIWithHeaders/1
 -WebViewTests/WebViewTest.Shim_TestWebRequestListenerSurvivesReparenting/0
 -WebViewTests/WebViewTest.Shim_TestWebRequestListenerSurvivesReparenting/1
--WebViewTests/WebViewTest.Shim_TestWebViewInsideFrame/0
--WebViewTests/WebViewTest.Shim_TestWebViewInsideFrame/1
--WebViewTests/WebViewTest.Shim_TestZoomAPI/0
--WebViewTests/WebViewTest.Shim_TestZoomAPI/1
--WebViewTests/WebViewTest.Shim_TestZoomBeforeNavigation/0
--WebViewTests/WebViewTest.Shim_TestZoomBeforeNavigation/1
 -WebViewTests/WebViewTest.Shim_WebViewWebRequestRegistryHasNoCache/0
 -WebViewTests/WebViewTest.Shim_WebViewWebRequestRegistryHasNoCache/1
--WebViewTests/WebViewTest.Shim_testFindInMultipleWebViews/0
--WebViewTests/WebViewTest.Shim_testFindInMultipleWebViews/1
 -WebViewTests/WebViewTest.StoragePersistence/0
 -WebViewTests/WebViewTest.StoragePersistence/1
--WebViewTests/WebViewTest.TaskManagerExistingWebView/0
--WebViewTests/WebViewTest.TaskManagerExistingWebView/1
--WebViewTests/WebViewTest.TaskManagerNewWebView/0
--WebViewTests/WebViewTest.TaskManagerNewWebView/1
--WebViewTests/WebViewTest.TearDownTest/0
--WebViewTests/WebViewTest.TearDownTest/1
--WebViewTests/WebViewTest.TestConfirmDialog/0
--WebViewTests/WebViewTest.TestConfirmDialog/1
--WebViewTests/WebViewTest.TestContextMenu/0
--WebViewTests/WebViewTest.TestContextMenu/1
--WebViewTests/WebViewTest.TestPlugin/0
--WebViewTests/WebViewTest.TestPlugin/1
--WebViewTests/WebViewTest.UserAgent/0
--WebViewTests/WebViewTest.UserAgent/1
 -WebViewTests/WebViewTest.WebViewInBackgroundPage/0
 -WebViewTests/WebViewTest.WebViewInBackgroundPage/1
--WebViewTests/WebViewTest.WhitelistedContentScript/0
--WebViewTests/WebViewTest.WhitelistedContentScript/1
--WebViewTests/WebViewVisibilityTest.EmbedderVisibilityChanged/0
--WebViewTests/WebViewVisibilityTest.EmbedderVisibilityChanged/1
--WebViewTests/WebViewVisibilityTest.GuestVisibilityChanged/0
--WebViewTests/WebViewVisibilityTest.GuestVisibilityChanged/1
--WebViewTests/WebViewVisibilityTest.Shim_TestHiddenBeforeNavigation/0
--WebViewTests/WebViewVisibilityTest.Shim_TestHiddenBeforeNavigation/1
--WebrtcAudioPrivateTest.TriggerEvent
--WebstoreInstallerBrowserTest.SimultaneousInstall
--WindowOpenApiTest.WindowArgumentsOverflow
--WindowOpenApiTest.WindowOpenSized
-
-# Failed tests that haven't been categorized.
--AdsPageLoadMetricsObserverBrowserTest.DocOverwritesNavigation
--AdsPageLoadMetricsObserverBrowserTest.SubresourceFilter
--BrowserNavigatorTest.CloseSingletonTab
--BrowserNavigatorTest.Disposition_CurrentTab
--BrowserNavigatorTest.NavigateFromPageToOptionsInNewTab
-# note: this passes locally but fails on bot.
--BrowserNonClientFrameViewBrowserTest.InactiveSeparatorColor
--BrowserTest.ClearPendingOnFailUnlessNTP
--BrowserTest.GetSizeForNewRenderView
--BrowsingDataRemoverBrowserTest.Cache
--BrowsingDataRemoverTransportSecurityStateBrowserTest.ClearTransportSecurityState
--CaptivePortalBrowserTest.RequestFailsFastTimout
--CertVerifierBrowserTest.MockCertVerifierSmokeTest
--ChromeResourceDispatcherHostDelegateBrowserTest.PolicyHeader
--ChromeResourceDispatcherHostDelegateBrowserTest.PolicyHeaderForRedirect
--ChromeResourceDispatcherHostDelegateBrowserTest.ThrottlesAddedExactlyOnceToADownloads
--ChromeResourceDispatcherHostDelegateBrowserTest.ThrottlesAddedExactlyOnceToLargeSniffedDownloads
--ChromeResourceDispatcherHostDelegateBrowserTest.ThrottlesAddedExactlyOnceToTinySniffedDownloads
--ChromeSecurityExploitBrowserTest.CreateFilesystemURLInExtensionOrigin
--ChromeServiceWorkerFetchPPAPIPrivateTest.OtherOrigin
--ChromeServiceWorkerFetchPPAPIPrivateTest.OtherOriginCORS
--ChromeServiceWorkerFetchPPAPIPrivateTest.OtherOriginCORSCredentials
--ChromeServiceWorkerFetchPPAPIPrivateTest.OtherOriginCredentials
--ChromeServiceWorkerFetchPPAPIPrivateTest.SameOrigin
--ChromeServiceWorkerFetchPPAPIPrivateTest.SameOriginCORS
--ChromeServiceWorkerFetchPPAPIPrivateTest.SameOriginCORSCredentials
--ChromeServiceWorkerFetchPPAPIPrivateTest.SameOriginCredentials
--ChromeServiceWorkerFetchPPAPITest.SameOrigin
--ContentFaviconDriverTest.ReloadBypassingCache
--CookiePolicyBrowserTest.AllowFirstPartyCookies
--CookiePolicyBrowserTest.AllowFirstPartyCookiesRedirect
--CrExtensionsCodeSectionTest.Layout
--CrExtensionsDetailViewTest.ClickableElements
--CrExtensionsDetailViewTest.IndicatorTest
--CrExtensionsDetailViewTest.Layout
--CrExtensionsDetailViewTest.Warnings
--CrExtensionsErrorPageTest.CodeSection
--CrExtensionsErrorPageTest.ErrorSelection
--CrExtensionsErrorPageTest.Layout
--CrExtensionsItemListTest.Filtering
--CrExtensionsItemListTest.NoItems
--CrExtensionsItemListTest.NoSearchResults
--CrExtensionsItemsTest.ClickableItems
--CrExtensionsItemsTest.DeveloperState
--CrExtensionsItemsTest.EnableToggle
--CrExtensionsItemsTest.NormalState
--CrExtensionsItemsTest.RemoveButton
--CrExtensionsItemsTest.SourceIndicator
--CrExtensionsItemsTest.Warnings
--CrExtensionsLoadErrorTest.CodeSection
--CrExtensionsLoadErrorTest.Interaction
--CrExtensionsManagerTestWithIdQueryParam.NavigationToDetails
--CrExtensionsManagerTestWithMultipleExtensionTypesInstalled.ChangePages
--CrExtensionsManagerTestWithMultipleExtensionTypesInstalled.ItemListVisibility
--CrExtensionsManagerTestWithMultipleExtensionTypesInstalled.SplitItems
--CrExtensionsManagerTest.ItemOrder
--CrExtensionsManagerTest.UpdateItemData
--CrExtensionsNavigationHelperTest.Basic
--CrExtensionsNavigationHelperTest.Conversion
--CrExtensionsNavigationHelperTest.PushAndReplaceState
--CrExtensionsNavigationHelperTest.SupportedRoutes
--CrExtensionsOptionsDialogTest.Layout
--CrExtensionsPackDialogTest.Interaction
--CrExtensionsPackDialogTest.PackError
--CrExtensionsPackDialogTest.PackSuccess
--CrExtensionsPackDialogTest.PackWarning
--CrExtensionsServiceTest.ProfileSettings
--CrExtensionsServiceTest.ToggleEnable
--CrExtensionsServiceTest.ToggleIncognito
--CrExtensionsServiceTest.Uninstall
--CrExtensionsSidebarTest.LayoutAndClickHandlers
--CrExtensionsSidebarTest.SetSelected
--CrExtensionsShortcutTest.Basic
--CrExtensionsShortcutTest.Layout
--CrExtensionsToggleRowTest.ToggleRowTest
--CrExtensionsToolbarTest.ClickHandlers
--CrExtensionsToolbarTest.Layout
--CrExtensionsViewManagerTest.EventFiringTest
--CrExtensionsViewManagerTest.VisibilityTest
--CredentialManagerBrowserTest.StoreInUnloadHandler_SameSite_OnDemandMojoPipe
--DataProxyScriptBrowserTest.Verify
--DeclarativeNetRequestBrowserTest.*
--DeclarativeNetRequestBrowserTest_Packed.BrowserRestart/0
--DevToolsExperimentalExtensionTest.TestDevToolsExperimentalExtensionAPI
--DevToolsExtensionTest.TestDevToolsExtensionAPI
--DevToolsExtensionTest.TestDevToolsExtensionMessaging
--DevToolsSanityTest.TestRawHeadersWithRedirectAndHSTS
--DeveloperPrivateApiTest.InspectAppWindowView
--DeveloperPrivateApiTest.InspectEmbeddedOptionsPage
--DoNotTrackTest.Redirect
--DoNotTrackTest.Simple
--DownloadExtensionTest.DownloadExtensionTest_Download_Basic
--DownloadExtensionTest.DownloadExtensionTest_Download_Redirect
--ExtensionApiTestWithManagementPolicy.UrlProtectedByPolicy
--ExtensionBrowserTest.NavigateToInaccessibleResourceFromChromeURL
--ExtensionBrowserTest.RSSParseFeedInvalidFeed1
--ExtensionBrowserTest.RSSParseFeedInvalidFeed2
--ExtensionBrowserTest.RSSParseFeedInvalidFeed3
--ExtensionBrowserTest.RSSParseFeedInvalidFeed4
--ExtensionContextMenuBrowserLazyTest.EventPage
--ExtensionFetchTest.ExtensionCanFetchHostedResourceWithHostPermissions
--ExtensionFetchTest.HostCanFetchWebAccessibleExtensionResource
--ExtensionIconSourceTest.IconsLoaded
--ExtensionIconSourceTest.IconsLoadedIncognito
--ExtensionLoadingTest.KeepAliveWithDevToolsOpenOnReload
--ExtensionResourceRequestPolicyTest.OriginPrivileges
--ExtensionResourceRequestPolicyTest.WebAccessibleResources
--ExtensionResourceRequestPolicyTest.WebAccessibleResourcesWithCSP
--ExtensionTabUtilBrowserTest.OpenExtensionsOptionsPage
--ExtensionTabUtilBrowserTest.OpenSpanningModeExtensionOptionsPageIncognito
--ExtensionTabUtilBrowserTest.OpenSplitModeExtensionOptionsPageIncognito
--ExtensionURLRewriteBrowserTest.BookmarksURLOverride
--ExtensionURLRewriteBrowserTest.NewTabPageURLOverride
--ExtensionUnloadBrowserTest.UnloadWithContentScripts
--ExternallyConnectableMessagingTest.EnablingAndDisabling
--ExternallyConnectableMessagingTest.FromIframeWithPermission
--ExternallyConnectableMessagingTest.FromIframeWithoutPermission
--ExternallyConnectableMessagingTest.FromIncognitoAllowApp
--ExternallyConnectableMessagingTest.FromIncognitoAllowExtension
--ExternallyConnectableMessagingTest.FromIncognitoDenyApp
--ExternallyConnectableMessagingTest.FromIncognitoDenyExtensionAndApp
--ExternallyConnectableMessagingTest.FromIncognitoPromptApp
--ExternallyConnectableMessagingTest.FromPopup
--ExternallyConnectableMessagingTest.HostedAppOnWebsite
--ExternallyConnectableMessagingTest.WebConnectableAndNotConnectable
--FeedbackTest.AnonymousUser
--FeedbackTest.ExtraDiagnostics
--FeedbackTest.ShowFeedback
--FeedbackTest.ShowLoginFeedback
--FileProxyScriptBrowserTest.Verify
--FlashEmbeds/ChromeContentRendererClientBrowserTest.RewriteYouTubeFlashEmbedObject/0
--FlashEmbeds/ChromeContentRendererClientBrowserTest.RewriteYouTubeFlashEmbedObject/1
--FtpProxyScriptBrowserTest.Verify
--HttpProxyScriptBrowserTest.Verify
--InProcessBrowserTest.ExternalConnectionFail
--InstantThemeTest.ThemeBackgroundAccess
--IsolatedAppTest.CookieIsolation
--JavaScriptBindings/ExternallyConnectableMessagingTest.EnablingAndDisabling/0
--JavaScriptBindings/ExternallyConnectableMessagingTest.FromIframeWithPermission/0
--JavaScriptBindings/ExternallyConnectableMessagingTest.FromIframeWithoutPermission/0
--JavaScriptBindings/ExternallyConnectableMessagingTest.FromIncognitoAllowApp/0
--JavaScriptBindings/ExternallyConnectableMessagingTest.FromIncognitoAllowExtension/0
--JavaScriptBindings/ExternallyConnectableMessagingTest.FromIncognitoDenyApp/0
--JavaScriptBindings/ExternallyConnectableMessagingTest.FromIncognitoDenyExtensionAndApp/0
--JavaScriptBindings/ExternallyConnectableMessagingTest.FromIncognitoPromptApp/0
--JavaScriptBindings/ExternallyConnectableMessagingTest.FromPopup/0
--JavaScriptBindings/ExternallyConnectableMessagingTest.HostedAppOnWebsite/0
--JavaScriptBindings/ExternallyConnectableMessagingTest.WebConnectableAndNotConnectable/0
--LazyBackgroundPageApiTest.OnUnload
--LocalNTPJavascriptTest.SimpleJavascriptTests
--LocalNTPVoiceJavascriptTest.MicrophoneTests
--LocalNTPVoiceJavascriptTest.SpeechTests
--LocalNTPVoiceJavascriptTest.TextTests
--LocalNTPVoiceJavascriptTest.ViewTests
--MediaStreamDevicesControllerTest.ExtensionRequestMicCam
--NativeBindings/ExternallyConnectableMessagingTest.EnablingAndDisabling/0
--NativeBindings/ExternallyConnectableMessagingTest.FromIframeWithPermission/0
--NativeBindings/ExternallyConnectableMessagingTest.FromIframeWithoutPermission/0
--NativeBindings/ExternallyConnectableMessagingTest.FromIncognitoAllowApp/0
--NativeBindings/ExternallyConnectableMessagingTest.FromIncognitoAllowExtension/0
--NativeBindings/ExternallyConnectableMessagingTest.FromIncognitoDenyApp/0
--NativeBindings/ExternallyConnectableMessagingTest.FromIncognitoDenyExtensionAndApp/0
--NativeBindings/ExternallyConnectableMessagingTest.FromIncognitoPromptApp/0
--NativeBindings/ExternallyConnectableMessagingTest.FromPopup/0
--NativeBindings/ExternallyConnectableMessagingTest.HostedAppOnWebsite/0
--NativeBindings/ExternallyConnectableMessagingTest.WebConnectableAndNotConnectable/0
--NativeBindingsApiTest.LazyListeners
--NewTabPageInterceptorTest.204Interception
--NewTabPageInterceptorTest.404Interception
--NewTabPageInterceptorTest.FailedRequestInterception
--NewTabPageInterceptorTest.NoInterception
--NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchHistograms/0
--NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchHistograms/1
--OutOfProcessPPAPITest.FileRef1
--OutOfProcessPPAPITest.FileRef2
--OutOfProcessPPAPITest.URLLoader1
--OutOfProcessProxyResolverBrowserTest.Verify
--PKPModelClientTest.PKPBypass
--PKPModelClientTest.PKPEnforced
--PPAPINaClNewlibTest.FileRef1
--PPAPINaClNewlibTest.FileRef2
--PPAPINaClNewlibTest.URLLoader1
-# Note: the next 3 tests pass locally but fail on bot.
--PPAPINaClPNaClNonSfiTest.FileRef1
--PPAPINaClPNaClNonSfiTest.FileRef2
--PPAPINaClPNaClNonSfiTest.URLLoader1
--PageLoadMetricsBrowserTest.ChromeErrorPage
--PageLoadMetricsBrowserTest.PayloadSize
--PageLoadMetricsBrowserTest.PayloadSizeChildFrame
--PaymentRequestInitiatedCompletionStatusMetricsTest.Aborted_NotShown
--PaymentRequestWebContentsManagerTest.MultipleRequests
--PlatformAppBrowserTest.Isolation
--PlatformAppBrowserTest.RunningAppsAreRecorded
--PolicyTest.BookmarkBarEnabled
--PolicyTest.HomepageLocation
--PredictorBrowserTest.CrossSiteNoReferrerNoPredictionAfterOneNavigation
--PredictorBrowserTest.CrossSiteRedirectNoPredictionWithPath
--PredictorBrowserTest.CrossSiteSimplePredictionAfterOneNavigationNoInterceptor
--PredictorBrowserTest.CrossSiteUseOneSocket
--PredictorBrowserTest.CrossSiteUseThreeSockets
--PredictorBrowserTest.DoNotEvictRecentlyUsed
--PredictorBrowserTest.ForgetBadPrediction
--PredictorBrowserTest.PreconnectAndFetchCORS
--PredictorBrowserTest.PreconnectAndFetchNonCORS
--ProcessManagerBrowserTest.ExtensionFrameNavigatesToParentSiteInstance
--ProcessManagerBrowserTest.ExtensionHostCreation
--ProcessManagerBrowserTest.HostedAppFilesAccess
--ProcessManagerBrowserTest.HttpHostMatchingExtensionId
--ProcessManagerBrowserTest.KeepaliveOnNetworkRequest
--ProcessManagerBrowserTest.NoBackgroundPage
--ProcessManagerBrowserTest.WebPopupFromExtensionMainFrameHasValidOpener
--ProcessManagerBrowserTest.WebPopupFromExtensionSubframeHasValidOpener
--ProcessMemoryMetricsEmitterTest.FetchAndEmitMetricsWithExtensions
--ProcessMemoryMetricsEmitterTest.FetchAndEmitMetricsWithExtensionsAndHostReuse
--ProfileWindowBrowserTest.GuestClearsCookies
--RegisterProtocolHandlerBrowserTest.CustomHandler
--ResourcePrefetchPredictorBrowserTest.SubresourceFcpOrder
--SBNavigationObserverBrowserTest.CompleteReferrerChain
--SBNavigationObserverBrowserTest.DirectDownload
--SBNavigationObserverBrowserTest.DirectDownloadNoReferrer
--SBNavigationObserverBrowserTest.DirectDownloadNoReferrerTargetBlank
--SBNavigationObserverBrowserTest.IPListDedup
--SBNavigationObserverBrowserTest.MixRedirects
--SBNavigationObserverBrowserTest.MultiMetaRefreshRedirects
--SBNavigationObserverBrowserTest.NewTabDownload
--SBNavigationObserverBrowserTest.NewTabDownloadWithDataURL
--SBNavigationObserverBrowserTest.PPAPIDownloadWithUserGestureOnHostingFrame
--SBNavigationObserverBrowserTest.PPAPIDownloadWithoutUserGestureOnHostingFrame
--SBNavigationObserverBrowserTest.ReferrerAttributionWithinTwoUserGestures
--SBNavigationObserverBrowserTest.RetargetingAndServerRedirect
--SBNavigationObserverBrowserTest.ServerRedirect
--SBNavigationObserverBrowserTest.SingleMetaRefreshRedirect
--SBNavigationObserverBrowserTest.SingleMetaRefreshRedirectTargetBlank
--SBNavigationObserverBrowserTest.SubFrameDirectDownload
--SBNavigationObserverBrowserTest.SubFrameNewTabDownload
--SBNavigationObserverBrowserTest.TwoServerRedirects
--SBNavigationObserverBrowserTest.TypeInURLDownload
--SBNavigationObserverBrowserTest.VerifySanitizeReferrerChain
--SBNavigationObserverBrowserTest.WindowLocationRedirect
--SSLUITestCommittedInterstitials.ErrorPage
--SSLUITest.BadCertFollowedByGoodCert
--SSLUITest.DisplayedContentWithCertErrorsClearedOnNavigation
--SSLUITest.TestBadHTTPSDownload
--SSLUITest.TestHTTPSOCSPOk
--SSLUITest.TestHTTPSOCSPRevoked
--SSLUITest.TestUnsafeContentsWithUserException
--SSLUITest.TestUnsafeImageWithUserException
--SSLUITestIgnoreLocalhostCertErrors.TestNoInterstitialOnLocalhost
--SSLUIWorkerFetchTest.TestUnsafeContentsInWorkerWithUserException/0
--SSLUIWorkerFetchTest.TestUnsafeContentsInWorkerWithUserException/1
--SSLUIWorkerFetchTest.TestUnsafeContentsInWorkerWithUserException/2
--SSLUIWorkerFetchTest.TestUnsafeContentsInWorkerWithUserException/3
--SafeBrowsingServiceTest.Prefetch
--SecurityStateTabHelperTest.BrokenHTTPS
--SecurityStateTabHelperTest.MixedContentWithSHA1Cert
--SecurityStateTabHelperTest.PasswordSecurityLevelDowngradedOnFilesystemUrl
--SecurityStateTabHelperTest.PasswordSecurityLevelNotDowngradedOnHttps
--SecurityStateTabHelperTest.SHA1CertificateBlocked
--SecurityStateTabHelperTest.SHA1CertificateWarning
--SecurityStateTabHelperTest.UMALogsVisitsAfterWarning
--SiteDetailsBrowserTest.ExtensionWithTwoWebIframes
--SiteDetailsBrowserTest.IsolateExtensions
--StreamsPrivateApiTest.NavigateCrossSite
--SuperfishSSLUITest.NoSuperfishRecorded
--SuperfishSSLUITest.SuperfishRecorded
--TabManagerTest.DiscardTabsWithMinimizedAndOccludedWindows
--TaskManagerBrowserTest.NoticeAppTab
--TaskManagerBrowserTest.NoticeAppTabChanges
--TaskManagerBrowserTest.NoticeExtensionTab
--TaskManagerBrowserTest.NoticeExtensionTabChanges
--TaskManagerBrowserTest.SentDataObserved
--TaskManagerBrowserTest.TotalSentDataObserved
--TaskManagerUtilityProcessBrowserTest.UtilityJSHeapMemory
--V4SafeBrowsingServiceTest.Prefetch
--ViewExtensionSourceTest.ViewSourceTabRestore
--WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsEmitsGatheringStateChange
--WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsGetStatsCallback
--WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsGetStatsPromise
--WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsOfferEcdsaAnswerRsa
--WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsOfferRsaAnswerEcdsa
--WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsOfferRsaAnswerRsa
--WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificateEcdsa
--WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsWithClonedCertificateRsa
--WebRtcRtpBrowserTest.AddAndRemoveTracksWithIndividualStreams
--WebRtcRtpBrowserTest.AddAndRemoveTracksWithSharedStream
--WebRtcRtpBrowserTest.AddAndRemoveTracksWithoutStream
--WebRtcRtpBrowserTest.GetReceiversSetRemoteDescription
--WebRtcRtpBrowserTest.GetSenders
--WebRtcRtpBrowserTest.SwitchRemoteStreamAndBackAgain
--WebRtcRtpBrowserTest.SwitchRemoteStreamWithoutWaitingForPromisesToResolve
--WebSocketBrowserTest.WebSocketAppliesHSTS
--WebSocketBrowserTest.WebSocketBasicAuthInHTTPSURL
--WebSocketBrowserTest.WebSocketBasicAuthInHTTPURL
--WebViewTests/WebViewTest.LoadWebviewAccessibleResource/1
--WindowOpenApiTest.BrowserIsApp
--WindowOpenApiTest.PopupBlockingExtension
--WindowOpenApiTest.WindowOpenPopupDefault
--WindowOpenApiTest.WindowOpenPopupIframe
--WindowOpenApiTest.WindowOpenPopupLarge
--WindowOpenApiTest.WindowOpenPopupSmall
 
 # crbug.com/776589 Intercepting requests with net::URLRequestFilter.
 -BrowserCloseManagerWithDownloadsBrowserTest/BrowserCloseManagerWithDownloadsBrowserTest.TestWithDownloads/0
@@ -2351,9 +1145,6 @@
 -SaveType/SavePageOriginalVsSavedComparisonTest.ObjectElementsViaFile/0
 -SaveType/SavePageOriginalVsSavedComparisonTest.ObjectElementsViaHttp/0
 
-# crbug.com/779115 The |devtools_extension_panel_rfh| is nullptr.
--DevToolsExtensionTest.HttpIframeInDevToolsExtensionPanel
-
 # crbug.com/779121 The |url_chain_| contains one empty string at DownloadUrlSBClient::StartCheck().
 -DownloadTest.SaveLinkAsReferrerPolicyOrigin
 
@@ -2386,12 +1177,6 @@
 -ReferrerPolicyTest.HttpsContextMenuOrigin
 -ReferrerPolicyTest.HttpsContextMenuRedirect
 
-# crbug.com/780325 Should be working again once chrome-extension loading is properly supported.
--ExtensionFetchTest.ExtensionCanFetchExtensionResource
--ExtensionFetchTest.ExtensionCanFetchHostedResourceWithHostPermissions
--ExtensionFetchTest.ExtensionCannotFetchHostedResourceWithoutHostPermissions
--ExtensionFetchTest.HostCanFetchWebAccessibleExtensionResource
-
 # crbug.com/781565
 -DownloadTest.DontCloseNewTab3
 -DownloadTest.CloseNewTab1
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index c9c7d27..6b390a5c 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -583,6 +583,11 @@
       "--snapshot-output-dir=${ISOLATED_OUTDIR}",
     ],
   },
+  "ios_chrome_bookmarks_egtests": {
+    "label": "//ios/chrome/test/earl_grey:ios_chrome_bookmarks_egtests",
+    "type": "raw",
+    "args": [],
+  },
   "ios_chrome_integration_egtests": {
     "label": "//ios/chrome/test/earl_grey:ios_chrome_integration_egtests",
     "type": "raw",
diff --git a/testing/buildbot/manage.py b/testing/buildbot/manage.py
index 6877013..dce6dd9 100755
--- a/testing/buildbot/manage.py
+++ b/testing/buildbot/manage.py
@@ -95,6 +95,7 @@
 
   # iOS tests are listed in //ios/build/bots.
   'cronet_test',
+  'ios_chrome_bookmarks_egtests',
   'ios_chrome_integration_egtests',
   'ios_chrome_payments_egtests',
   'ios_chrome_reading_list_egtests',
diff --git a/testing/libfuzzer/fuzzers/feature_policy_corpus/16 b/testing/libfuzzer/fuzzers/feature_policy_corpus/16
new file mode 100644
index 0000000..933c321e
--- /dev/null
+++ b/testing/libfuzzer/fuzzers/feature_policy_corpus/16
@@ -0,0 +1 @@
+vibrate 'src'
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index fdd2e9a..1fcb0590 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -6491,7 +6491,7 @@
 crbug.com/591099 http/tests/devtools/extensions/extensions-network.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/devtools/extensions/extensions-sidebar.html [ Crash Failure ]
 crbug.com/591099 http/tests/devtools/extensions/extensions-timeline-api.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/indexeddb/resources-panel.html [ Crash Failure Pass Timeout ]
+crbug.com/591099 http/tests/devtools/indexeddb/resources-panel.js [ Crash Failure Pass Timeout ]
 crbug.com/591099 http/tests/devtools/layers/layer-canvas-log.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/devtools/layers/layer-replay-scale.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/devtools/layers/layer-sticky-position-constraint-get.html [ Crash Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/MSANExpectations b/third_party/WebKit/LayoutTests/MSANExpectations
index 0e0c72d..da93bd0e 100644
--- a/third_party/WebKit/LayoutTests/MSANExpectations
+++ b/third_party/WebKit/LayoutTests/MSANExpectations
@@ -66,8 +66,8 @@
 crbug.com/729136 [ Linux ] fast/css/css-selector-deeply-nested.html [ Timeout ]
 crbug.com/729136 [ Linux ] http/tests/devtools/forced-layout-in-microtask.js [ Timeout ]
 crbug.com/729136 [ Linux ] http/tests/devtools/tracing/timeline-xhr-response-type-blob-event.html [ Timeout ]
-crbug.com/729136 [ Linux ] http/tests/devtools/components/file-path-scoring.html [ Timeout ]
-crbug.com/667560 [ Linux ] virtual/mojo-loading/http/tests/devtools/components/file-path-scoring.html [ Timeout ]
+crbug.com/729136 [ Linux ] http/tests/devtools/components/file-path-scoring.js [ Timeout ]
+crbug.com/667560 [ Linux ] virtual/mojo-loading/http/tests/devtools/components/file-path-scoring.js [ Timeout ]
 crbug.com/729136 [ Linux ] http/tests/devtools/elements/styles-4/styles-should-not-force-sync-style-recalc.js [ Timeout ]
 crbug.com/667560 [ Linux ] virtual/mojo-loading/http/tests/devtools/elements/styles-4/styles-should-not-force-sync-style-recalc.js [ Timeout ]
 crbug.com/729136 [ Linux ] webaudio/mixing.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 50d323c..a1ff8df7 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -901,14 +901,14 @@
 
 crbug.com/731731 inspector-protocol/layers/paint-profiler-load-empty.js [ Failure Pass ]
 
-crbug.com/734744 http/tests/devtools/indexeddb/resources-panel.html [ Pass Failure Timeout ]
-crbug.com/734744 virtual/mojo-loading/http/tests/devtools/indexeddb/resources-panel.html [ Pass Failure Timeout ]
+crbug.com/734744 http/tests/devtools/indexeddb/resources-panel.js [ Pass Failure Timeout ]
+crbug.com/734744 virtual/mojo-loading/http/tests/devtools/indexeddb/resources-panel.js [ Pass Failure Timeout ]
 
-crbug.com/734793 http/tests/devtools/indexeddb/database-names.html [ Pass Failure Timeout ]
-crbug.com/734793 virtual/mojo-loading/http/tests/devtools/indexeddb/database-names.html [ Pass Failure Timeout ]
+crbug.com/734793 http/tests/devtools/indexeddb/database-names.js [ Pass Failure Timeout ]
+crbug.com/734793 virtual/mojo-loading/http/tests/devtools/indexeddb/database-names.js [ Pass Failure Timeout ]
 
-crbug.com/735259 http/tests/devtools/indexeddb/upgrade-events.html [ Pass Failure ]
-crbug.com/735259 virtual/mojo-loading/http/tests/devtools/indexeddb/upgrade-events.html [ Pass Failure ]
+crbug.com/735259 http/tests/devtools/indexeddb/upgrade-events.js [ Pass Failure ]
+crbug.com/735259 virtual/mojo-loading/http/tests/devtools/indexeddb/upgrade-events.js [ Pass Failure ]
 
 # Will be re-enabled and rebaselined once we remove the '--enable-file-cookies' flag.
 crbug.com/470482 fast/cookies/local-file-can-set-cookies.html [ Skip ]
@@ -1700,8 +1700,8 @@
 
 crbug.com/605059 [ Retina ] fast/text/international/rtl-negative-letter-spacing.html [ Failure ]
 
-crbug.com/610464 [ Linux Win7 Debug ] http/tests/devtools/components/throttler.html [ Failure Pass ]
-crbug.com/667560 [ Linux Win7 Debug ] virtual/mojo-loading/http/tests/devtools/components/throttler.html [ Failure Pass ]
+crbug.com/610464 [ Linux Win7 Debug ] http/tests/devtools/components/throttler.js [ Failure Pass ]
+crbug.com/667560 [ Linux Win7 Debug ] virtual/mojo-loading/http/tests/devtools/components/throttler.js [ Failure Pass ]
 crbug.com/654477 [ Win ] compositing/video/video-controls-layer-creation.html [ Pass Failure ]
 crbug.com/654477 fast/hidpi/video-controls-in-hidpi.html [ Failure ]
 crbug.com/654477 fast/layers/video-layer.html [ Failure ]
@@ -1872,8 +1872,8 @@
 
 # Untriaged failures after https://crrev.com/c/543695/.
 # These need to be updated but appear not to be related to that change.
-crbug.com/626703 http/tests/devtools/indexeddb/database-refresh-view.html [ Pass Failure ]
-crbug.com/626703 virtual/mojo-loading/http/tests/devtools/indexeddb/database-refresh-view.html [ Pass Failure ]
+crbug.com/626703 http/tests/devtools/indexeddb/database-refresh-view.js [ Pass Failure ]
+crbug.com/626703 virtual/mojo-loading/http/tests/devtools/indexeddb/database-refresh-view.js [ Pass Failure ]
 crbug.com/626703 http/tests/devtools/network/network-filters.html [ Pass Failure ]
 crbug.com/626703 virtual/mojo-loading/http/tests/devtools/network/network-filters.html [ Pass Failure ]
 crbug.com/626703 http/tests/devtools/application-panel/resources-panel-selection-on-reload.js [ Pass Failure ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests.tentative-expected.txt
new file mode 100644
index 0000000..24850939
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (all) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests.tentative.html
new file mode 100644
index 0000000..383914a1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Basic tests for cookieStore</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite();
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests.tentative.https-expected.txt
new file mode 100644
index 0000000..24850939
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (all) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests.tentative.https.html
new file mode 100644
index 0000000..a892d46
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Basic tests for cookieStore (HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite();
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests_static.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests_static.tentative-expected.txt
new file mode 100644
index 0000000..24850939
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests_static.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (all) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests_static.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests_static.tentative.html
new file mode 100644
index 0000000..6a4fa758
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests_static.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Basic tests for cookieStore (Static)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite();
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests_static.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests_static.tentative.https-expected.txt
new file mode 100644
index 0000000..24850939
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests_static.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (all) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests_static.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests_static.tentative.https.html
new file mode 100644
index 0000000..0776ab3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/cookie_store_tests_static.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Basic tests for cookieStore (Static; HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite();
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies.tentative-expected.txt
new file mode 100644
index 0000000..9108f079
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testDeleteCookies) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies.tentative.html
new file mode 100644
index 0000000..db8bd93
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: delete cookies</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testDeleteCookies'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies.tentative.https-expected.txt
new file mode 100644
index 0000000..9108f079
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testDeleteCookies) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies.tentative.https.html
new file mode 100644
index 0000000..e042fcff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: delete cookies (HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testDeleteCookies'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies_static.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies_static.tentative-expected.txt
new file mode 100644
index 0000000..9108f079
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies_static.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testDeleteCookies) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies_static.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies_static.tentative.html
new file mode 100644
index 0000000..045a3e7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies_static.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: delete cookies (Static)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testDeleteCookies'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies_static.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies_static.tentative.https-expected.txt
new file mode 100644
index 0000000..9108f079
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies_static.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testDeleteCookies) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies_static.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies_static.tentative.https.html
new file mode 100644
index 0000000..da8e24f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/delete_cookies_static.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: delete cookies (Static; HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testDeleteCookies'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie.tentative-expected.txt
new file mode 100644
index 0000000..1c9dbfd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testDocumentCookie) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie.tentative.html
new file mode 100644
index 0000000..5bcc0e924
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: document.cookie</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testDocumentCookie'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie.tentative.https-expected.txt
new file mode 100644
index 0000000..1c9dbfd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testDocumentCookie) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie.tentative.https.html
new file mode 100644
index 0000000..27e34d59b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: document.cookie (HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testDocumentCookie'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie_static.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie_static.tentative-expected.txt
new file mode 100644
index 0000000..1c9dbfd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie_static.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testDocumentCookie) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie_static.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie_static.tentative.html
new file mode 100644
index 0000000..34c1ed9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie_static.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: document.cookie (Static)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testDocumentCookie'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie_static.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie_static.tentative.https-expected.txt
new file mode 100644
index 0000000..1c9dbfd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie_static.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testDocumentCookie) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie_static.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie_static.tentative.https.html
new file mode 100644
index 0000000..0664910
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/document_cookie_static.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: document.cookie (Static; HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testDocumentCookie'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration.tentative-expected.txt
new file mode 100644
index 0000000..43b427d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testExpiration) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration.tentative.html
new file mode 100644
index 0000000..3abe909
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: expiration</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testExpiration'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration.tentative.https-expected.txt
new file mode 100644
index 0000000..43b427d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testExpiration) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration.tentative.https.html
new file mode 100644
index 0000000..50f0e2e1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: expiration (HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testExpiration'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration_static.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration_static.tentative-expected.txt
new file mode 100644
index 0000000..43b427d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration_static.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testExpiration) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration_static.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration_static.tentative.html
new file mode 100644
index 0000000..bfb8320
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration_static.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: expiration (Static)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testExpiration'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration_static.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration_static.tentative.https-expected.txt
new file mode 100644
index 0000000..43b427d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration_static.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testExpiration) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration_static.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration_static.tentative.https.html
new file mode 100644
index 0000000..e582849
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/expiration_static.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: expiration (Static; HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testExpiration'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all.tentative-expected.txt
new file mode 100644
index 0000000..e389920a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testGetSetGetAll) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all.tentative.html
new file mode 100644
index 0000000..cc59bd5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: get, set, getAll</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testGetSetGetAll'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all.tentative.https-expected.txt
new file mode 100644
index 0000000..e389920a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testGetSetGetAll) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all.tentative.https.html
new file mode 100644
index 0000000..3d37ec9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: get, set, getAll (HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testGetSetGetAll'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all_static.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all_static.tentative-expected.txt
new file mode 100644
index 0000000..e389920a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all_static.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testGetSetGetAll) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all_static.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all_static.tentative.html
new file mode 100644
index 0000000..aa7fa31
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all_static.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: get, set, getAll (Static)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testGetSetGetAll'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all_static.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all_static.tentative.https-expected.txt
new file mode 100644
index 0000000..e389920a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all_static.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testGetSetGetAll) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all_static.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all_static.tentative.https.html
new file mode 100644
index 0000000..31c8c1d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/get_set_get_all_static.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: get, set, getAll (Static; HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testGetSetGetAll'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/http_cookie_and_set_cookie_headers.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/http_cookie_and_set_cookie_headers.tentative-expected.txt
new file mode 100644
index 0000000..e10c45b9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/http_cookie_and_set_cookie_headers.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testHttpCookieAndSetCookieHeaders) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/http_cookie_and_set_cookie_headers.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/http_cookie_and_set_cookie_headers.tentative.html
new file mode 100644
index 0000000..bfe6eaa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/http_cookie_and_set_cookie_headers.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: HTTP Cookie and Set-Cookie headers</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testHttpCookieAndSetCookieHeaders'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/http_cookie_and_set_cookie_headers.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/http_cookie_and_set_cookie_headers.tentative.https-expected.txt
new file mode 100644
index 0000000..e10c45b9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/http_cookie_and_set_cookie_headers.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testHttpCookieAndSetCookieHeaders) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/http_cookie_and_set_cookie_headers.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/http_cookie_and_set_cookie_headers.tentative.https.html
new file mode 100644
index 0000000..56649e5f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/http_cookie_and_set_cookie_headers.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: HTTP Cookie and Set-Cookie headers (HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testHttpCookieAndSetCookieHeaders'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie.tentative-expected.txt
new file mode 100644
index 0000000..0d2a2f34
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testMetaHttpEquivSetCookie) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie.tentative.html
new file mode 100644
index 0000000..69943ec43
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: <title>Async Cookies: document.cookie</title>lt;Meta Http-Equiv="Set-Cookie" ... <title>Async Cookies: document.cookie</title>gt;</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testMetaHttpEquivSetCookie'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie.tentative.https-expected.txt
new file mode 100644
index 0000000..0d2a2f34
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testMetaHttpEquivSetCookie) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie.tentative.https.html
new file mode 100644
index 0000000..43bde2eb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: <title>Async Cookies: document.cookie</title>lt;Meta Http-Equiv="Set-Cookie" ... <title>Async Cookies: document.cookie</title>gt; (HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testMetaHttpEquivSetCookie'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie_static.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie_static.tentative-expected.txt
new file mode 100644
index 0000000..0d2a2f34
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie_static.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testMetaHttpEquivSetCookie) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie_static.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie_static.tentative.html
new file mode 100644
index 0000000..55d90aa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie_static.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: <title>Async Cookies: document.cookie</title>lt;Meta Http-Equiv="Set-Cookie" ... <title>Async Cookies: document.cookie</title>gt; (Static)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testMetaHttpEquivSetCookie'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie_static.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie_static.tentative.https-expected.txt
new file mode 100644
index 0000000..0d2a2f34
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie_static.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testMetaHttpEquivSetCookie) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie_static.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie_static.tentative.https.html
new file mode 100644
index 0000000..fd07594
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/meta_http_equiv_set_cookie_static.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: <title>Async Cookies: document.cookie</title>lt;Meta Http-Equiv="Set-Cookie" ... <title>Async Cookies: document.cookie</title>gt; (Static; HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testMetaHttpEquivSetCookie'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value.tentative-expected.txt
new file mode 100644
index 0000000..701daed3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testNoNameAndNoValue) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value.tentative.html
new file mode 100644
index 0000000..e7ea7c8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test No Name and No Value</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testNoNameAndNoValue'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value.tentative.https-expected.txt
new file mode 100644
index 0000000..701daed3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testNoNameAndNoValue) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value.tentative.https.html
new file mode 100644
index 0000000..07eb950e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test No Name and No Value (HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testNoNameAndNoValue'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value_static.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value_static.tentative-expected.txt
new file mode 100644
index 0000000..701daed3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value_static.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testNoNameAndNoValue) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value_static.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value_static.tentative.html
new file mode 100644
index 0000000..c40fbec
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value_static.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test No Name and No Value (Static)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testNoNameAndNoValue'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value_static.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value_static.tentative.https-expected.txt
new file mode 100644
index 0000000..701daed3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value_static.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testNoNameAndNoValue) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value_static.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value_static.tentative.https.html
new file mode 100644
index 0000000..463af00
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_and_no_value_static.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test No Name and No Value (Static; HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testNoNameAndNoValue'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value.tentative-expected.txt
new file mode 100644
index 0000000..c9efedc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testNoNameEqualsInValue) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value.tentative.html
new file mode 100644
index 0000000..07767a9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test No Name, '=' in Value</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testNoNameEqualsInValue'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value.tentative.https-expected.txt
new file mode 100644
index 0000000..c9efedc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testNoNameEqualsInValue) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value.tentative.https.html
new file mode 100644
index 0000000..30b3c9e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test No Name, '=' in Value (HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testNoNameEqualsInValue'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value_static.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value_static.tentative-expected.txt
new file mode 100644
index 0000000..c9efedc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value_static.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testNoNameEqualsInValue) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value_static.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value_static.tentative.html
new file mode 100644
index 0000000..24a8558
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value_static.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test No Name, '=' in Value (Static)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testNoNameEqualsInValue'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value_static.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value_static.tentative.https-expected.txt
new file mode 100644
index 0000000..c9efedc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value_static.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testNoNameEqualsInValue) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value_static.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value_static.tentative.https.html
new file mode 100644
index 0000000..badeae4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_equals_in_value_static.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test No Name, '=' in Value (Static; HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testNoNameEqualsInValue'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values.tentative-expected.txt
new file mode 100644
index 0000000..92e93ef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testNoNameMultipleValues) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values.tentative.html
new file mode 100644
index 0000000..e1b0aa1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test No Name, Multiple Values</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testNoNameMultipleValues'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values.tentative.https-expected.txt
new file mode 100644
index 0000000..92e93ef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testNoNameMultipleValues) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values.tentative.https.html
new file mode 100644
index 0000000..f29e3fa9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test No Name, Multiple Values (HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testNoNameMultipleValues'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values_static.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values_static.tentative-expected.txt
new file mode 100644
index 0000000..92e93ef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values_static.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testNoNameMultipleValues) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values_static.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values_static.tentative.html
new file mode 100644
index 0000000..3200eb6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values_static.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test No Name, Multiple Values (Static)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testNoNameMultipleValues'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values_static.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values_static.tentative.https-expected.txt
new file mode 100644
index 0000000..92e93ef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values_static.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testNoNameMultipleValues) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values_static.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values_static.tentative.https.html
new file mode 100644
index 0000000..1c8e920c5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/no_name_multiple_values_static.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test No Name, Multiple Values (Static; HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testNoNameMultipleValues'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation.tentative-expected.txt
new file mode 100644
index 0000000..0d75e6f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testObservation) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation.tentative.html
new file mode 100644
index 0000000..7a70b2bc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test Observation</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testObservation'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation.tentative.https-expected.txt
new file mode 100644
index 0000000..0d75e6f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testObservation) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation.tentative.https.html
new file mode 100644
index 0000000..c499171
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test Observation (HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testObservation'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation_static.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation_static.tentative-expected.txt
new file mode 100644
index 0000000..0d75e6f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation_static.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testObservation) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation_static.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation_static.tentative.html
new file mode 100644
index 0000000..b524b05
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation_static.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test Observation (Static)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testObservation'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation_static.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation_static.tentative.https-expected.txt
new file mode 100644
index 0000000..0d75e6f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation_static.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testObservation) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation_static.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation_static.tentative.https.html
new file mode 100644
index 0000000..3d953c2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/observation_static.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: Test Observation (Static; HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testObservation'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie.tentative-expected.txt
new file mode 100644
index 0000000..ee7ac04
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testOneSimpleOriginCookie) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie.tentative.html
new file mode 100644
index 0000000..2bf2ae6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: One simple origin cookie</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testOneSimpleOriginCookie'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie.tentative.https-expected.txt
new file mode 100644
index 0000000..ee7ac04
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testOneSimpleOriginCookie) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie.tentative.https.html
new file mode 100644
index 0000000..05e586de6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: One simple origin cookie (HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testOneSimpleOriginCookie'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie_static.tentative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie_static.tentative-expected.txt
new file mode 100644
index 0000000..ee7ac04
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie_static.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testOneSimpleOriginCookie) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie_static.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie_static.tentative.html
new file mode 100644
index 0000000..f7e04eac
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie_static.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: One simple origin cookie (Static)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testOneSimpleOriginCookie'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie_static.tentative.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie_static.tentative.https-expected.txt
new file mode 100644
index 0000000..ee7ac04
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie_static.tentative.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Cookie Store Tests (testOneSimpleOriginCookie) assert_equals: testDeleteCookies failures: TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function,TypeError: cookieStore.delete is not a function expected 0 but got 12
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie_static.tentative.https.html b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie_static.tentative.https.html
new file mode 100644
index 0000000..25e155a88
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/one_simple_origin_cookie_static.tentative.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>Async Cookies: One simple origin cookie (Static; HTTPS)</title>
+<meta name="help" href="https://github.com/WICG/async-cookies-api/blob/gh-pages/explainer.md">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testharness-helpers.js"></script>
+<script src="resources/cookie-store-tests.js"></script>
+<script>
+'use strict';
+
+suite({testName: 'testOneSimpleOriginCookie'});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/resources/cookie-store-tests.js b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/resources/cookie-store-tests.js
new file mode 100644
index 0000000..f9bb78f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/resources/cookie-store-tests.js
@@ -0,0 +1,1129 @@
+'use strict';
+
+// Buffered exceptions re-thrown at end of suite
+let savedExceptions = [];
+
+// Observer-based document.cookie simulator
+let observer;
+let observationLog = [];
+let observedStore = [];
+
+// Note on cookie naming conventions:
+//
+// A simple origin cookie is a cookie named with the __Host- prefix
+// which is always secure-flagged, always implicit-domain, always
+// /-scoped, and hence always unambiguous in the cookie jar serialization
+// and origin-scoped. It can be treated as a simple key/value pair.
+//
+// "LEGACY" in a cookie name here means it is an old-style unprefixed
+// cookie name, so you can't tell e.g. whether it is Secure-flagged or
+// /-pathed just by looking at it, and its flags, domain and path may
+// vary even in a single cookie jar serialization leading to apparent
+// duplicate entries, ambiguities, and complexity (it cannot be
+// treated as a simple key/value pair.)
+//
+// Cookie names used in the tests are intended to be
+// realistic. Traditional session cookie names are typically
+// all-upper-case for broad framework compatibility. The more modern
+// "__Host-" prefix has only one allowed casing. An expected upgrade
+// path from traditional "legacy" cookie names to simple origin cookie
+// names is simply to prefix the traditional name with the "__Host-"
+// prefix.
+//
+// Many of the used cookie names are non-ASCII to ensure
+// straightforward internationalization is possible at every API surface.
+// These work in many modern browsers, though not yet all of them.
+
+// Approximate async observer-based equivalent to the document.cookie
+// getter but with important differences: an empty cookie jar returns
+// undefined. Introduces unfortunate but apparently unavoidable delays
+// to ensure the observer has time to run.
+//
+// Timeouts here are intended to give observers enough time to sense
+// a change. It can't be changed to wait indefinitely as it is
+// sometimes used to verify observers were not notified of any
+// change.
+const getCookieStringObserved = opt_name => {
+  // Run later to ensure the cookie scanner (which runs one task
+  // later, at least in the polyfill) has a chance.
+  //
+  // We cannot use the s\u0065tTimeout identifier unescaped inside WPT
+  // tests (the linter does not allow it.) However we need an actual
+  // delay to allow batched observers to fire.
+  const initialLength = observationLog.length;
+  return (async () => {
+    assert_not_equals(observer, undefined, 'observer should not be undefined');
+    await new Promise(resolve => s\u0065tTimeout(resolve));
+    const lengthAfterImplicit0msSetTimeout = observationLog.length;
+    if (lengthAfterImplicit0msSetTimeout === initialLength) {
+      await new Promise(resolve => s\u0065tTimeout(resolve, 4));
+      const lengthAfter4msSetTimeout = observationLog.length;
+      if (lengthAfter4msSetTimeout === initialLength) {
+        let lengthAfterRequestAnimationFrame = lengthAfter4msSetTimeout;
+        if (typeof requestAnimationFrame !== 'undefined') {
+          await new Promise(resolve => requestAnimationFrame(resolve));
+          lengthAfterRequestAnimationFrame = observationLog.length;
+        }
+        if (lengthAfterRequestAnimationFrame === initialLength) {
+          await new Promise(
+              resolve => s\u0065tTimeout(resolve, kExtraObserverDelay));
+        }
+      }
+    }
+    let filtered = observedStore;
+    if (opt_name != null) filtered = filtered.filter(
+        cookie => cookie.name === opt_name);
+    return cookieString(filtered);
+  })();
+};
+
+const assertEmptyCookieJar = async (testCase, messageSuffix) => {
+  assert_equals(
+      await getCookieString(),
+      undefined,
+      'No cookies ' + messageSuffix);
+  if (!kIsStatic) assert_equals(
+      await getCookieStringHttp(),
+      undefined,
+      'No HTTP cookies ' + messageSuffix);
+  if (kHasDocument) assert_equals(
+      await getCookieStringDocument(),
+      undefined,
+      'No document.cookie cookies ' + messageSuffix);
+};
+
+const suite = ({testName = undefined} = {}) => {
+  promise_test(async testCase => {
+    testOverride = testName;
+    observer = undefined;
+    observationLog.length = 0;
+    observedStore.length = 0;
+    savedExceptions.length = 0;
+    // Start with a clean slate.
+    //
+    // Attempt testDeleteCookies first too, since otherwise an earlier
+    // failed test can cause all subsequent tests to fail.
+    await testDeleteCookies(testCase);
+    await assertEmptyCookieJar(testCase, 'at start of test');
+    let unfinished = true;
+    try {
+      if (includeTest('testObservation')) {
+        observer = await testObservation();
+        assert_equals(
+            await getCookieStringObserved(),
+            undefined,
+            'No observed cookies at start of test');
+      }
+      // These use the same cookie names and so cannot run interleaved
+      if (includeTest('testNoNameAndNoValue')) await testNoNameAndNoValue();
+      if (includeTest('testNoNameMultipleValues')) {
+        await testNoNameMultipleValues();
+      }
+      if (includeTest('testNoNameEqualsInValue')) {
+        await testNoNameEqualsInValue();
+      }
+      if (includeTest('testMetaHttpEquivSetCookie')) {
+        await testMetaHttpEquivSetCookie();
+      }
+      if (includeTest('testDocumentCookie', !kHasDocument)) {
+        await testDocumentCookie();
+      }
+      if (includeTest('testHttpCookieAndSetCookieHeaders', kIsStatic)) {
+        await testHttpCookieAndSetCookieHeaders();
+      }
+      if (includeTest('testGetSetGetAll')) {
+        await testGetSetGetAll();
+      }
+      if (includeTest('testOneSimpleOriginCookie')) {
+        await testOneSimpleOriginCookie(testCase);
+      }
+      if (includeTest('testExpiration')) {
+        await testExpiration(testCase);
+      }
+      await promise_rejects_when_unsecured(
+          testCase,
+          new SyntaxError(),
+          testThreeSimpleOriginSessionCookiesSetSequentially(),
+          '__Host- cookies only writable from secure contexts' +
+            ' (testThreeSimpleOriginSessionCookiesSetSequentially)');
+      await promise_rejects_when_unsecured(
+          testCase,
+          new SyntaxError(),
+          testThreeSimpleOriginSessionCookiesSetNonsequentially(),
+          '__Host- cookies only writable from secure contexts' +
+            ' (testThreeSimpleOriginSessionCookiesSetNonsequentially)');
+      await promise_rejects_when_unsecured(
+          testCase,
+          new SyntaxError(),
+          setExpiredSecureCookieWithDomainPathAndFallbackValue(),
+          'Secure cookies only writable from secure contexts' +
+            ' (setExpiredSecureCookieWithDomainPathAndFallbackValue)');
+      await promise_rejects_when_unsecured(
+          testCase,
+          new SyntaxError(),
+          deleteSimpleOriginCookie(),
+          '__Host- cookies only writable from secure contexts' +
+            ' (deleteSimpleOriginCookie)');
+      await promise_rejects_when_unsecured(
+          testCase,
+          new SyntaxError(),
+          deleteSecureCookieWithDomainAndPath(),
+          'Secure cookies only writable from secure contexts' +
+            ' (deleteSecureCookieWithDomainAndPath)');
+      if (kIsUnsecured) {
+        assert_equals(
+            await getCookieString(),
+            includeTest('testGetSetGetAll') ? 'TEST=value' : undefined,
+            (includeTest('testGetSetGetAll') ?
+             'Only one unsecured cookie' :
+             'No unsecured cookies') +
+              ' before testDeleteCookies at end of test');
+        if (observer) assert_equals(
+            await getCookieStringObserved(),
+            includeTest('testGetSetGetAll') ? 'TEST=value' : undefined,
+            (includeTest('testGetSetGetAll') ?
+             'Only one observed unsecured cookie' :
+             'No observed unsecured cookies') +
+              ' before testDeleteCookies at end of test');
+      } else {
+        assert_equals(
+            await getCookieString(),
+            (includeTest('testGetSetGetAll') ? 'TEST=value; ' : '') +
+              '__Host-1🍪=🔵cookie-value1🔴; ' +
+              '__Host-2🌟=🌠cookie-value2🌠; ' +
+              '__Host-3🌱=🔶cookie-value3🔷; ' +
+              '__Host-unordered1🍪=🔵unordered-cookie-value1🔴; ' +
+              '__Host-unordered2🌟=🌠unordered-cookie-value2🌠; ' +
+              '__Host-unordered3🌱=🔶unordered-cookie-value3🔷',
+            'All residual cookies before testDeleteCookies at end of test');
+        if (observer) assert_equals(
+            await getCookieStringObserved(),
+            (includeTest('testGetSetGetAll') ? 'TEST=value; ' : '') +
+              '__Host-1🍪=🔵cookie-value1🔴; ' +
+              '__Host-2🌟=🌠cookie-value2🌠; ' +
+              '__Host-3🌱=🔶cookie-value3🔷; ' +
+              '__Host-unordered1🍪=🔵unordered-cookie-value1🔴; ' +
+              '__Host-unordered2🌟=🌠unordered-cookie-value2🌠; ' +
+              '__Host-unordered3🌱=🔶unordered-cookie-value3🔷',
+            'All residual observed cookies before testDeleteCookies ' +
+              'at end of test');
+      }
+      if (kIsUnsecured) {
+        if (!kIsStatic) assert_equals(
+            await getCookieStringHttp(),
+            includeTest('testGetSetGetAll') ? 'TEST=value' : undefined,
+            (includeTest('testGetSetGetAll') ?
+             'Only one unsecured HTTP cookie' :
+             'No unsecured HTTP cookies') +
+              ' before testDeleteCookies at end of test');
+      } else {
+        if (!kIsStatic) assert_equals(
+            await getCookieStringHttp(),
+            (includeTest('testGetSetGetAll') ? 'TEST=value; ' : '') +
+              '__Host-1🍪=🔵cookie-value1🔴; ' +
+              '__Host-2🌟=🌠cookie-value2🌠; ' +
+              '__Host-3🌱=🔶cookie-value3🔷; ' +
+              '__Host-unordered1🍪=🔵unordered-cookie-value1🔴; ' +
+              '__Host-unordered2🌟=🌠unordered-cookie-value2🌠; ' +
+              '__Host-unordered3🌱=🔶unordered-cookie-value3🔷',
+            'All residual HTTP cookies before testDeleteCookies ' +
+              'at end of test');
+      }
+      if (kIsUnsecured) {
+        if (kHasDocument) assert_equals(
+            await getCookieStringDocument(),
+            includeTest('testGetSetGetAll') ? 'TEST=value' : undefined,
+            (includeTest('testGetSetGetAll') ?
+             'Only one unsecured document.cookie cookie' :
+             'No unsecured document.cookie cookies') +
+              ' before testDeleteCookies at end of test');
+      } else {
+        if (kHasDocument) assert_equals(
+            await getCookieStringDocument(),
+            (includeTest('testGetSetGetAll') ? 'TEST=value; ' : '') +
+              '__Host-1🍪=🔵cookie-value1🔴; ' +
+              '__Host-2🌟=🌠cookie-value2🌠; ' +
+              '__Host-3🌱=🔶cookie-value3🔷; ' +
+              '__Host-unordered1🍪=🔵unordered-cookie-value1🔴; ' +
+              '__Host-unordered2🌟=🌠unordered-cookie-value2🌠; ' +
+              '__Host-unordered3🌱=🔶unordered-cookie-value3🔷',
+            'All residual document.cookie cookies before testDeleteCookies ' +
+              'at end of test');
+      }
+      unfinished = false;
+      assert_equals(
+          savedExceptions.length,
+          0,
+          'Found saved exceptions: ' + savedExceptions);
+    } finally {
+      try {
+        await testDeleteCookies(testCase);
+        if (observer) observer.disconnect();
+        await assertEmptyCookieJar(testCase, 'at end of test');
+      } catch (e) {
+        // only re-throw testDeleteCookies failures if finished to avoid masking
+        // earlier failures
+        if (!unfinished) throw e;
+      }
+    }
+  }, 'Cookie Store Tests (' + (testName || 'all') + ')');
+};
+
+
+// Try to clean up cookies and observers used by tests. Also
+// verifies delete() behavior for secure contexts and unsecured
+// contexts.
+//
+// Parameters:
+// - testCase: (TestCase) Context in which the testDeleteCookies is run.
+const testDeleteCookies = async testCase => {
+  let exceptions = [];
+  for (let resetStep of [
+    async () => await cookieStore.delete(''),
+    async () => await cookieStore.delete('TEST'),
+    async () => await cookieStore.delete('META-🍪'),
+    async () => await cookieStore.delete('DOCUMENT-🍪'),
+    async () => await cookieStore.delete('HTTP-🍪'),
+    async () => {
+      if (!kIsStatic) await setCookieStringHttp(
+          'HTTPONLY-🍪=DELETED; path=/; max-age=0; httponly');
+    },
+    async () => await promise_rejects_when_unsecured(
+        testCase,
+        new SyntaxError(),
+        cookieStore.delete('__Host-COOKIENAME')),
+    async () => await promise_rejects_when_unsecured(
+        testCase,
+        new SyntaxError(),
+        cookieStore.delete('__Host-1🍪')),
+    async () => await promise_rejects_when_unsecured(
+        testCase,
+        new SyntaxError(),
+        cookieStore.delete('__Host-2🌟')),
+    async () => await promise_rejects_when_unsecured(
+        testCase,
+        new SyntaxError(),
+        cookieStore.delete('__Host-3🌱')),
+    async () => await promise_rejects_when_unsecured(
+        testCase,
+        new SyntaxError(),
+        cookieStore.delete('__Host-unordered1🍪')),
+    async () => await promise_rejects_when_unsecured(
+        testCase,
+        new SyntaxError(),
+        cookieStore.delete('__Host-unordered2🌟')),
+    async () => await promise_rejects_when_unsecured(
+        testCase,
+        new SyntaxError(),
+        cookieStore.delete('__Host-unordered3🌱')),
+  ]) {
+    try {
+      await resetStep();
+    } catch (x) {
+      exceptions.push(x);
+    };
+  }
+  assert_equals(
+      exceptions.length,
+      0,
+      'testDeleteCookies failures: ' + exceptions);
+};
+
+// Helper to verify first-of-name get using async/await.
+//
+// Returns the first script-visible value of the __Host-COOKIENAME cookie or
+// undefined if no matching cookies are script-visible.
+let getOneSimpleOriginCookie = async () => {
+  let cookie = await cookieStore.get('__Host-COOKIENAME');
+  if (!cookie) return undefined;
+  return cookie.value;
+};
+
+// Returns the number of script-visible cookies whose names start with
+// __Host-COOKIEN
+let countMatchingSimpleOriginCookies = async () => {
+  let cookieList = await cookieStore.getAll({
+    name: '__Host-COOKIEN',
+    matchType: 'startsWith'
+  });
+  return cookieList.length;
+};
+
+// Set the secure implicit-domain cookie __Host-COOKIENAME with value
+// cookie-value on path / and session duration.
+let setOneSimpleOriginSessionCookie = async () => {
+  await cookieStore.set('__Host-COOKIENAME', 'cookie-value');
+};
+
+// Set the secure example.org-domain cookie __Secure-COOKIENAME with
+// value cookie-value on path /cgi-bin/ and 24 hour duration; domain
+// and path will be rewritten below.
+//
+// This uses a Date object for expiration.
+let setOneDaySecureCookieWithDate = async () => {
+  // one day ahead, ignoring a possible leap-second
+  let inTwentyFourHours = new Date(Date.now() + 24 * 60 * 60 * 1000);
+  await cookieStore.set('__Secure-COOKIENAME', 'cookie-value', {
+    path: '/cgi-bin/',
+    expires: inTwentyFourHours,
+    secure: true,
+    domain: 'example.org'
+  });
+};
+
+// Set the unsecured example.org-domain cookie LEGACYCOOKIENAME with
+// value cookie-value on path /cgi-bin/ and 24 hour duration; domain
+// and path will be rewritten below.
+//
+// This uses milliseconds since the start of the Unix epoch for
+// expiration.
+let setOneDayUnsecuredCookieWithMillisecondsSinceEpoch = async () => {
+  // one day ahead, ignoring a possible leap-second
+  let inTwentyFourHours = Date.now() + 24 * 60 * 60 * 1000;
+  await cookieStore.set('LEGACYCOOKIENAME', 'cookie-value', {
+    path: '/cgi-bin/',
+    expires: inTwentyFourHours,
+    secure: false,
+    domain: 'example.org'
+  });
+};
+
+// Delete the cookie written by
+// setOneDayUnsecuredCookieWithMillisecondsSinceEpoch.
+let deleteUnsecuredCookieWithDomainAndPath = async () => {
+  await cookieStore.delete('LEGACYCOOKIENAME', {
+    path: '/cgi-bin/',
+    secure: false,
+    domain: 'example.org'
+  });
+};
+
+
+// Set the secured example.org-domain cookie __Secure-COOKIENAME with
+// value cookie-value on path /cgi-bin/ and expiration in June of next
+// year; domain and path will be rewritten below.
+//
+// This uses an HTTP-style date string for expiration.
+let setSecureCookieWithHttpLikeExpirationString = async () => {
+  const year = (new Date()).getUTCFullYear() + 1;
+  const date = new Date('07 Jun ' + year + ' 07:07:07 UTC');
+  const day = ('Sun Mon Tue Wed Thu Fri Sat'.split(' '))[date.getUTCDay()];
+  await cookieStore.set('__Secure-COOKIENAME', 'cookie-value', {
+    path: '/cgi-bin/',
+    expires: day + ', 07 Jun ' + year + ' 07:07:07 GMT',
+    secure: true,
+    domain: 'example.org'
+  });
+};
+
+// Set three simple origin session cookies sequentially and ensure
+// they all end up in the cookie jar in order.
+let testThreeSimpleOriginSessionCookiesSetSequentially = async () => {
+  await cookieStore.set('__Host-1🍪', '🔵cookie-value1🔴');
+  await cookieStore.set('__Host-2🌟', '🌠cookie-value2🌠');
+  await cookieStore.set('__Host-3🌱', '🔶cookie-value3🔷');
+  // NOTE: this assumes no concurrent writes from elsewhere; it also
+  // uses three separate cookie jar read operations where a single getAll
+  // would be more efficient, but this way the CookieStore does the filtering
+  // for us.
+  let matchingValues = await Promise.all([ '1🍪', '2🌟', '3🌱' ].map(
+      async suffix => (await cookieStore.get('__Host-' + suffix)).value));
+  let actual = matchingValues.join(';');
+  let expected = '🔵cookie-value1🔴;🌠cookie-value2🌠;🔶cookie-value3🔷';
+  if (actual !== expected) throw new Error(
+      'Expected ' + JSON.stringify(expected) +
+        ' but got ' + JSON.stringify(actual));
+};
+
+// Set three simple origin session cookies in undefined order using
+// Promise.all and ensure they all end up in the cookie jar in any
+// order.
+let testThreeSimpleOriginSessionCookiesSetNonsequentially = async () => {
+  await Promise.all([
+    cookieStore.set('__Host-unordered1🍪', '🔵unordered-cookie-value1🔴'),
+    cookieStore.set('__Host-unordered2🌟', '🌠unordered-cookie-value2🌠'),
+    cookieStore.set('__Host-unordered3🌱', '🔶unordered-cookie-value3🔷')
+  ]);
+  // NOTE: this assumes no concurrent writes from elsewhere; it also
+  // uses three separate cookie jar read operations where a single getAll
+  // would be more efficient, but this way the CookieStore does the filtering
+  // for us and we do not need to sort.
+  let matchingCookies = await Promise.all([ '1🍪', '2🌟', '3🌱' ].map(
+      suffix => cookieStore.get('__Host-unordered' + suffix)));
+  let actual = matchingCookies.map(({ value }) => value).join(';');
+  let expected =
+      '🔵unordered-cookie-value1🔴;' +
+      '🌠unordered-cookie-value2🌠;' +
+      '🔶unordered-cookie-value3🔷';
+  if (actual !== expected) throw new Error(
+      'Expected ' + JSON.stringify(expected) +
+        ' but got ' + JSON.stringify(actual));
+};
+
+// Set an already-expired cookie.
+let setExpiredSecureCookieWithDomainPathAndFallbackValue = async () => {
+  let theVeryRecentPast = Date.now();
+  let expiredCookieSentinelValue = 'EXPIRED';
+  await cookieStore.set('__Secure-COOKIENAME', expiredCookieSentinelValue, {
+    path: '/cgi-bin/',
+    expires: theVeryRecentPast,
+    secure: true,
+    domain: 'example.org'
+  });
+};
+
+// Delete the __Host-COOKIENAME cookie created above.
+let deleteSimpleOriginCookie = async () => {
+  await cookieStore.delete('__Host-COOKIENAME');
+};
+
+// Delete the __Secure-COOKIENAME cookie created above.
+let deleteSecureCookieWithDomainAndPath = async () => {
+  await cookieStore.delete('__Secure-COOKIENAME', {
+    path: '/cgi-bin/',
+    domain: 'example.org',
+    secure: true
+  });
+};
+
+// Test for CookieObserver. Used in implementation of async observer-based
+// document.cookie simulator. This is passed to the Promise constructor after
+// rewriting.
+let testObservation_ = (resolve, reject) => {
+  // This will get invoked (asynchronously) shortly after the
+  // observe(...) call to provide an initial snapshot; in that case
+  // the length of cookieChanges may be 0, indicating no matching
+  // script-visible cookies for any URL+cookieStore currently
+  // observed. The CookieObserver instance is passed as the second
+  // parameter to allow additional calls to observe or disconnect.
+  let callback = (cookieChanges, observer) => {
+    var logEntry = [];
+    observationLog.push(logEntry);
+    const cookieChangesStrings = changes => changes.map(
+        ({type, name, value, index}) => cookieString(Object.assign(
+            new Array(observedStore.length),
+            {[index]: {
+              name: ((type === 'visible') ? '+' : '-') + name,
+              value: value
+            }})));
+    logEntry.push(['before', cookieString(observedStore)]);
+    logEntry.push(['changes', cookieChangesStrings(cookieChanges)]);
+    const newObservedStore = observedStore.slice(0);
+    try {
+      const insertions = [], deletions = [];
+      cookieChanges.forEach(({
+        cookieStore,
+        type,
+        url,
+        name,
+        value,
+        index,
+        all
+      }) => {
+        switch (type) {
+          case 'visible':
+            // Creation or modification (e.g. change in value, or
+            // removal of HttpOnly), or appearance to script due to
+            // change in policy or permissions
+            insertions.push([index, {name: name, value: value}]);
+            break;
+          case 'hidden':
+            // Deletion/expiration or disappearance (e.g. due to
+            // modification adding HttpOnly), or disappearance from
+            // script due to change in policy or permissions
+            assert_object_equals(
+                {name: name, value: value},
+                observedStore[index],
+                'Hidden cookie at index ' + index +
+                  ' was not the expected one: ' + JSON.stringify({
+                    got: {name: name, value: value},
+                    expected: observedStore[index]
+                  }));
+            deletions.push(index);
+            break;
+          default:
+            savedExceptions.push('Unexpected CookieChange type ' + type);
+            if (reject) reject(savedExceptions[savedExceptions.length - 1]);
+            throw savedExceptions[savedExceptions.length - 1];
+        }
+      });
+      deletions.sort((a, b) => b - a).forEach(
+          index => newObservedStore.splice(index, 1));
+      let bias = 0;
+      insertions.sort(([a], [b]) => a - b).forEach(([ index, cookie ]) => {
+        if (newObservedStore[index + bias] !== undefined) {
+          newObservedStore.splice(index, 0, cookie);
+          --bias;
+        } else {
+          newObservedStore[index] = cookie;
+        }
+      });
+      observedStore = newObservedStore.filter(entry => entry !== undefined);
+      logEntry.push(['after', cookieString(observedStore)]);
+      const reported =
+            cookieChanges && cookieChanges.length ?
+            cookieChanges[cookieChanges.length - 1].all :
+            [];
+      assert_equals(
+          cookieString(reported),
+          cookieString(observedStore),
+          'Mismatch between observed store and reported store.' +
+            '\n observed:\n ' + cookieString(observedStore) +
+            '\n reported:\n ' + cookieString(reported) +
+            '\n log:\n ' + observationLog.map(JSON.stringify).join('\n '));
+    } catch (e) {
+      logEntry.push([' *** ⚠ *** ERROR: EXCEPTION THROWN *** ⚠ *** ']);
+      savedExceptions.push('Exception in observer');
+      savedExceptions.push(e);
+      if (reject) reject(e);
+      throw e;
+    }
+    // Resolve promise after first callback
+    if (resolve) resolve(observer);
+    resolve = null;
+    reject = null;
+  };
+  CookieObserver.startTimer_ = (handler, ignoredDelay) => {
+    var timer = {shouldRun: true, fingerPrint: Math.random()};
+    new Promise(resolve => s\u0065tTimeout(resolve)).then(() => {
+      if (!timer.shouldRun) return;
+      CookieObserver.stopTimer_(timer);
+      handler();
+    });
+    return timer;
+  };
+  CookieObserver.stopTimer_ = timer => {
+    timer.shouldRun = false;
+  };
+  let observer = new CookieObserver(callback);
+  // If null or omitted this defaults to location.pathname up to and
+  // including the final '/' in a document context, or worker scope up
+  // to and including the final '/' in a service worker context.
+  let url = (location.pathname).replace(/[^\/]+$/, '');
+  // If null or omitted this defaults to interest in all
+  // script-visible cookies.
+  let interests = [
+    // Interested in all secure cookies named '__Secure-COOKIENAME';
+    // the default matchType is 'equals' at the given URL.
+    { name: '__Secure-COOKIENAME', url: url },
+    // Interested in all simple origin cookies named like
+    // /^__Host-COOKIEN.*$/ at the default URL.
+    { name: '__Host-COOKIEN', matchType: 'startsWith' },
+    // Interested in all simple origin cookies named '__Host-1🍪'
+    // at the default URL.
+    { name: '__Host-1🍪' },
+    // Interested in all cookies named 'OLDCOOKIENAME' at the given URL.
+    { name: 'OLDCOOKIENAME', matchType: 'equals', url: url },
+    // Interested in all simple origin cookies named like
+    // /^__Host-AUTHTOKEN.*$/ at the given URL.
+    { name: '__Host-AUTHTOKEN', matchType: 'startsWith', url: url + 'auth/' }
+  ];
+  observer.observe(cookieStore, interests);
+  // Default interest: all script-visible changes, default URL
+  observer.observe(cookieStore);
+};
+
+// Rewrite testObservation_ to use a path we are allowed to see from a
+// document context.
+//
+// FIXME: remove this once ServiceWorker support is implemented and
+// path observation can actually be verified at a sub-path.
+if (kHasDocument) {
+  testObservation_ = eval(String(testObservation_).split('auth/').join('auth'));
+}
+
+// Wrap testObservation_ to work as a promise.
+const testObservation = () => new Promise(testObservation_);
+
+// Verify behavior of no-name and no-value cookies.
+let testNoNameAndNoValue = async () => {
+  await cookieStore.set('', 'first-value');
+  let actual1 =
+      (await cookieStore.getAll('')).map(({ value }) => value).join(';');
+  let expected1 = 'first-value';
+  if (actual1 !== expected1) throw new Error(
+      'Expected ' + JSON.stringify(expected1) +
+        ' but got ' + JSON.stringify(actual1));
+  await cookieStore.set('', '');
+  let actual2 =
+      (await cookieStore.getAll('')).map(({ value }) => value).join(';');
+  let expected2 = '';
+  if (actual2 !== expected2) throw new Error(
+      'Expected ' + JSON.stringify(expected) +
+        ' but got ' + JSON.stringify(actual));
+  await cookieStore.delete('');
+  assert_equals(
+      await getCookieString(),
+      undefined,
+      'Empty cookie jar after testNoNameAndNoValue');
+  if (!kIsStatic) assert_equals(
+      await getCookieStringHttp(),
+      undefined,
+      'Empty HTTP cookie jar after testNoNameAndNoValue');
+  if (kHasDocument) assert_equals(
+      await getCookieStringDocument(),
+      undefined,
+      'Empty document.cookie cookie jar after testNoNameAndNoValue');
+  if (observer) assert_equals(
+      await getCookieStringObserved(),
+      undefined,
+      'Empty observed cookie jar after testNoNameAndNoValue');
+};
+
+// Verify behavior of multiple no-name cookies.
+let testNoNameMultipleValues = async () => {
+  await cookieStore.set('', 'first-value');
+  let actual1 =
+      (await cookieStore.getAll('')).map(({ value }) => value).join(';');
+  let expected1 = 'first-value';
+  if (actual1 !== expected1) throw new Error(
+      'Expected ' + JSON.stringify(expected1) +
+        ' but got ' + JSON.stringify(actual1));
+  await cookieStore.set('', 'second-value');
+  let actual2 =
+      (await cookieStore.getAll('')).map(({ value }) => value).join(';');
+  let expected2 = 'second-value';
+  if (actual2 !== expected2) throw new Error(
+      'Expected ' + JSON.stringify(expected2) +
+        ' but got ' + JSON.stringify(actual2));
+  await cookieStore.delete('');
+  assert_equals(
+      await getCookieString(),
+      undefined,
+      'Empty cookie jar after testNoNameMultipleValues');
+  if (!kIsStatic) assert_equals(
+      await getCookieStringHttp(),
+      undefined,
+      'Empty HTTP cookie jar after testNoNameMultipleValues');
+  if (observer) assert_equals(
+      await getCookieStringObserved(),
+      undefined,
+      'Empty observed cookie jar after testNoNameMultipleValues');
+};
+
+// Verify that attempting to set a cookie with no name and with '=' in
+// the value does not work.
+let testNoNameEqualsInValue = async () => {
+  await cookieStore.set('', 'first-value');
+  let actual1 =
+      (await cookieStore.getAll('')).map(({ value }) => value).join(';');
+  let expected1 = 'first-value';
+  if (actual1 !== expected1) throw new Error(
+      'Expected ' + JSON.stringify(expected1) +
+        ' but got ' + JSON.stringify(actual1));
+  try {
+    await cookieStore.set('', 'suspicious-value=resembles-name-and-value');
+  } catch (expectedError) {
+    let actual2 =
+        (await cookieStore.getAll('')).map(({ value }) => value).join(';');
+    let expected2 = 'first-value';
+    if (actual2 !== expected2) throw new Error(
+        'Expected ' + JSON.stringify(expected2) +
+          ' but got ' + JSON.stringify(actual2));
+    assert_equals(
+        await getCookieString(),
+        'first-value',
+        'Earlier cookie jar after rejected part of testNoNameEqualsInValue');
+    await cookieStore.delete('');
+    assert_equals(
+        await getCookieString(),
+        undefined,
+        'Empty cookie jar after cleanup in testNoNameEqualsInValue');
+    if (!kIsStatic) assert_equals(
+        await getCookieStringHttp(),
+        undefined,
+        'Empty HTTP cookie jar after cleanup in testNoNameEqualsInValue');
+    if (observer) assert_equals(
+        await getCookieStringObserved(),
+        undefined,
+        'Empty observed cookie jar after cleanup in testNoNameEqualsInValue');
+    return;
+  }
+  throw new Error(
+      'Expected promise rejection' +
+        ' when setting a cookie with no name and "=" in value');
+};
+
+// https://github.com/whatwg/html/issues/3076#issuecomment-332920132
+// proposes to remove <meta http-equiv="set-cookie" ... > but it is
+// not yet an accepted part of the HTML spec.
+//
+// Until the feature is gone, it interacts with other cookie APIs,
+// including this one.
+//
+// When kMetaHttpEquivSetCookieIsGone is set, verify that <meta
+// http-equiv="set-cookie" ... > no longer works. Otherwise, verify
+// its interoperability with other APIs.
+let testMetaHttpEquivSetCookie = async () => {
+  await setCookieStringMeta('META-🍪=🔵; path=/');
+  if (kMetaHttpEquivSetCookieIsGone) {
+    assert_equals(
+        await getCookieString(),
+        undefined,
+        'Empty cookie jar after no-longer-supported' +
+          ' <meta http-equiv="set-cookie" ... >');
+    if (!kIsStatic) assert_equals(
+        await getCookieStringHttp(),
+        undefined,
+        'Empty HTTP cookie jar after no-longer-supported' +
+          ' <meta http-equiv="set-cookie" ... >');
+    if (observer) assert_equals(
+        await getCookieStringObserved(),
+        undefined,
+        'Empty observed cookie jar after no-longer-supported' +
+          ' <meta http-equiv="set-cookie" ... >');
+  } else {
+    assert_equals(
+        await getCookieString(),
+        'META-🍪=🔵',
+        'Cookie we wrote using' +
+          ' <meta http-equiv="set-cookie" ... > in cookie jar');
+    if (!kIsStatic) assert_equals(
+        await getCookieStringHttp(),
+        'META-🍪=🔵',
+        'Cookie we wrote using' +
+          ' <meta http-equiv="set-cookie" ... > in HTTP cookie jar');
+    if (observer) assert_equals(
+        await getCookieStringObserved(),
+        'META-🍪=🔵',
+        'Cookie we wrote using' +
+          ' <meta http-equiv="set-cookie" ... > in observed cookie jar');
+    await setCookieStringMeta('META-🍪=DELETED; path=/; max-age=0');
+    assert_equals(
+        await getCookieString(),
+        undefined,
+        'Empty cookie jar after <meta http-equiv="set-cookie" ... >' +
+          ' cookie-clearing using max-age=0');
+    if (!kIsStatic) assert_equals(
+        await getCookieStringHttp(),
+        undefined,
+        'Empty HTTP cookie jar after <meta http-equiv="set-cookie" ... >' +
+          ' cookie-clearing using max-age=0');
+    if (observer) assert_equals(
+        await getCookieStringObserved(),
+        undefined,
+        'Empty observed cookie jar after <meta http-equiv="set-cookie" ... >' +
+          ' cookie-clearing using max-age=0');
+  }
+};
+
+// Verify interoperability of document.cookie with other APIs.
+let testDocumentCookie = async () => {
+  await setCookieStringDocument('DOCUMENT-🍪=🔵; path=/');
+  assert_equals(
+      await getCookieString(),
+      'DOCUMENT-🍪=🔵',
+      'Cookie we wrote using document.cookie in cookie jar');
+  if (!kIsStatic) assert_equals(
+      await getCookieStringHttp(),
+      'DOCUMENT-🍪=🔵',
+      'Cookie we wrote using document.cookie in HTTP cookie jar');
+  assert_equals(
+      await getCookieStringDocument(),
+      'DOCUMENT-🍪=🔵',
+      'Cookie we wrote using document.cookie in document.cookie');
+  if (observer) assert_equals(
+      await getCookieStringObserved(),
+      'DOCUMENT-🍪=🔵',
+      'Cookie we wrote using document.cookie in observed cookie jar');
+  await setCookieStringDocument('DOCUMENT-🍪=DELETED; path=/; max-age=0');
+  assert_equals(
+      await getCookieString(),
+      undefined,
+      'Empty cookie jar after document.cookie' +
+        ' cookie-clearing using max-age=0');
+  if (!kIsStatic) assert_equals(
+      await getCookieStringHttp(),
+      undefined,
+      'Empty HTTP cookie jar after document.cookie' +
+        ' cookie-clearing using max-age=0');
+  assert_equals(
+      await getCookieStringDocument(),
+      undefined,
+      'Empty document.cookie cookie jar after document.cookie' +
+        ' cookie-clearing using max-age=0');
+  if (observer) assert_equals(
+      await getCookieStringObserved(),
+      undefined,
+      'Empty observed cookie jar after document.cookie cookie-clearing' +
+        ' using max-age=0');
+};
+
+// Verify interoperability of HTTP Set-Cookie: with other APIs.
+let testHttpCookieAndSetCookieHeaders = async () => {
+  await setCookieStringHttp('HTTP-🍪=🔵; path=/');
+  assert_equals(
+      await getCookieString(),
+      'HTTP-🍪=🔵',
+      'Cookie we wrote using HTTP in cookie jar');
+  assert_equals(
+      await getCookieStringHttp(),
+      'HTTP-🍪=🔵',
+      'Cookie we wrote using HTTP in HTTP cookie jar');
+  if (observer) assert_equals(
+      await getCookieStringObserved(),
+      'HTTP-🍪=🔵',
+      'Cookie we wrote using HTTP in observed cookie jar');
+  await setCookieStringHttp('HTTP-🍪=DELETED; path=/; max-age=0');
+  assert_equals(
+      await getCookieString(),
+      undefined,
+      'Empty cookie jar after HTTP cookie-clearing using max-age=0');
+  assert_equals(
+      await getCookieStringHttp(),
+      undefined,
+      'Empty HTTP cookie jar after HTTP cookie-clearing using max-age=0');
+  if (observer) assert_equals(
+      await getCookieStringObserved(),
+      undefined,
+      'Empty observed cookie jar after HTTP cookie-clearing' +
+        ' using max-age=0');
+  await setCookieStringHttp('HTTPONLY-🍪=🔵; path=/; httponly');
+  assert_equals(
+      await getCookieString(),
+      undefined,
+      'HttpOnly cookie we wrote using HTTP in cookie jar' +
+        ' is invisible to script');
+  assert_equals(
+      await getCookieStringHttp(),
+      'HTTPONLY-🍪=🔵',
+      'HttpOnly cookie we wrote using HTTP in HTTP cookie jar');
+  if (observer) assert_equals(
+      await getCookieStringObserved(),
+      undefined,
+      'HttpOnly cookie we wrote using HTTP is invisible to observer');
+  await setCookieStringHttp(
+      'HTTPONLY-🍪=DELETED; path=/; max-age=0; httponly');
+  assert_equals(
+      await getCookieString(),
+      undefined,
+      'Empty cookie jar after HTTP cookie-clearing using max-age=0');
+  assert_equals(
+      await getCookieStringHttp(),
+      undefined,
+      'Empty HTTP cookie jar after HTTP cookie-clearing using max-age=0');
+  if (observer) assert_equals(
+      await getCookieStringObserved(),
+      undefined,
+      'Empty observed cookie jar after HTTP cookie-clearing' +
+        ' using max-age=0');
+  // Non-UTF-8 byte sequences cause the Set-Cookie to be dropped.
+  await setCookieBinaryHttp(
+      unescape(encodeURIComponent('HTTP-🍪=🔵')) + '\xef\xbf\xbd; path=/');
+  assert_equals(
+      await getCookieString(),
+      'HTTP-🍪=🔵\ufffd',
+      'Binary cookie we wrote using HTTP in cookie jar');
+  assert_equals(
+      await getCookieStringHttp(),
+      'HTTP-🍪=🔵\ufffd',
+      'Binary cookie we wrote using HTTP in HTTP cookie jar');
+  assert_equals(
+      decodeURIComponent(escape(await getCookieBinaryHttp())),
+      'HTTP-🍪=🔵\ufffd',
+      'Binary cookie we wrote in binary HTTP cookie jar');
+  assert_equals(
+      await getCookieBinaryHttp(),
+      unescape(encodeURIComponent('HTTP-🍪=🔵')) + '\xef\xbf\xbd',
+      'Binary cookie we wrote in binary HTTP cookie jar');
+  if (observer) assert_equals(
+      await getCookieStringObserved(),
+      'HTTP-🍪=🔵\ufffd',
+      'Binary cookie we wrote using HTTP in observed cookie jar');
+  await setCookieBinaryHttp(
+      unescape(encodeURIComponent('HTTP-🍪=DELETED; path=/; max-age=0')));
+  assert_equals(
+      await getCookieString(),
+      undefined,
+      'Empty cookie jar after binary HTTP cookie-clearing using max-age=0');
+  assert_equals(
+      await getCookieStringHttp(),
+      undefined,
+      'Empty HTTP cookie jar after' +
+        ' binary HTTP cookie-clearing using max-age=0');
+  assert_equals(
+      await getCookieBinaryHttp(),
+      undefined,
+      'Empty binary HTTP cookie jar after' +
+        ' binary HTTP cookie-clearing using max-age=0');
+  if (observer) assert_equals(
+      await getCookieStringObserved(),
+      undefined,
+      'Empty observed cookie jar after binary HTTP cookie-clearing' +
+        ' using max-age=0');
+};
+
+const testGetSetGetAll = async () => {
+  await cookieStore.set('TEST', 'value0');
+  assert_equals(
+      await getCookieString(),
+      'TEST=value0',
+      'Cookie jar contains only cookie we set');
+  if (!kIsStatic) assert_equals(
+      await getCookieStringHttp(),
+      'TEST=value0',
+      'HTTP cookie jar contains only cookie we set');
+  if (observer) assert_equals(
+      await getCookieStringObserved(),
+      'TEST=value0',
+      'Observed cookie jar contains only cookie we set');
+  await cookieStore.set('TEST', 'value');
+  assert_equals(
+      await getCookieString(),
+      'TEST=value',
+      'Cookie jar contains only cookie we overwrote');
+  if (!kIsStatic) assert_equals(
+      await getCookieStringHttp(),
+      'TEST=value',
+      'HTTP cookie jar contains only cookie we overwrote');
+  if (observer) assert_equals(
+      await getCookieStringObserved(),
+      'TEST=value',
+      'Observed cookie jar contains only cookie we overwrote');
+  let allCookies = await cookieStore.getAll();
+  assert_equals(
+      allCookies[0].name,
+      'TEST',
+      'First entry in allCookies should be named TEST');
+  assert_equals(
+      allCookies[0].value,
+      'value',
+      'First entry in allCookies should have value "value"');
+  assert_equals(
+      allCookies.length,
+      1,
+      'Only one cookie should exist in allCookies');
+  let firstCookie = await cookieStore.get();
+  assert_equals(
+      firstCookie.name,
+      'TEST',
+      'First cookie should be named TEST');
+  assert_equals(
+      firstCookie.value,
+      'value',
+      'First cookie should have value "value"');
+  let allCookies_TEST = await cookieStore.getAll('TEST');
+  assert_equals(
+      allCookies_TEST[0].name,
+      'TEST',
+      'First entry in allCookies_TEST should be named TEST');
+  assert_equals(
+      allCookies_TEST[0].value,
+      'value',
+      'First entry in allCookies_TEST should have value "value"');
+  assert_equals(
+      allCookies_TEST.length,
+      1,
+      'Only one cookie should exist in allCookies_TEST');
+  let firstCookie_TEST = await cookieStore.get('TEST');
+  assert_equals(
+      firstCookie_TEST.name,
+      'TEST',
+      'First TEST cookie should be named TEST');
+  assert_equals(
+      firstCookie_TEST.value,
+      'value',
+      'First TEST cookie should have value "value"');
+};
+
+const testOneSimpleOriginCookie = async testCase => {
+  await promise_rejects_when_unsecured(
+      testCase,
+      new SyntaxError(),
+      setOneSimpleOriginSessionCookie(),
+      '__Host- prefix only writable from' +
+        ' secure contexts (setOneSimpleOriginSessionCookie)');
+  if (!kIsUnsecured) {
+    assert_equals(
+        await getOneSimpleOriginCookie(),
+        'cookie-value',
+        '__Host-COOKIENAME cookie should be found' +
+          ' in a secure context (getOneSimpleOriginCookie)');
+  } else {
+    assert_equals(
+        await getOneSimpleOriginCookie(),
+        undefined,
+        '__Host-COOKIENAME cookie should not be found' +
+          ' in an unsecured context (getOneSimpleOriginCookie)');
+  }
+  if (kIsUnsecured) {
+    assert_equals(
+        await countMatchingSimpleOriginCookies(),
+        0,
+        'No __Host-COOKIEN* cookies should be found' +
+          ' in an unsecured context (countMatchingSimpleOriginCookies)');
+  } else {
+    assert_equals(
+        await countMatchingSimpleOriginCookies(),
+        1,
+        'One __Host-COOKIEN* cookie should be found' +
+          ' in a secure context (countMatchingSimpleOriginCookies)');
+  }
+};
+
+const testExpiration = async testCase => {
+  await promise_rejects_when_unsecured(
+      testCase,
+      new SyntaxError(),
+      setOneDaySecureCookieWithDate(),
+      'Secure cookies only writable' +
+        ' from secure contexts (setOneDaySecureCookieWithDate)');
+  await setOneDayUnsecuredCookieWithMillisecondsSinceEpoch();
+  assert_equals(
+      await getCookieString('LEGACYCOOKIENAME'),
+      'LEGACYCOOKIENAME=cookie-value',
+      'Ensure unsecured cookie we set is visible');
+  if (observer) assert_equals(
+      await getCookieStringObserved('LEGACYCOOKIENAME'),
+      'LEGACYCOOKIENAME=cookie-value',
+      'Ensure unsecured cookie we set is visible to observer');
+  await deleteUnsecuredCookieWithDomainAndPath();
+  await promise_rejects_when_unsecured(
+      testCase,
+      new SyntaxError(),
+      setSecureCookieWithHttpLikeExpirationString(),
+      'Secure cookies only writable from secure contexts' +
+        ' (setSecureCookieWithHttpLikeExpirationString)');
+};
+
+// Rewrite domain and path in affected cases to match current test
+// domain and directory.
+//
+// FIXME: remove these once ServiceWorker support and cross-domain
+// testing are added and full domain and path coverage is possible.
+setOneDaySecureCookieWithDate =
+    eval(String(setOneDaySecureCookieWithDate).split(
+        '/cgi-bin/').join(location.pathname.replace(/[^/]+$/, '')));
+setOneDaySecureCookieWithDate =
+    eval(String(setOneDaySecureCookieWithDate).split(
+        'example.org').join(location.hostname));
+setOneDayUnsecuredCookieWithMillisecondsSinceEpoch =
+    eval(String(setOneDayUnsecuredCookieWithMillisecondsSinceEpoch).split(
+        '/cgi-bin/').join(location.pathname.replace(/[^/]+$/, '')));
+setOneDayUnsecuredCookieWithMillisecondsSinceEpoch =
+    eval(String(setOneDayUnsecuredCookieWithMillisecondsSinceEpoch).split(
+        'example.org').join(location.hostname));
+deleteUnsecuredCookieWithDomainAndPath =
+    eval(String(deleteUnsecuredCookieWithDomainAndPath).split(
+        '/cgi-bin/').join(location.pathname.replace(/[^/]+$/, '')));
+deleteUnsecuredCookieWithDomainAndPath =
+    eval(String(deleteUnsecuredCookieWithDomainAndPath).split(
+        'example.org').join(location.hostname));
+setSecureCookieWithHttpLikeExpirationString =
+    eval(String(setSecureCookieWithHttpLikeExpirationString).split(
+        '/cgi-bin/').join(location.pathname.replace(/[^/]+$/, '')));
+setSecureCookieWithHttpLikeExpirationString =
+    eval(String(setSecureCookieWithHttpLikeExpirationString).split(
+        'example.org').join(location.hostname));
+setExpiredSecureCookieWithDomainPathAndFallbackValue =
+    eval(String(setExpiredSecureCookieWithDomainPathAndFallbackValue).split(
+        '/cgi-bin/').join(location.pathname.replace(/[^/]+$/, '')));
+setExpiredSecureCookieWithDomainPathAndFallbackValue =
+    eval(String(setExpiredSecureCookieWithDomainPathAndFallbackValue).split(
+        'example.org').join(location.hostname));
+deleteSecureCookieWithDomainAndPath =
+    eval(String(deleteSecureCookieWithDomainAndPath).split(
+        '/cgi-bin/').join(location.pathname.replace(/[^/]+$/, '')));
+deleteSecureCookieWithDomainAndPath =
+    eval(String(deleteSecureCookieWithDomainAndPath).split(
+        'example.org').join(location.hostname));
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/resources/cookie_helper.py b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/resources/cookie_helper.py
new file mode 100755
index 0000000..cf48f26e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/resources/cookie_helper.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Active wptserve handler for cookie operations.
+#
+# This must support the following requests:
+#
+# - GET with the following query parameters:
+#   - charset: (optional) character set for response (default: utf-8)
+#   A cookie: request header (if present) is echoed in the body with a
+#   cookie= prefix followed by the urlencoded bytes from the header.
+#   Used to inspect the cookie jar from an HTTP request header context.
+# - POST with form-data in the body and the following query-or-form parameters:
+#   - set-cookie: (optional; repeated) echoed in the set-cookie: response
+#     header and also echoed in the body with a set-cookie= prefix
+#     followed by the urlencoded bytes from the parameter; multiple occurrences
+#     are CRLF-delimited.
+#   Used to set cookies from an HTTP response header context.
+#
+# The response has 200 status and content-type: text/plain; charset=<charset>
+import cgi, encodings, os, re, sys, urllib
+
+# NOTE: These are intentionally very lax to permit testing
+DISALLOWED_IN_COOKIE_NAME_RE = re.compile(r'[;\0-\x1f\x7f]');
+DISALLOWED_IN_HEADER_RE = re.compile(r'[\0-\x1f\x7f]');
+
+# Ensure common charset names do not end up with different
+# capitalization or punctuation
+CHARSET_OVERRIDES = {
+    encodings.codecs.lookup(charset).name: charset
+    for charset in ('utf-8', 'iso-8859-1',)
+}
+
+def main(request, response):
+  assert request.method in (
+      'GET',
+      'POST',
+  ), 'request method was neither GET nor POST: %r' % request.method
+  qd = (request.url.split('#')[0].split('?', 1) + [''])[1]
+  if request.method == 'POST':
+    qd += '&' + request.body
+  args = cgi.parse_qs(qd, keep_blank_values = True)
+  charset = encodings.codecs.lookup(args.get('charset', ['utf-8'])[-1]).name
+  charset = CHARSET_OVERRIDES.get(charset, charset)
+  headers = [('content-type', 'text/plain; charset=' + charset)]
+  body = []
+  if request.method == 'POST':
+    for set_cookie in args.get('set-cookie', []):
+      if '=' in set_cookie.split(';', 1)[0]:
+        name, rest = set_cookie.split('=', 1)
+        assert re.search(
+            DISALLOWED_IN_COOKIE_NAME_RE,
+            name
+        ) is None, 'name had disallowed characters: %r' % name
+      else:
+        rest = set_cookie
+      assert re.search(
+          DISALLOWED_IN_HEADER_RE,
+          rest
+      ) is None, 'rest had disallowed characters: %r' % rest
+      headers.append(('set-cookie', set_cookie))
+      body.append('set-cookie=' + urllib.quote(set_cookie, ''))
+  else:
+    cookie = request.headers.get('cookie')
+    if cookie is not None:
+      body.append('cookie=' + urllib.quote(cookie, ''))
+  body = '\r\n'.join(body)
+  headers.append(('content-length', str(len(body))))
+  return 200, headers, body
diff --git a/third_party/WebKit/LayoutTests/external/wpt/async_cookies/resources/testharness-helpers.js b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/resources/testharness-helpers.js
new file mode 100644
index 0000000..a9c2374f9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/async_cookies/resources/testharness-helpers.js
@@ -0,0 +1,286 @@
+'use strict';
+
+// Length of final setTimeout when observer callback has not fired.
+//
+const kExtraObserverDelay = 0;  // For builtin implementation
+
+// NOTE: A polyfill was used for pre-implementation testing. To revive
+// it uncomment these and comment out the preceding line:
+//
+// const kExtraObserverDelay = 200;  // Polyfill when not running on battery
+// // const kExtraObserverDelay = 5000;  // ... when running on battery
+// document.open();
+// document.write(`
+//   <script>delete cookieStore</script>
+//   <script src="https://wicg.github.io/async-cookies-api/cookies.js">
+//   </script>
+// `);
+// document.close()
+
+// See https://github.com/whatwg/html/pull/3011#issuecomment-331187136
+// and https://www.chromestatus.com/feature/6170540112871424
+const kMetaHttpEquivSetCookieIsGone = true;
+
+// True when running in a document context as opposed to a worker context
+const kHasDocument = typeof document !== 'undefined';
+
+// Override for named test inclusion. Set by suite().
+let testOverride = undefined;
+
+// Determines whether the named test should be included in this run of the
+// suite. Only usable in a test runner context as this uses assert_equals.
+//
+// Parameters:
+//
+// - testName: (string) test name; must be an identifier starting with 'test'
+// - opt_excludeFromAll: (optional; boolean) if true, explicit or implicit
+//   #...&test=all (which is the default) will not activate this test.
+const includeTest = (testName, opt_excludeFromAll) => {
+  assert_equals(!!testName.match(/^test\w+/), true, 'includeTest: ' + testName);
+  assert_equals(typeof eval(testName), 'function', 'includeTest: ' + testName);
+  let testParams =
+        (location.hash || '#').substr(1).split('&').filter(
+            x => x.match(/^test=/)).map(x => decodeURIComponent(x));
+  if (!testParams.length) {
+    testParams = ['test=all'];
+    if (testOverride !== undefined) {
+      testParams = ['test=' + testOverride];
+    }
+  }
+  const filterSet =
+        testParams.map(x => x.split('=', 2)[1]).join(',').split(',').reduce(
+            (set, name) => Object.assign(set, {[name]: true}), {});
+  for (let name in filterSet) {
+    if (name === 'all' || !filterSet.hasOwnProperty(name)) continue;
+    assert_equals(!!name.match(/^test\w+/), true, '#test=' + testName);
+    assert_equals(typeof eval(name), 'function', '#test=' + testName);
+  }
+  return (filterSet.all && !opt_excludeFromAll) ||
+      filterSet.hasOwnProperty(testName) && filterSet[testName];
+}
+
+// True when running on unsecured 'http:' rather than secured 'https:'.
+const kIsUnsecured = location.protocol !== 'https:';
+
+// True when no CGI/no active wptserve handlers should be used.
+const kIsStatic = !!((location.hash || '#').match(/(^#|&)static=true(&|$)/) ||
+                     location.pathname.match(/_static\./));
+
+const kCookieHelperCgi = 'resources/cookie_helper.py';
+
+// Async wrapper for an async function or promise that is expected
+// reject in an unsecured (non-https:) context and work in a secured
+// (https:) context.
+//
+// Parameters:
+//
+// - testCase: (TestCase) test case context
+// - code: (Error class or number) expected rejection type in unsecured context
+// - promise: (thenable) test code
+// - message: (optional; string) message to forward to promise_rejects in
+//   unsecured context
+const promise_rejects_when_unsecured = async (
+    testCase,
+    code,
+    promise,
+    message = 'Feature unavailable from unsecured contexts'
+) => {
+  if (kIsUnsecured) await promise_rejects(testCase, code, promise, message);
+  else await promise;
+};
+
+// Converts a list of cookie records {name, value} to [name=]value; ... as
+// seen in Cookie: and document.cookie.
+//
+// Parameters:
+// - cookies: (array of {name, value}) records to convert
+//
+// Returns a string serializing the records, or undefined if no records were
+// given.
+const cookieString = cookies => cookies.length ? cookies.map((
+    {name, value}) => (name ? (name + '=') : '') + value).join('; ') :
+      undefined;
+
+// Approximate async equivalent to the document.cookie getter but with
+// important differences: optional additional getAll arguments are
+// forwarded, and an empty cookie jar returns undefined.
+//
+// This is intended primarily for verification against expected cookie
+// jar contents. It should produce more readable messages using
+// assert_equals in failing cases than assert_object_equals would
+// using parsed cookie jar contents and also allows expectations to be
+// written more compactly.
+const getCookieString = async (...args) => {
+  return cookieString(await cookieStore.getAll(...args));
+}
+
+// Approximate async equivalent to the document.cookie getter but from
+// the server's point of view. Returns UTF-8 interpretation. Allows
+// sub-path to be specified.
+//
+// Unlike document.cookie, this returns undefined when no cookies are
+// present.
+const getCookieStringHttp = async (extraPath = null) => {
+  if (kIsStatic) throw 'CGI not available in static HTML test';
+  const url =
+        kCookieHelperCgi + ((extraPath == null) ? '' : ('/' + extraPath));
+  const response = await fetch(url, { credentials: 'include' });
+  const text = await response.text();
+  assert_equals(
+      response.ok,
+      true,
+      'CGI should have succeeded in getCookieStringHttp\n' + text);
+  assert_equals(
+      response.headers.get('content-type'),
+      'text/plain; charset=utf-8',
+      'CGI did not return UTF-8 text in getCookieStringHttp');
+  if (text === '') return undefined;
+  assert_equals(
+      text.indexOf('cookie='),
+      0,
+      'CGI response did not begin with "cookie=" and was not empty: ' + text);
+  return decodeURIComponent(text.replace(/^cookie=/, ''));
+}
+
+// Approximate async equivalent to the document.cookie getter but from
+// the server's point of view. Returns binary string
+// interpretation. Allows sub-path to be specified.
+//
+// Unlike document.cookie, this returns undefined when no cookies are
+// present.
+const getCookieBinaryHttp = async (extraPath = null) => {
+  if (kIsStatic) throw 'CGI not available in static HTML test';
+  const url =
+        kCookieHelperCgi +
+        ((extraPath == null) ?
+         '' :
+         ('/' + extraPath)) + '?charset=iso-8859-1';
+  const response = await fetch(url, { credentials: 'include' });
+  const text = await response.text();
+  assert_equals(
+      response.ok,
+      true,
+      'CGI should have succeeded in getCookieBinaryHttp\n' + text);
+  assert_equals(
+      response.headers.get('content-type'),
+      'text/plain; charset=iso-8859-1',
+      'CGI did not return ISO 8859-1 text in getCookieBinaryHttp');
+  if (text === '') return undefined;
+  assert_equals(
+      text.indexOf('cookie='),
+      0,
+      'CGI response did not begin with "cookie=" and was not empty: ' + text);
+  return unescape(text.replace(/^cookie=/, ''));
+}
+
+// Approximate async equivalent to the document.cookie setter but from
+// the server's point of view.
+const setCookieStringHttp = async setCookie => {
+  if (kIsStatic) throw 'CGI not available in static HTML test';
+  const encodedSetCookie = encodeURIComponent(setCookie);
+  const url = kCookieHelperCgi;
+  const headers = new Headers();
+  headers.set(
+      'content-type',
+      'application/x-www-form-urlencoded; charset=utf-8');
+  const response = await fetch(
+      url,
+      {
+        credentials: 'include',
+        method: 'POST',
+        headers: headers,
+        body: 'set-cookie=' + encodedSetCookie,
+      });
+  const text = await response.text();
+  assert_equals(
+      response.ok,
+      true,
+      'CGI should have succeeded in setCookieStringHttp set-cookie: ' +
+        setCookie + '\n' + text);
+  assert_equals(
+      response.headers.get('content-type'),
+      'text/plain; charset=utf-8',
+      'CGI did not return UTF-8 text in setCookieStringHttp');
+  assert_equals(
+      text,
+      'set-cookie=' + encodedSetCookie,
+      'CGI did not faithfully echo the set-cookie value');
+};
+
+// Approximate async equivalent to the document.cookie setter but from
+// the server's point of view. This version sets a binary cookie rather
+// than a UTF-8 one.
+const setCookieBinaryHttp = async setCookie => {
+  if (kIsStatic) throw 'CGI not available in static HTML test';
+  const encodedSetCookie = escape(setCookie).split('/').join('%2F');
+  const url = kCookieHelperCgi + '?charset=iso-8859-1';
+  const headers = new Headers();
+  headers.set(
+      'content-type',
+      'application/x-www-form-urlencoded; charset=iso-8859-1');
+  const response = await fetch(url, {
+    credentials: 'include',
+    method: 'POST',
+    headers: headers,
+    body: 'set-cookie=' + encodedSetCookie
+  });
+  const text = await response.text();
+  assert_equals(
+      response.ok,
+      true,
+      'CGI should have succeeded in setCookieBinaryHttp set-cookie: ' +
+        setCookie + '\n' + text);
+  assert_equals(
+      response.headers.get('content-type'),
+      'text/plain; charset=iso-8859-1',
+      'CGI did not return Latin-1 text in setCookieBinaryHttp');
+  assert_equals(
+      text,
+      'set-cookie=' + encodedSetCookie,
+      'CGI did not faithfully echo the set-cookie value');
+};
+
+// Approximate async equivalent to the document.cookie setter but using
+// <meta http-equiv="set-cookie" content="..."> written into a temporary
+// IFRAME. Merely appending the node to HEAD works in some browsers (e.g.
+// Chromium) but not others (e.g. Firefox.)
+const setCookieStringMeta = async setCookie => {
+  if (document.readyState !== 'complete') {
+    await new Promise(resolve => addEventListener('load', resolve, true));
+  }
+  const meta = Object.assign(document.createElement('meta'), {
+    httpEquiv: 'set-cookie',
+    content: setCookie
+  });
+  const ifr = document.createElement('iframe');
+  await new Promise(resolve => document.body.appendChild(Object.assign(
+      ifr,
+      {
+        onload: resolve
+      })));
+  try {
+    ifr.contentWindow.document.open('text/html; charset=utf-8');
+    ifr.contentWindow.document.write([
+      '<!DOCTYPE html>',
+      '<meta charset="utf-8">',
+      meta.outerHTML
+    ].join('\r\n'));
+    ifr.contentWindow.document.close();
+  } finally {
+    if (ifr.parentNode) ifr.parentNode.removeChild(ifr);
+  }
+};
+
+// Async document.cookie getter; converts '' to undefined which loses
+// information in the edge case where a single ''-valued anonymous
+// cookie is visible.
+const getCookieStringDocument = async () => {
+  if (!kHasDocument) throw 'document.cookie not available in this context';
+  return String(document.cookie || '') || undefined;
+};
+
+// Async document.cookie setter
+const setCookieStringDocument = async setCookie => {
+  if (!kHasDocument) throw 'document.cookie not available in this context';
+  document.cookie = setCookie;
+};
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/websocket/resources/simple.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/websocket-worker.js
similarity index 75%
rename from third_party/WebKit/LayoutTests/http/tests/serviceworker/websocket/resources/simple.js
rename to third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/websocket-worker.js
index 6b7c5ec..bb2dc81 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/websocket/resources/simple.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/websocket-worker.js
@@ -8,7 +8,7 @@
 onmessage = event => {
   port = event.source;
 
-  const ws = new WebSocket('ws://localhost:8880/echo');
+  const ws = new WebSocket('wss://{{host}}:{{ports[wss][0]}}/echo');
   ws.onopen = () => {
     ws.send('Hello');
   };
@@ -21,9 +21,9 @@
     received = true;
     ws.close();
   };
-  ws.onclose = () => {
+  ws.onclose = (event) => {
     if (!received) {
-      reportFailure('Closed before receiving reply');
+      reportFailure('Closed before receiving reply: ' + event.code);
       return;
     }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/websocket/websocket-in-service-worker.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/websocket-in-service-worker.https.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/http/tests/serviceworker/websocket/websocket-in-service-worker.html
rename to third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/websocket-in-service-worker.https.html
index 3955ee77..cda9d6fe 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/websocket/websocket-in-service-worker.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/websocket-in-service-worker.https.html
@@ -2,10 +2,10 @@
 <title>Service Worker: WebSockets can be created in a Service Worker</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="../resources/test-helpers.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
 <script>
 promise_test(t => {
-    const SCRIPT = 'resources/simple.js';
+    const SCRIPT = 'resources/websocket-worker.js?pipe=sub';
     const SCOPE = 'resources/blank.html';
     let registration;
     return service_worker_unregister_and_register(t, SCRIPT, SCOPE)
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/absolute-position-change-containing-block-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/absolute-position-change-containing-block-expected.txt
index 97014db..086d3f2 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/absolute-position-change-containing-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/absolute-position-change-containing-block-expected.txt
@@ -29,11 +29,11 @@
     },
     {
       "object": "LayoutBlockFlow DIV id='container' class='fixed blue'",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "LayoutBlockFlow (positioned) DIV class='absolute green'",
-      "reason": "geometry"
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/change-transform-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/change-transform-expected.txt
index 2d634955..bf1b532 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/change-transform-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/change-transform-expected.txt
@@ -32,7 +32,7 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow DIV id='square'",
-      "reason": "geometry"
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-added-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-added-expected.txt
index 50f9731..d3a6e86 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-added-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-added-expected.txt
@@ -20,12 +20,27 @@
       "backgroundColor": "#0000FF",
       "paintInvalidations": [
         {
+          "object": "LayoutBlockFlow (positioned) DIV id='container'",
+          "rect": [0, 0, 100, 100],
+          "reason": "style change"
+        },
+        {
           "object": "LayoutBlockFlow (positioned) DIV class='fixed'",
           "rect": [50, 50, 75, 75],
           "reason": "appeared"
         }
       ]
     }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow (positioned) DIV id='container'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow (positioned) DIV class='fixed'",
+      "reason": "style change"
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-added-individual-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-added-individual-expected.txt
index 50f9731..d3a6e86 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-added-individual-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-added-individual-expected.txt
@@ -20,12 +20,27 @@
       "backgroundColor": "#0000FF",
       "paintInvalidations": [
         {
+          "object": "LayoutBlockFlow (positioned) DIV id='container'",
+          "rect": [0, 0, 100, 100],
+          "reason": "style change"
+        },
+        {
           "object": "LayoutBlockFlow (positioned) DIV class='fixed'",
           "rect": [50, 50, 75, 75],
           "reason": "appeared"
         }
       ]
     }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow (positioned) DIV id='container'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow (positioned) DIV class='fixed'",
+      "reason": "style change"
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-removed-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-removed-expected.txt
index 6df2399e..a5314db 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-removed-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-removed-expected.txt
@@ -21,6 +21,11 @@
       "backgroundColor": "#0000FF",
       "paintInvalidations": [
         {
+          "object": "LayoutBlockFlow (positioned) DIV id='container'",
+          "rect": [0, 0, 100, 100],
+          "reason": "style change"
+        },
+        {
           "object": "LayoutBlockFlow (positioned) DIV class='fixed'",
           "rect": [50, 50, 75, 75],
           "reason": "disappeared"
@@ -30,8 +35,12 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "LayoutBlockFlow (positioned) DIV id='container'",
+      "reason": "style change"
+    },
+    {
       "object": "LayoutBlockFlow (positioned) DIV class='fixed'",
-      "reason": "geometry"
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-removed-individual-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-removed-individual-expected.txt
index bb7844a..45a9668 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-removed-individual-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/containing-block-removed-individual-expected.txt
@@ -22,6 +22,11 @@
       "backgroundColor": "#0000FF",
       "paintInvalidations": [
         {
+          "object": "LayoutBlockFlow (positioned) DIV id='container'",
+          "rect": [0, 0, 100, 100],
+          "reason": "style change"
+        },
+        {
           "object": "LayoutBlockFlow (positioned) DIV class='fixed'",
           "rect": [50, 50, 75, 75],
           "reason": "disappeared"
@@ -31,8 +36,12 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "LayoutBlockFlow (positioned) DIV id='container'",
+      "reason": "style change"
+    },
+    {
       "object": "LayoutBlockFlow (positioned) DIV class='fixed'",
-      "reason": "geometry"
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/invalidate-when-leaving-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/invalidate-when-leaving-squashed-layer-expected.txt
index e630a34..dfa0a35 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/invalidate-when-leaving-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/compositing/invalidate-when-leaving-squashed-layer-expected.txt
@@ -68,7 +68,7 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow (positioned) DIV id='target'",
-      "reason": "compositing update"
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/containing-block-position-change-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/containing-block-position-change-expected.txt
index c198708..8cc4a0f 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/containing-block-position-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/containing-block-position-change-expected.txt
@@ -9,12 +9,12 @@
         {
           "object": "LayoutBlockFlow (positioned) DIV",
           "rect": [158, 74, 50, 50],
-          "reason": "geometry"
+          "reason": "style change"
         },
         {
           "object": "LayoutBlockFlow (positioned) DIV",
           "rect": [100, 74, 50, 50],
-          "reason": "geometry"
+          "reason": "style change"
         }
       ]
     }
@@ -26,7 +26,7 @@
     },
     {
       "object": "LayoutBlockFlow (positioned) DIV",
-      "reason": "geometry"
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-after-scroll-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-after-scroll-expected.txt
index 24100a90..1365636 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-after-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-after-scroll-expected.txt
@@ -35,6 +35,10 @@
     {
       "object": "LayoutBlockFlow (positioned) DIV id='t' class='green absolute'",
       "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow (positioned) DIV id='t' class='green absolute'",
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-and-absolute-position-scrolled-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-and-absolute-position-scrolled-expected.txt
index f9f3cec..b6ac27f9 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-and-absolute-position-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-and-absolute-position-scrolled-expected.txt
@@ -33,11 +33,11 @@
     },
     {
       "object": "LayoutBlockFlow DIV id='container' class='relative'",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "LayoutBlockFlow (positioned) DIV id='absoluteDiv' class='absolute green'",
-      "reason": "geometry"
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-position-transparency-with-overflow-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-position-transparency-with-overflow-expected.txt
index 357236dd..314a85a 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-position-transparency-with-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-position-transparency-with-overflow-expected.txt
@@ -18,6 +18,10 @@
     {
       "object": "LayoutBlockFlow (relative positioned) DIV id='container' class='relative blue'",
       "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow (positioned) DIV class='absolute green'",
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-to-relative-position-with-absolute-child-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-to-relative-position-with-absolute-child-expected.txt
index f781d731..a4f2b10 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-to-relative-position-with-absolute-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/fixed-to-relative-position-with-absolute-child-expected.txt
@@ -9,22 +9,22 @@
         {
           "object": "LayoutBlockFlow (positioned) DIV class='absolute green'",
           "rect": [108, 308, 100, 100],
-          "reason": "geometry"
+          "reason": "style change"
         },
         {
           "object": "LayoutBlockFlow (positioned) DIV class='absolute green'",
           "rect": [108, 300, 100, 100],
-          "reason": "geometry"
+          "reason": "style change"
         },
         {
           "object": "LayoutBlockFlow (relative positioned) DIV id='container' class='fixed blue'",
           "rect": [8, 208, 100, 100],
-          "reason": "geometry"
+          "reason": "style change"
         },
         {
           "object": "LayoutBlockFlow (relative positioned) DIV id='container' class='fixed blue'",
           "rect": [8, 200, 100, 100],
-          "reason": "geometry"
+          "reason": "style change"
         }
       ]
     }
@@ -44,11 +44,11 @@
     },
     {
       "object": "LayoutBlockFlow (relative positioned) DIV id='container' class='fixed blue'",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "LayoutBlockFlow (positioned) DIV class='absolute green'",
-      "reason": "geometry"
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt
index 23a8ed4..afd26e9 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt
@@ -30,6 +30,50 @@
     {
       "object": "LayoutBlockFlow DIV id='container'",
       "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow (positioned) DIV id='absolute'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow P",
+      "reason": "style change"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "style change"
+    },
+    {
+      "object": "InlineTextBox 'This test checks that switching opacity'",
+      "reason": "style change"
+    },
+    {
+      "object": "InlineTextBox 'invalidates the full subtree.'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow P",
+      "reason": "style change"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "style change"
+    },
+    {
+      "object": "InlineTextBox 'This text should be visible in the'",
+      "reason": "style change"
+    },
+    {
+      "object": "InlineTextBox 'output.'",
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/mix-blend-mode-separate-stacking-context-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/mix-blend-mode-separate-stacking-context-expected.txt
index e765a7be..c253b2e 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/mix-blend-mode-separate-stacking-context-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/mix-blend-mode-separate-stacking-context-expected.txt
@@ -80,6 +80,10 @@
     {
       "object": "LayoutBlockFlow (relative positioned) (floating) DIV id='fourth'",
       "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow (floating) DIV",
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/stacking-context-lost-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/stacking-context-lost-expected.txt
index d2e747bb..a9b429a 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/stacking-context-lost-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/stacking-context-lost-expected.txt
@@ -30,7 +30,7 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow (relative positioned) DIV id='outer'",
-      "reason": "background"
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/svg/transform-foreign-object-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/svg/transform-foreign-object-expected.txt
index 9f4690d..7652cfc 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/svg/transform-foreign-object-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/svg/transform-foreign-object-expected.txt
@@ -18,6 +18,16 @@
         }
       ]
     }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutSVGForeignObject foreignObject",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow DIV",
+      "reason": "style change"
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/svg/transform-text-element-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/svg/transform-text-element-expected.txt
index 9cfe745..fba511f 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/svg/transform-text-element-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/svg/transform-text-element-expected.txt
@@ -22,19 +22,19 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutSVGText text",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "RootInlineBox",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineTextBox 'Test'",
-      "reason": "geometry"
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/transform-inline-layered-child-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/transform-inline-layered-child-expected.txt
index c17d83a..f92b8d4 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/transform-inline-layered-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v175/paint/invalidation/transform-inline-layered-child-expected.txt
@@ -62,95 +62,95 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow (positioned) DIV id='box'",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "RootInlineBox",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "LayoutInline (relative positioned) SPAN id='child'",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "LayoutText #text",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineTextBox 'A B C'",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineTextBox 'D E F'",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineTextBox 'G H I'",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineTextBox 'J K L'",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineTextBox 'M N O'",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineTextBox 'P Q R'",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineTextBox 'S T U'",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineTextBox 'V W X'",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "InlineTextBox 'Y Z'",
-      "reason": "geometry"
+      "reason": "style change"
     },
     {
       "object": "LayoutText #text",
-      "reason": "geometry"
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/chunked-file-reader.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/chunked-file-reader.js
similarity index 71%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/chunked-file-reader.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/chunked-file-reader.js
index 4ae4c37..cd107a0 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/chunked-file-reader.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/chunked-file-reader.js
@@ -1,10 +1,12 @@
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-<script src="../../inspector/inspector-test.js"></script>
-<script>
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-async function test() {
+(async function() {
+  TestRunner.addResult(
+      `This tests that ChunkedFileReader properly re-assembles chunks, especially in case these contain multibyte characters.\n`);
+
+
   var text = [
     'Латынь из моды вышла ныне:\n', 'Так, если правду вам сказать,\n', 'Он знал довольно по-латыне,\n',
     'Чтоб эпиграфы разбирать\n'
@@ -25,15 +27,4 @@
   TestRunner.assertEquals(text.join(''), output.data(), 'Read text is different from written text');
   TestRunner.addResult('DONE');
   TestRunner.completeTest();
-}
-
-</script>
-</head>
-
-<body onload="runTest()">
-<p>
-This tests that ChunkedFileReader properly re-assembles chunks, especially in case these contain multibyte characters.
-</p>
-
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/color.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/color.js
similarity index 88%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/color.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/color.js
index 2a9396577..a3f00b89 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/color.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/color.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script type="text/javascript">
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-var test = function() {
+(async function() {
+  TestRunner.addResult(`Tests Common.Color\n`);
+
+
   function dumpColor(colorText) {
     var color = Common.Color.parse(colorText);
     TestRunner.addResult('Dumping \'' + colorText + '\' in different formats:');
@@ -53,11 +55,4 @@
   dumpColor('#1234');
   dumpColor('#0FF');
   TestRunner.completeTest();
-};
-
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests Common.Color</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/cookie-parser.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/cookie-parser.html
deleted file mode 100644
index 72a8e02e..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/cookie-parser.html
+++ /dev/null
@@ -1,81 +0,0 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script type="text/javascript">
-
-function initialize_CookieTests()
-{
-
-InspectorTest.dumpCookie = function(cookie)
-{
-    var requestDate = new Date("Mon Oct 18 2010 17:00:00 GMT+0000");
-    var expires = cookie.expiresDate(requestDate);
-
-    var output = "name: " + cookie.name() + ", value: " + cookie.value() + ", httpOnly: " + cookie.httpOnly() +
-        ", sameSite: " + cookie.sameSite() + ", secure: " + cookie.secure() +
-        ", session: " + cookie.session() + ", path: " + cookie.path() +
-        ", domain: " + cookie.domain() + ", port: " + cookie.port() +
-        ", expires: " + (expires ? expires.getTime() : "n/a") +
-        ", size: " + cookie.size();
-
-    TestRunner.addResult(output);
-    TestRunner.addObject(cookie.attributes());
-}
-
-InspectorTest.dumpCookies = function(cookies)
-{
-    for (var i = 0; i < cookies.length; ++i)
-        InspectorTest.dumpCookie(cookies[i]);
-}
-
-InspectorTest.parseAndDumpCookie = function(header)
-{
-    var parser = new SDK.CookieParser();
-    TestRunner.addResult("source: " + header);
-    InspectorTest.dumpCookies(parser.parseCookie(header));
-}
-
-InspectorTest.parseAndDumpSetCookie = function(header)
-{
-    var parser = new SDK.CookieParser();
-    TestRunner.addResult("source: " + header);
-    InspectorTest.dumpCookies(parser.parseSetCookie(header));
-}
-
-}
-
-var test = function() {
-  InspectorTest.parseAndDumpCookie('cookie=value');
-  InspectorTest.parseAndDumpCookie('$version=1; a=b,c  =   d, e=f');
-  InspectorTest.parseAndDumpCookie('$version=1; a=b;c  =   d; e =f');
-  InspectorTest.parseAndDumpCookie('cooke1 = value1; another cookie = another value');
-  InspectorTest.parseAndDumpCookie('cooke1 = value; $Path=/; $Domain=.example.com;');
-  InspectorTest.parseAndDumpCookie(
-      'cooke1 = value; $Path=/; $Domain=.example.com ; Cookie2 = value2; $Path = /foo; $DOMAIN = foo.example.com;');
-  InspectorTest.parseAndDumpCookie(
-      'cooke1 = value; $Path=/; $Domain=.example.com\nCookie2 = value2; $Path = /foo; $DOMAIN = foo.example.com; ');
-  InspectorTest.parseAndDumpCookie(
-      '$version =1; cooke1 = value; $Path=/; $Domain   =.example.com;  \n Cookie2 = value2; $Path = /foo; $DOMAIN = foo.example.com;');
-
-  InspectorTest.parseAndDumpSetCookie('cookie=value');
-  InspectorTest.parseAndDumpSetCookie('a=b\n c=d\n f');
-  InspectorTest.parseAndDumpSetCookie('cooke1 = value; Path=/; Domain=.example.com;');
-  InspectorTest.parseAndDumpSetCookie(
-      'cooke1 = value; Path=/; Domain=  .example.com \nCookie2 = value2; Path = /foo; Domain = foo.example.com');
-  InspectorTest.parseAndDumpSetCookie(
-      'cooke1 = value; expires = Mon, Oct 18 2010 17:00 GMT+0000; Domain   =.example.com\nCookie2 = value2; Path = /foo; DOMAIN = foo.example.com; HttpOnly; Secure; Discard;');
-  InspectorTest.parseAndDumpSetCookie(
-      'cooke1 = value; max-age= 1440; Domain   =.example.com\n Cookie2 = value2; Path = /foo; DOMAIN = foo.example.com; HttpOnly; Secure; Discard;');
-  InspectorTest.parseAndDumpSetCookie('cooke1 = value; HttpOnly; Secure; SameSite=Lax;');
-  InspectorTest.parseAndDumpSetCookie('cooke1 = value; HttpOnly; Secure; SameSite=Secure;');
-  InspectorTest.parseAndDumpSetCookie('cooke1; Path=/; Domain=.example.com;');
-  InspectorTest.parseAndDumpSetCookie('cooke1=; Path=/; Domain=.example.com;');
-  TestRunner.completeTest();
-};
-
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests inspector cookie parser</p>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/cookie-parser.js b/third_party/WebKit/LayoutTests/http/tests/devtools/components/cookie-parser.js
new file mode 100644
index 0000000..2102329
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/cookie-parser.js
@@ -0,0 +1,65 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Tests inspector cookie parser\n`);
+
+
+  TestRunner.dumpCookie = function(cookie) {
+    var requestDate = new Date('Mon Oct 18 2010 17:00:00 GMT+0000');
+    var expires = cookie.expiresDate(requestDate);
+
+    var output = 'name: ' + cookie.name() + ', value: ' + cookie.value() + ', httpOnly: ' + cookie.httpOnly() +
+        ', sameSite: ' + cookie.sameSite() + ', secure: ' + cookie.secure() + ', session: ' + cookie.session() +
+        ', path: ' + cookie.path() + ', domain: ' + cookie.domain() + ', port: ' + cookie.port() +
+        ', expires: ' + (expires ? expires.getTime() : 'n/a') + ', size: ' + cookie.size();
+
+    TestRunner.addResult(output);
+    TestRunner.addObject(cookie.attributes());
+  };
+
+  TestRunner.dumpCookies = function(cookies) {
+    for (var i = 0; i < cookies.length; ++i)
+      TestRunner.dumpCookie(cookies[i]);
+  };
+
+  TestRunner.parseAndDumpCookie = function(header) {
+    var parser = new SDK.CookieParser();
+    TestRunner.addResult('source: ' + header);
+    TestRunner.dumpCookies(parser.parseCookie(header));
+  };
+
+  TestRunner.parseAndDumpSetCookie = function(header) {
+    var parser = new SDK.CookieParser();
+    TestRunner.addResult('source: ' + header);
+    TestRunner.dumpCookies(parser.parseSetCookie(header));
+  };
+
+  TestRunner.parseAndDumpCookie('cookie=value');
+  TestRunner.parseAndDumpCookie('$version=1; a=b,c  =   d, e=f');
+  TestRunner.parseAndDumpCookie('$version=1; a=b;c  =   d; e =f');
+  TestRunner.parseAndDumpCookie('cooke1 = value1; another cookie = another value');
+  TestRunner.parseAndDumpCookie('cooke1 = value; $Path=/; $Domain=.example.com;');
+  TestRunner.parseAndDumpCookie(
+      'cooke1 = value; $Path=/; $Domain=.example.com ; Cookie2 = value2; $Path = /foo; $DOMAIN = foo.example.com;');
+  TestRunner.parseAndDumpCookie(
+      'cooke1 = value; $Path=/; $Domain=.example.com\nCookie2 = value2; $Path = /foo; $DOMAIN = foo.example.com; ');
+  TestRunner.parseAndDumpCookie(
+      '$version =1; cooke1 = value; $Path=/; $Domain   =.example.com;  \n Cookie2 = value2; $Path = /foo; $DOMAIN = foo.example.com;');
+
+  TestRunner.parseAndDumpSetCookie('cookie=value');
+  TestRunner.parseAndDumpSetCookie('a=b\n c=d\n f');
+  TestRunner.parseAndDumpSetCookie('cooke1 = value; Path=/; Domain=.example.com;');
+  TestRunner.parseAndDumpSetCookie(
+      'cooke1 = value; Path=/; Domain=  .example.com \nCookie2 = value2; Path = /foo; Domain = foo.example.com');
+  TestRunner.parseAndDumpSetCookie(
+      'cooke1 = value; expires = Mon, Oct 18 2010 17:00 GMT+0000; Domain   =.example.com\nCookie2 = value2; Path = /foo; DOMAIN = foo.example.com; HttpOnly; Secure; Discard;');
+  TestRunner.parseAndDumpSetCookie(
+      'cooke1 = value; max-age= 1440; Domain   =.example.com\n Cookie2 = value2; Path = /foo; DOMAIN = foo.example.com; HttpOnly; Secure; Discard;');
+  TestRunner.parseAndDumpSetCookie('cooke1 = value; HttpOnly; Secure; SameSite=Lax;');
+  TestRunner.parseAndDumpSetCookie('cooke1 = value; HttpOnly; Secure; SameSite=Secure;');
+  TestRunner.parseAndDumpSetCookie('cooke1; Path=/; Domain=.example.com;');
+  TestRunner.parseAndDumpSetCookie('cooke1=; Path=/; Domain=.example.com;');
+  TestRunner.completeTest();
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/cookies-table.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/cookies-table.js
similarity index 95%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/cookies-table.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/cookies-table.js
index 5ad2f2a0..2b6adeb 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/cookies-table.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/cookies-table.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script type="text/javascript">
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-var test = function() {
+(async function() {
+  TestRunner.addResult(`Tests inspector cookies table\n`);
+
+
   function dumpCookies(cookies) {
     TestRunner.addResult(cookies.map(x => x.name()).join(','));
   }
@@ -153,11 +155,4 @@
   }
 
   self.runtime.loadModulePromise('cookie_table').then(run);
-};
-
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests inspector cookies table</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/css-shadow-model.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/css-shadow-model.js
similarity index 90%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/css-shadow-model.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/css-shadow-model.js
index 96222b24..3b4fbf5 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/css-shadow-model.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/css-shadow-model.js
@@ -1,12 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script>
-var initialize_Test = function() {
-    InspectorTest.preloadModule("inline_editor");
-};
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-function test() {
+(async function() {
+  TestRunner.addResult(`Tests CSSLength.parse, CSSShadowModel.parseTextShadow, and CSSShadowModel.parseBoxShadow.\n`);
+  await TestRunner.loadModule("inline_editor");
+
   TestRunner.addResult('-----CSSLengths-----');
   dumpCSSLength('10px');
   dumpCSSLength('10PX');
@@ -111,12 +110,4 @@
     var statusText = shadows.length !== 0 ? 'Succeeded: ' + output.join(', ') : 'Failed';
     TestRunner.addResult('"' + shadowText + '", Parsing ' + statusText);
   }
-}
-
-</script>
-</head>
-
-<body onload="runTest()">
-<p>Tests CSSLength.parse, CSSShadowModel.parseTextShadow, and CSSShadowModel.parseBoxShadow.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid-autosize-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid-autosize-expected.txt
index 99ca81d..57644a6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid-autosize-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid-autosize-expected.txt
@@ -1,6 +1,5 @@
 Tests DataGrid column auto size calculation.
 
-Bug 101363
 Auto sizing [198,2,400], minPercent=90, maxPercent=undefined
     [33,33,34]
 Auto sizing [1000], minPercent=5, maxPercent=undefined
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid-autosize.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid-autosize.js
similarity index 73%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid-autosize.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid-autosize.js
index 6b9df23..1d0f373 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid-autosize.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid-autosize.js
@@ -1,8 +1,13 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script type="text/javascript">
-function test() {
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Tests DataGrid column auto size calculation.\n`);
+  await TestRunner.loadHTML(`
+      <a href="https://bugs.webkit.org/show_bug.cgi?id=101363">Bug 101363</a>
+    `);
+
   runtime.loadModulePromise('data_grid').then(function() {
     function testAutoSize(widths, minPercent, maxPercent) {
       TestRunner.addResult(
@@ -27,12 +32,4 @@
     testAutoSize([3, 10, 7, 7, 13, 13, 9, 10, 15, 15, 20, 20, 14, 14, 12, 12, 12, 10, 9, 14, 10, 6, 7, 10, 18], 5);
     TestRunner.completeTest();
   });
-}
-
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests DataGrid column auto size calculation.</p>
-<a href="https://bugs.webkit.org/show_bug.cgi?id=101363">Bug 101363</a>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid.js
similarity index 90%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid.js
index f35df3f..6a36b74 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/datagrid.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../resources/datagrid-test.js"></script>
-<script>
-function test() {
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Tests ViewportDataGrid.\n`);
+  await TestRunner.loadModule('data_grid_test_runner');
+
   function attach(parent, child, index) {
     var parentName = parent === root ? 'root' : parent.data.id;
     if (typeof index === 'number')
@@ -125,10 +127,4 @@
   dumpNodes();
 
   TestRunner.completeTest();
-}
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests ViewportDataGrid.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/dom-extension.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/dom-extension.js
similarity index 87%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/dom-extension.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/dom-extension.js
index 9919bef..14909d3a 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/dom-extension.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/dom-extension.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script>
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-function test() {
+(async function() {
+  TestRunner.addResult(`This test checks dom extensions.\n`);
+
+
   TestRunner.runTestSuite([
     function traverseNextNodeInShadowDom(next) {
       function createContent(parent, selection) {
@@ -44,15 +46,4 @@
       next();
     },
   ]);
-}
-
-</script>
-</head>
-
-<body onload="runTest()">
-<p>
-This test checks dom extensions.
-</p>
-
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/file-path-scoring.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/file-path-scoring.js
similarity index 86%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/file-path-scoring.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/file-path-scoring.js
index d7b28e84..5544e8ab 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/file-path-scoring.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/file-path-scoring.js
@@ -1,10 +1,12 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/sources-test.js"></script>
-<script src="../resources/example-fileset-for-test.js"></script>
-<script>
-function test() {
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Test file path scoring function\n`);
+  await TestRunner.loadModule('sources_test_runner');
+  await TestRunner.addScriptTag('../resources/example-fileset-for-test.js');
+
   const TestQueries = [
     ['textepl', './Source/devtools/front_end/TextEditor.pl'],
     ['defted', './Source/devtools/front_end/DefaultTextEditor.pl'],
@@ -78,10 +80,4 @@
       result += '<';
     return result + ' (score: ' + score + ')';
   }
-};
-</script>
-</head>
-<body onload="runTest()">
-<p>Test file path scoring function</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/flame-chart.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/flame-chart.js
similarity index 83%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/flame-chart.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/flame-chart.js
index 07c3f1b..4a0afc0c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/flame-chart.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/flame-chart.js
@@ -1,12 +1,13 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script>
-function initialize_flameChartTest()
-{
-InspectorTest.preloadModule("perf_ui");
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-InspectorTest.FlameChartProvider = class {
+(async function() {
+  TestRunner.addResult(`Smoke test for basic FlameChart functionality.\n`);
+
+  await TestRunner.loadModule("perf_ui");
+
+   class FlameChartProvider {
     constructor(entries, groups, defaults) {
         this._entries = entries;
         this._defaults = defaults || {};
@@ -66,12 +67,8 @@
 
     highlightEntry(entryIndex) {
     }
-}
+  }
 
-}
-
-
-function test() {
   var entries = [
     {start: 1000, end: 5000, level: 0, title: 'AAAAAAAAAAAAAAAAAAAAAA'},
     {start: 2000, end: 3000, level: 1, title: 'bbbb'},
@@ -81,7 +78,7 @@
   ];
 
   try {
-    var provider = new InspectorTest.FlameChartProvider(entries, null);
+    var provider = new FlameChartProvider(entries, null);
     var flameChart = new PerfUI.FlameChart(provider, new PerfUI.FlameChartDelegate());
     flameChart.update();
     TestRunner.addResult('PASSED');
@@ -89,11 +86,4 @@
     TestRunner.addResult('Failed: ' + e.stack);
   }
   TestRunner.completeTest();
-}
-
-</script>
-</head>
-<body onload="runTest()">
-<p>Smoke test for basic FlameChart functionality.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/geometry.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/geometry.js
similarity index 94%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/geometry.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/geometry.js
index 314988f..811bc32 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/geometry.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/geometry.js
@@ -1,8 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script>
-function test() {
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Tests Geometry utility class\n`);
+
+
   TestRunner.runTestSuite([
 
     function testVectorLength(next) {
@@ -128,10 +131,4 @@
     }
 
   ]);
-}
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests Geometry utility class</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/json-balanced-tokenizer-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/components/json-balanced-tokenizer-expected.txt
index 5b411e9..c2825b9d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/json-balanced-tokenizer-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/json-balanced-tokenizer-expected.txt
@@ -1,5 +1,6 @@
 Test TextUtils.TextUtils.BalancedJSONTokenizer.
 
+
 Running: testMatchQuotes
 
 Parsing {"odd back slashes with text around":"tes\\\"t"}
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/json-balanced-tokenizer.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/json-balanced-tokenizer.js
similarity index 86%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/json-balanced-tokenizer.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/json-balanced-tokenizer.js
index 51d1365..6d321232 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/json-balanced-tokenizer.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/json-balanced-tokenizer.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-<script>
-function test() {
+(async function() {
+  TestRunner.addResult(`Test TextUtils.TextUtils.BalancedJSONTokenizer.\n`);
+
+
   TestRunner.runTestSuite([
     function testMatchQuotes(next) {
       var testStrings = [
@@ -16,7 +18,7 @@
       for (var i = 0; i < testStrings.length; ++i) {
         var string = JSON.stringify(testStrings[i]);
         TestRunner.addResult('\nParsing ' + string);
-        var tokenizer = new TextUtils.TextUtils.BalancedJSONTokenizer(TestRunner.addResult.bind(InspectorTest));
+        var tokenizer = new TextUtils.TextUtils.BalancedJSONTokenizer(TestRunner.addResult.bind(TestRunner));
         var result = tokenizer.write(string);
         if (!result)
           TestRunner.addResult(`tokenizer.write() returned ${result}, true expected`);
@@ -34,7 +36,7 @@
       for (var i = 0; i < testData.length; ++i) {
         var string = JSON.stringify(testData[i]);
         TestRunner.addResult('\nParsing ' + string);
-        var tokenizer = new TextUtils.TextUtils.BalancedJSONTokenizer(TestRunner.addResult.bind(InspectorTest));
+        var tokenizer = new TextUtils.TextUtils.BalancedJSONTokenizer(TestRunner.addResult.bind(TestRunner));
         var result = tokenizer.write(string);
         if (!result)
           TestRunner.addResult(`tokenizer.write() returned ${result}, false expected`);
@@ -52,7 +54,7 @@
       for (var i = 0; i < testData.length; ++i) {
         var string = JSON.stringify(testData[i]);
         TestRunner.addResult('\nParsing ' + string);
-        var tokenizer = new TextUtils.TextUtils.BalancedJSONTokenizer(TestRunner.addResult.bind(InspectorTest), true);
+        var tokenizer = new TextUtils.TextUtils.BalancedJSONTokenizer(TestRunner.addResult.bind(TestRunner), true);
         var result = tokenizer.write(string);
         var expectedResult = !(testData[i] instanceof Array);
         if (result != expectedResult)
@@ -69,14 +71,14 @@
         {'etc': {'\\\\"': '\\\\"'}}
       ];
       var string = JSON.stringify(testStrings);
-      var tokenizer = new TextUtils.TextUtils.BalancedJSONTokenizer(TestRunner.addResult.bind(InspectorTest), true);
+      var tokenizer = new TextUtils.TextUtils.BalancedJSONTokenizer(TestRunner.addResult.bind(TestRunner), true);
       TestRunner.addResult('\nRunning at once:');
       var result = tokenizer.write(string);
       if (result)
         TestRunner.addResult(`tokenizer.write() returned ${result}, false expected`);
 
       for (var sample of [3, 15, 50]) {
-        tokenizer = new TextUtils.TextUtils.BalancedJSONTokenizer(TestRunner.addResult.bind(InspectorTest), true);
+        tokenizer = new TextUtils.TextUtils.BalancedJSONTokenizer(TestRunner.addResult.bind(TestRunner), true);
         TestRunner.addResult('\nRunning by ' + sample + ':');
         for (var i = 0; i < string.length; i += sample) {
           var result = tokenizer.write(string.substring(i, i + sample));
@@ -91,17 +93,10 @@
     function testGarbageAfterObject(next) {
       var testString = '[{a: \'b\'}], {\'x\': {a: \'b\'}}';
       TestRunner.addResult('\nParsing ' + testString);
-      var tokenizer = new TextUtils.TextUtils.BalancedJSONTokenizer(TestRunner.addResult.bind(InspectorTest), true);
+      var tokenizer = new TextUtils.TextUtils.BalancedJSONTokenizer(TestRunner.addResult.bind(TestRunner), true);
       var result = tokenizer.write(testString);
       TestRunner.addResult(`tokenizer.write() returned ${result}, false expected`);
       next();
     }
   ]);
-}
-</script>
-
-<body onload="runTest()">
-Test TextUtils.TextUtils.BalancedJSONTokenizer.
-</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/minimum-size.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/minimum-size.js
similarity index 94%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/minimum-size.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/minimum-size.js
index 4a6aca2..d73fd0e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/minimum-size.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/minimum-size.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script>
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-function test() {
+(async function() {
+  TestRunner.addResult(`Tests how widget minimum size works.\n`);
+
+
   function showRootSplitWidget(splitWidget) {
     splitWidget.element.style.position = 'absolute';
     splitWidget.element.style.top = '0';
@@ -127,10 +129,4 @@
   dumpBoundingBoxes(widgets);
 
   TestRunner.completeTest();
-}
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests how widget minimum size works.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/parsed-url.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/parsed-url.js
similarity index 91%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/parsed-url.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/parsed-url.js
index 8aa69e3..44f32663 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/parsed-url.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/parsed-url.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script type="text/javascript">
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-function test() {
+(async function() {
+  TestRunner.addResult(`Tests inspector ParsedURL class\n`);
+
+
   function parseAndDumpURL(url) {
     var parsedURL = new Common.ParsedURL(url);
 
@@ -58,11 +60,4 @@
   testSplitLineColumn('http://www.chromium.org/foo.js:10:20');
 
   TestRunner.completeTest();
-}
-
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests inspector ParsedURL class</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/progress-bar.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/progress-bar.js
similarity index 63%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/progress-bar.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/progress-bar.js
index 9225f7ed..4f592fe 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/progress-bar.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/progress-bar.js
@@ -1,72 +1,60 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script type="text/javascript">
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-function initialize_ProgressBarTest()
-{
+(async function() {
+  TestRunner.addResult(`Tests inspector's composite progress bar.\n`);
 
-InspectorTest.MockProgressIndicator = function()
-{
-}
 
-InspectorTest.MockProgressIndicator.prototype = {
+  var MockProgressIndicator = function() {};
+
+  MockProgressIndicator.prototype = {
     // Implementation of Common.Progress interface.
-    isCanceled: function()
-    {
-        return this._isCanceled;
+    isCanceled: function() {
+      return this._isCanceled;
     },
 
-    done: function()
-    {
-        TestRunner.addResult("progress indicator: done");
+    done: function() {
+      TestRunner.addResult('progress indicator: done');
     },
 
-    setTotalWork: function(totalWork)
-    {
-        this._totalWork = totalWork;
+    setTotalWork: function(totalWork) {
+      this._totalWork = totalWork;
     },
 
-    setWorked: function(worked, title)
-    {
-        this._worked = worked;
-        if (typeof title !== "undefined")
-            this._title = title;
-    },
-
-    setTitle: function(title)
-    {
+    setWorked: function(worked, title) {
+      this._worked = worked;
+      if (typeof title !== 'undefined')
         this._title = title;
     },
 
-    // Test methods.
-    cancel: function()
-    {
-        this._isCanceled = true;
+    setTitle: function(title) {
+      this._title = title;
     },
 
-    dump: function()
-    {
-        const roundFactor = 10000;
+    // Test methods.
+    cancel: function() {
+      this._isCanceled = true;
+    },
 
-        var worked = this._worked;
-        var totalWork = this._totalWork;
+    dump: function() {
+      const roundFactor = 10000;
 
-        if (typeof worked === "number")
-            worked = Math.round(worked * roundFactor) / roundFactor;
-        if (typeof totalWork === "number")
-            totalWork = Math.round(totalWork * roundFactor) / roundFactor;
+      var worked = this._worked;
+      var totalWork = this._totalWork;
 
-        TestRunner.addResult("progress: `" + this._title + "' " + worked + " out of " + totalWork + " done.");
-    }    
-}
+      if (typeof worked === 'number')
+        worked = Math.round(worked * roundFactor) / roundFactor;
+      if (typeof totalWork === 'number')
+        totalWork = Math.round(totalWork * roundFactor) / roundFactor;
 
-}
+      TestRunner.addResult('progress: `' + this._title + '\' ' + worked + ' out of ' + totalWork + ' done.');
+    }
+  };
 
-var test = function() {
   TestRunner.runTestSuite([
     function testOneSubProgress(next) {
-      var indicator = new InspectorTest.MockProgressIndicator();
+      var indicator = new MockProgressIndicator();
       var composite = new Common.CompositeProgress(indicator);
       var subProgress = composite.createSubProgress();
 
@@ -85,7 +73,7 @@
     },
 
     function testMultipleSubProgresses(next) {
-      var indicator = new InspectorTest.MockProgressIndicator();
+      var indicator = new MockProgressIndicator();
       var composite = new Common.CompositeProgress(indicator);
       var subProgress1 = composite.createSubProgress();
       var subProgress2 = composite.createSubProgress(3);
@@ -118,7 +106,7 @@
     },
 
     function testCancel(next) {
-      var indicator = new InspectorTest.MockProgressIndicator();
+      var indicator = new MockProgressIndicator();
       var composite = new Common.CompositeProgress(indicator);
       var subProgress = composite.createSubProgress();
 
@@ -130,7 +118,7 @@
     },
 
     function testNested(next) {
-      var indicator = new InspectorTest.MockProgressIndicator();
+      var indicator = new MockProgressIndicator();
       var composite0 = new Common.CompositeProgress(indicator);
       var subProgress01 = composite0.createSubProgress();
       var composite1 = new Common.CompositeProgress(subProgress01);
@@ -157,11 +145,4 @@
       next();
     }
   ]);
-};
-
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests inspector's composite progress bar.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/segmented-range.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/segmented-range.js
similarity index 90%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/segmented-range.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/segmented-range.js
index 361797e..9fa5ea9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/segmented-range.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/segmented-range.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../resources/datagrid-test.js"></script>
-<script>
-function test() {
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Tests SegmentedRange\n`);
+  await TestRunner.loadModule('data_grid_test_runner');
+
   function testCase(testName, data, merge, expectSameBackwards) {
     TestRunner.addResult('Test case: ' + testName);
     TestRunner.addResult('Input Segments: ' + JSON.stringify(data));
@@ -59,10 +61,4 @@
   testCase('one consuming many:', [[0, 1, 'a'], [2, 3, 'a'], [4, 5, 'a'], [6, 7, 'a'], [2, 6, 'a']], merge, true);
   testCase('one consuming many, no merge:', [[0, 1, 'a'], [2, 3, 'a'], [4, 5, 'a'], [6, 7, 'a'], [2, 6, 'a']]);
   TestRunner.completeTest();
-}
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests SegmentedRange</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/split-string-by-regexes.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/split-string-by-regexes.js
similarity index 86%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/split-string-by-regexes.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/split-string-by-regexes.js
index 8141209c..22997085 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/split-string-by-regexes.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/split-string-by-regexes.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script>
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-function test() {
+(async function() {
+  TestRunner.addResult(`Tests TextUtils.TextUtils.splitStringByRegexes.\n`);
+
+
   TestRunner.runTestSuite([
     function testSimple(next) {
       var regexes = [/hello/g, /[0-9]+/g];
@@ -62,13 +64,4 @@
       TestRunner.addResult('"' + result.value + '", ' + result.position + ', ' + result.regexIndex);
     }
   }
-}
-</script>
-</head>
-
-<body onload="runTest()">
-<p>
-Tests TextUtils.TextUtils.splitStringByRegexes.
-</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/split-widget.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/split-widget.js
similarity index 94%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/split-widget.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/split-widget.js
index fd14b500..6ffa49cd 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/split-widget.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/split-widget.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script>
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-function test() {
+(async function() {
+  TestRunner.addResult(`Tests how split widget saving to settings works.\n`);
+
+
   var settingIndex = 0;
   function createAndShowSplitWidget(
       isVertical, secondIsSidebar, settingName, defaultSidebarWidth, defaultSidebarHeight, shouldSaveShowMode) {
@@ -123,10 +125,4 @@
   testSplitWidgetSizes(true, false);
   testSplitWidgetSizes(true, true);
   TestRunner.completeTest();
-}
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests how split widget saving to settings works.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/throttler.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/throttler.js
similarity index 95%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/throttler.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/throttler.js
index 7d2f26f..bd3974f6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/throttler.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/throttler.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script>
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-function test() {
+(async function() {
+  TestRunner.addResult(`This test verifies throttler behavior.\n`);
+  TestRunner.printDevToolsConsole();
+
   class TimeoutMock {
     constructor() {
       this._timeoutId = 0;
@@ -45,7 +47,7 @@
       this._timeoutIdToProcess = {};
       this._timeoutIdToMillis = {};
     }
-  };
+  }
 
   var ProcessMock = function(name, runnable) {
     this._runnable = runnable;
@@ -276,12 +278,4 @@
   function logSchedule(operation, asSoonAsPossible) {
     TestRunner.addResult('SCHEDULED: \'' + operation.processName + '\' asSoonAsPossible: ' + asSoonAsPossible);
   }
-}
-
-</script>
-</head>
-
-<body onload="runTest()">
-<p>This test verifies throttler behavior.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities-highlight-results-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities-highlight-results-expected.txt
index ef78e7f9..68aa31b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities-highlight-results-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities-highlight-results-expected.txt
@@ -1,6 +1,5 @@
 Tests how utilities functions highlight text and then revert/re-apply highlighting changes.
 
-Bug 70244
 --------- Running test: ----------
 After highlight: [function]
 After revert: function
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities-highlight-results.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities-highlight-results.js
similarity index 88%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities-highlight-results.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities-highlight-results.js
index 1a88cd7..b41d565a7 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities-highlight-results.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities-highlight-results.js
@@ -1,9 +1,13 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="utilities-test.js"></script>
-<script>
-function test() {
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Tests how utilities functions highlight text and then revert/re-apply highlighting changes.\n`);
+  await TestRunner.loadHTML(`
+      <a href="https://bugs.webkit.org/show_bug.cgi?id=70244">Bug 70244</a>
+    `);
+
   function dumpTextNodesAsString(node) {
     var result = '';
     function dumpTextNode(node) {
@@ -85,11 +89,4 @@
       textElement(['function', ' ', 'functionName']),
       [range(0, 1), range(7, 3), range(20, 1)]);  // Highlight like that: "[f]unctio[n f]unctionNam[e]"
   TestRunner.completeTest();
-}
-</script>
-</head>
-<body onload="runTest()">
-    <p>Tests how utilities functions highlight text and then revert/re-apply highlighting changes.</p>
-    <a href="https://bugs.webkit.org/show_bug.cgi?id=70244">Bug 70244</a>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities.js
similarity index 97%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities.js
index 6d80b54..7914695 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/utilities.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script>
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-function test() {
+(async function() {
+  TestRunner.addResult(`This test checks Web Inspector utilities.\n`);
+
+
   TestRunner.runTestSuite([
     function remove(next) {
       var testArrays = [
@@ -371,15 +373,4 @@
       next();
     }
   ]);
-}
-
-</script>
-</head>
-
-<body onload="runTest()">
-<p>
-This test checks Web Inspector utilities.
-</p>
-
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/viewport-datagrid.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/viewport-datagrid.js
similarity index 93%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/viewport-datagrid.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/viewport-datagrid.js
index b241ad9..a296f907 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/viewport-datagrid.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/viewport-datagrid.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../resources/datagrid-test.js"></script>
-<script>
-function test() {
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Tests ViewportDataGrid.\n`);
+  await TestRunner.loadModule('data_grid_test_runner');
+
   function attach(parent, child, index) {
     var parentName = parent === root ? 'root' : parent.data.id;
     if (typeof index === 'number')
@@ -180,10 +182,4 @@
   TestRunner.addResult(`Class list: ${dataGrid.element.classList}`);
 
   TestRunner.completeTest();
-}
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests ViewportDataGrid.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/widget-events.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/widget-events.js
similarity index 96%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/widget-events.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/widget-events.js
index e4f6eb5b..71deab6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/widget-events.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/widget-events.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script>
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-function test() {
+(async function() {
+  TestRunner.addResult(`This tests that events are properly propagated through Widget hierarchy.\n`);
+
+
   var TestWidget = class extends UI.Widget {
     constructor(widgetName) {
       super();
@@ -335,15 +337,4 @@
       next();
     }
   ]);
-}
-
-</script>
-</head>
-
-<body onload="runTest()">
-<p>
-This tests that events are properly propagated through Widget hierarchy.
-</p>
-
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/components/widget-focus.html b/third_party/WebKit/LayoutTests/http/tests/devtools/components/widget-focus.js
similarity index 89%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/components/widget-focus.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/components/widget-focus.js
index 23cd92c..966e90b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/components/widget-focus.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/components/widget-focus.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script>
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-function test() {
+(async function() {
+  TestRunner.addResult(`Tests whether focus is properly remembered on widgets.\n`);
+
+
   var outerInput = document.createElement('input');
   outerInput.id = 'Outer';
 
@@ -93,10 +95,4 @@
     var id = focused ? focused.id : '';
     TestRunner.addResult(id ? id + ' Focused' : 'No focus');
   }
-}
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests whether focus is properly remembered on widgets.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-data-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-data-expected.txt
index afed790..9504723 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-data-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-data-expected.txt
@@ -1,15 +1,3 @@
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback1
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback2
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback3
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback4
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback5
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback6
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback7
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback8
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback9
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback10
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback11
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback12
 Tests that data is correctly loaded by IndexedDBModel from IndexedDB object store and index.
 
 Dumping values, fromIndex = false, skipCount = 0, pageSize = 2, idbKeyRange = null
@@ -64,4 +52,16 @@
 Cleared data from objectStore
 Dumping values, fromIndex = false, skipCount = 0, pageSize = 10, idbKeyRange = null
     hasMore = false
+VM:3 InspectorTest.IndexedDB_callback1
+VM:3 InspectorTest.IndexedDB_callback2
+VM:3 InspectorTest.IndexedDB_callback3
+VM:3 InspectorTest.IndexedDB_callback4
+VM:3 InspectorTest.IndexedDB_callback5
+VM:3 InspectorTest.IndexedDB_callback6
+VM:3 InspectorTest.IndexedDB_callback7
+VM:3 InspectorTest.IndexedDB_callback8
+VM:3 InspectorTest.IndexedDB_callback9
+VM:3 InspectorTest.IndexedDB_callback10
+VM:3 InspectorTest.IndexedDB_callback11
+VM:3 InspectorTest.IndexedDB_callback12
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-data.html b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-data.js
similarity index 92%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-data.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-data.js
index bee2d51..e9ad0540 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-data.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-data.js
@@ -1,9 +1,12 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/indexeddb/indexeddb-test.js"></script>
-<script>
-function test() {
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(
+      `Tests that data is correctly loaded by IndexedDBModel from IndexedDB object store and index.\n`);
+  await TestRunner.loadModule('application_test_runner');
+
   var indexedDBModel = ApplicationTestRunner.createIndexedDBModel();
   var mainFrameId = TestRunner.resourceTreeModel.mainFrame.id;
   var securityOrigin = 'http://127.0.0.1:8000';
@@ -191,13 +194,8 @@
     }
 
     function step4() {
+      ConsoleTestRunner.dumpConsoleMessages();
       TestRunner.completeTest();
     }
   }
-}
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests that data is correctly loaded by IndexedDBModel from IndexedDB object store and index.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-names.html b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-names.js
similarity index 84%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-names.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-names.js
index e43034dd..1d8e3a1c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-names.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-names.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/indexeddb/indexeddb-test.js"></script>
-<script>
-function test() {
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Tests that database names are correctly loaded and saved in IndexedDBModel.\n`);
+  await TestRunner.loadModule('application_test_runner');
+
   var indexedDBModel = ApplicationTestRunner.createIndexedDBModel();
   var mainFrameId = TestRunner.resourceTreeModel.mainFrame.id;
 
@@ -63,10 +65,4 @@
     dumpDatabaseNames();
     TestRunner.completeTest();
   }
-}
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests that database names are correctly loaded and saved in IndexedDBModel.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-refresh-view.html b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-refresh-view.js
similarity index 91%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-refresh-view.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-refresh-view.js
index eb7a147..ea7f182 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-refresh-view.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-refresh-view.js
@@ -1,12 +1,13 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/resources-test.js"></script>
-<script src="../../inspector/console-test.js"></script>
-<script src="../../inspector/indexeddb/indexeddb-test.js"></script>
-<script>
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-async function test() {
+(async function() {
+  TestRunner.addResult(`Tests refreshing the database information and data views.\n`);
+  await TestRunner.loadModule('application_test_runner');
+  await TestRunner.loadModule('console_test_runner');
+  await TestRunner.showPanel('resources');
+
   var databaseName = 'testDatabase';
   var objectStoreName1 = 'testObjectStore1';
   var objectStoreName2 = 'testObjectStore2';
@@ -126,10 +127,4 @@
   dumpObjectStores();
 
   TestRunner.completeTest();
-}
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests refreshing the database information and data views.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-structure-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-structure-expected.txt
index 8f33c93c..524e5e7 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-structure-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-structure-expected.txt
@@ -1,13 +1,3 @@
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback1
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback2
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback3
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback4
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback5
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback6
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback7
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback8
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback9
-CONSOLE MESSAGE: line 3: InspectorTest.IndexedDB_callback10
 Tests that database names are correctly loaded and saved in IndexedDBModel.
 
 Dumping database:
@@ -120,4 +110,14 @@
     version: 9
     objectStores:
 
+VM:3 InspectorTest.IndexedDB_callback1
+VM:3 InspectorTest.IndexedDB_callback2
+VM:3 InspectorTest.IndexedDB_callback3
+VM:3 InspectorTest.IndexedDB_callback4
+VM:3 InspectorTest.IndexedDB_callback5
+VM:3 InspectorTest.IndexedDB_callback6
+VM:3 InspectorTest.IndexedDB_callback7
+VM:3 InspectorTest.IndexedDB_callback8
+VM:3 InspectorTest.IndexedDB_callback9
+VM:3 InspectorTest.IndexedDB_callback10
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-structure.html b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-structure.js
similarity index 93%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-structure.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-structure.js
index 1433020b..ee8693f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-structure.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/database-structure.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/indexeddb/indexeddb-test.js"></script>
-<script>
-function test() {
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Tests that database names are correctly loaded and saved in IndexedDBModel.\n`);
+  await TestRunner.loadModule('application_test_runner');
+
   var indexedDBModel = ApplicationTestRunner.createIndexedDBModel();
   var mainFrameId = TestRunner.resourceTreeModel.mainFrame.id;
   var databaseName = 'testDatabase1';
@@ -170,12 +172,7 @@
   }
 
   function step22() {
+    ConsoleTestRunner.dumpConsoleMessages();
     TestRunner.completeTest();
   }
-}
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests that database names are correctly loaded and saved in IndexedDBModel.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/resources-panel.html b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/resources-panel.js
similarity index 89%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/resources-panel.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/resources-panel.js
index ec7350e..1460dda 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/resources-panel.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/resources-panel.js
@@ -1,15 +1,16 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/indexeddb/indexeddb-test.js"></script>
-<script src="../../inspector/resources-test.js"></script>
-<script src="../../inspector/console-test.js"></script>
-<script>
-function test() {
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Tests IndexedDB tree element on resources panel.\n`);
+  await TestRunner.loadModule('application_test_runner');
+  await TestRunner.loadModule('console_test_runner');
+
   var mainFrameId = TestRunner.resourceTreeModel.mainFrame.id;
   var indexedDBModel;
   var withoutIndexedDBURL = 'http://localhost:8000/inspector/indexeddb/resources/without-indexed-db.html';
-  var originalURL = 'http://127.0.0.1:8000/devtools/indexeddb/resources-panel.html';
+  var originalURL = 'http://127.0.0.1:8000/devtools/indexeddb/resources-panel.js';
   var databaseName = 'testDatabase';
   var objectStoreName = 'testObjectStore';
   var indexName = 'testIndexName';
@@ -102,11 +103,4 @@
     UI.panels.resources._sidebar.indexedDBListTreeElement.collapse();
     TestRunner.completeTest();
   }
-}
-
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests IndexedDB tree element on resources panel.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/transaction-promise-console.html b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/transaction-promise-console.js
similarity index 68%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/transaction-promise-console.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/transaction-promise-console.js
index 2362488..286953ab 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/transaction-promise-console.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/transaction-promise-console.js
@@ -1,9 +1,12 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/console-test.js"></script>
-<script>
-function test() {
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(
+      `Ensure transactions created within Promise callbacks are not deactivated due to console activity\n`);
+  await TestRunner.loadModule('console_test_runner');
+
   testRunner.waitUntilDone();
   testRunner.showWebInspector();
 
@@ -30,11 +33,4 @@
       });
     };
   };
-}
-
-</script>
-</head>
-<body onload="runTest()">
-<p>Ensure transactions created within Promise callbacks are not deactivated due to console activity</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/upgrade-events.html b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/upgrade-events.js
similarity index 91%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/upgrade-events.html
rename to third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/upgrade-events.js
index dab0cafd5..1aabd15 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/upgrade-events.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/indexeddb/upgrade-events.js
@@ -1,9 +1,11 @@
-<html>
-<head>
-<script src="../../inspector/inspector-test.js"></script>
-<script src="../../inspector/indexeddb/indexeddb-test.js"></script>
-<script>
-function test() {
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Tests that deleted databases do not get recreated.\n`);
+  await TestRunner.loadModule('application_test_runner');
+
   var indexedDBModel = ApplicationTestRunner.createIndexedDBModel();
   var mainFrameId = TestRunner.resourceTreeModel.mainFrame.id;
   var securityOrigin = 'http://127.0.0.1:8000';
@@ -120,10 +122,4 @@
       callback();
     }
   }
-}
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests that deleted databases do not get recreated.</p>
-</body>
-</html>
+})();
diff --git a/third_party/WebKit/LayoutTests/svg/dom/resources/tooltip-title-external-svg.svg b/third_party/WebKit/LayoutTests/svg/dom/resources/tooltip-title-external-svg.svg
new file mode 100644
index 0000000..7d072405
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/dom/resources/tooltip-title-external-svg.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500">
+<title>Top Level Title in Object</title>
+    <rect width="250" height="250" fill="green">
+        <title>Second Level Title in Object</title>
+    </rect>
+</svg>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/svg/dom/tooltip-title-external-svg.html b/third_party/WebKit/LayoutTests/svg/dom/tooltip-title-external-svg.html
new file mode 100644
index 0000000..eae76029
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/dom/tooltip-title-external-svg.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<object type="image/svg+xml" data="resources/tooltip-title-external-svg.svg">
+    Browser does not support SVG
+</object>
+<script>
+
+testTooltipText(100, 300, "", "Tooltip title of title child under SVG root added as an object");
+testTooltipText(100, 100, "Second Level Title in Object", "Tooltip title of title child under an element as part of external SVG object");
+
+function testTooltipText(x, y, expectedText, description) {
+    async_test(function(t) {
+        window.addEventListener('load', t.step_func_done(function() {
+            assert_exists(window, 'eventSender');
+            assert_exists(window, 'testRunner');
+            eventSender.dragMode = false;
+            eventSender.mouseMoveTo(x,y);
+            assert_equals(testRunner.tooltipText, expectedText);
+        }));
+    }, description);
+}
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/svg/dom/tooltip-title-inline-svg.html b/third_party/WebKit/LayoutTests/svg/dom/tooltip-title-inline-svg.html
new file mode 100644
index 0000000..59305806
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/dom/tooltip-title-inline-svg.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<svg width="500" height="500">
+    <title>Top Level Title</title>
+    <rect width="250" height="250" fill="green">
+        <title>Second Level Title</title>
+    </rect>
+</svg>
+<script>
+testTooltipText(100, 300, "Top Level Title", "Tooltip title of title child under SVG root");
+testTooltipText(100, 100, "Second Level Title", "Tooltip title of title child under an element");
+
+function testTooltipText(x, y, expectedText, description) {
+    async_test(function(t) {
+        window.addEventListener('load', t.step_func_done(function() {
+            assert_exists(window, 'eventSender');
+            assert_exists(window, 'testRunner');
+            eventSender.dragMode = false;
+            eventSender.mouseMoveTo(x,y);
+            assert_equals(testRunner.tooltipText, expectedText);
+        }));
+    }, description);
+}
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/Source/core/exported/WebInputMethodControllerImpl.cpp b/third_party/WebKit/Source/core/exported/WebInputMethodControllerImpl.cpp
index 2a24e7d..1b0bf41 100644
--- a/third_party/WebKit/Source/core/exported/WebInputMethodControllerImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebInputMethodControllerImpl.cpp
@@ -147,6 +147,21 @@
   return GetFrame()->GetInputMethodController().TextInputType();
 }
 
+WebRange WebInputMethodControllerImpl::CompositionRange() {
+  EphemeralRange range =
+      GetFrame()->GetInputMethodController().CompositionEphemeralRange();
+
+  if (range.IsNull())
+    return WebRange();
+
+  Element* editable =
+      GetFrame()->Selection().RootEditableElementOrDocumentElement();
+
+  editable->GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
+
+  return PlainTextRange::Create(*editable, range);
+}
+
 WebRange WebInputMethodControllerImpl::GetSelectionOffsets() const {
   // TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets
   // needs to be audited.  See http://crbug.com/590369 for more details.
diff --git a/third_party/WebKit/Source/core/exported/WebInputMethodControllerImpl.h b/third_party/WebKit/Source/core/exported/WebInputMethodControllerImpl.h
index f615e3c..5a208e5 100644
--- a/third_party/WebKit/Source/core/exported/WebInputMethodControllerImpl.h
+++ b/third_party/WebKit/Source/core/exported/WebInputMethodControllerImpl.h
@@ -44,6 +44,8 @@
   WebTextInputInfo TextInputInfo() override;
   int ComputeWebTextInputNextPreviousFlags() override;
   WebTextInputType TextInputType() override;
+  WebRange CompositionRange() override;
+
   WebRange GetSelectionOffsets() const;
 
   void Trace(blink::Visitor*);
diff --git a/third_party/WebKit/Source/core/exported/WebViewImpl.cpp b/third_party/WebKit/Source/core/exported/WebViewImpl.cpp
index c346ddd..a9e5bb10 100644
--- a/third_party/WebKit/Source/core/exported/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebViewImpl.cpp
@@ -2175,29 +2175,6 @@
 
 // TODO(ekaramad):This method is almost duplicated in WebFrameWidgetImpl as
 // well. This code needs to be refactored  (http://crbug.com/629721).
-WebRange WebViewImpl::CompositionRange() {
-  LocalFrame* focused = FocusedLocalFrameAvailableForIme();
-  if (!focused)
-    return WebRange();
-
-  const EphemeralRange range =
-      focused->GetInputMethodController().CompositionEphemeralRange();
-  if (range.IsNull())
-    return WebRange();
-
-  Element* editable =
-      focused->Selection().RootEditableElementOrDocumentElement();
-  DCHECK(editable);
-
-  // TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets
-  // needs to be audited.  See http://crbug.com/590369 for more details.
-  editable->GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
-
-  return PlainTextRange::Create(*editable, range);
-}
-
-// TODO(ekaramad):This method is almost duplicated in WebFrameWidgetImpl as
-// well. This code needs to be refactored  (http://crbug.com/629721).
 bool WebViewImpl::SelectionBounds(WebRect& anchor, WebRect& focus) const {
   const Frame* frame = FocusedCoreFrame();
   if (!frame || !frame->IsLocalFrame())
@@ -2384,7 +2361,11 @@
 // TODO(ekaramad):This method is almost duplicated in WebFrameWidgetImpl as
 // well. This code needs to be refactored  (http://crbug.com/629721).
 bool WebViewImpl::GetCompositionCharacterBounds(WebVector<WebRect>& bounds) {
-  WebRange range = CompositionRange();
+  WebInputMethodController* controller = GetActiveWebInputMethodController();
+  if (!controller)
+    return false;
+
+  WebRange range = controller->CompositionRange();
   if (range.IsEmpty())
     return false;
 
diff --git a/third_party/WebKit/Source/core/exported/WebViewImpl.h b/third_party/WebKit/Source/core/exported/WebViewImpl.h
index bed7a2b8..602c03d 100644
--- a/third_party/WebKit/Source/core/exported/WebViewImpl.h
+++ b/third_party/WebKit/Source/core/exported/WebViewImpl.h
@@ -143,7 +143,6 @@
                                          bool has_scrolled_by_touch) override;
   void MouseCaptureLost() override;
   void SetFocus(bool enable) override;
-  WebRange CompositionRange() override;
   WebColor BackgroundColor() const override;
   WebPagePopupImpl* GetPagePopup() const override;
   bool SelectionBounds(WebRect& anchor, WebRect& focus) const override;
diff --git a/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.cpp b/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.cpp
index f33d976..966bee5a 100644
--- a/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.cpp
+++ b/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.cpp
@@ -565,29 +565,6 @@
   }
 }
 
-// TODO(ekaramad):This method is almost duplicated in WebViewImpl as well. This
-// code needs to be refactored  (http://crbug.com/629721).
-WebRange WebFrameWidgetImpl::CompositionRange() {
-  LocalFrame* focused = FocusedLocalFrameAvailableForIme();
-  if (!focused)
-    return WebRange();
-
-  const EphemeralRange range =
-      focused->GetInputMethodController().CompositionEphemeralRange();
-  if (range.IsNull())
-    return WebRange();
-
-  Element* editable =
-      focused->Selection().RootEditableElementOrDocumentElement();
-  DCHECK(editable);
-
-  // TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets
-  // needs to be audited.  See http://crbug.com/590369 for more details.
-  editable->GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
-
-  return PlainTextRange::Create(*editable, range);
-}
-
 WebColor WebFrameWidgetImpl::BackgroundColor() const {
   if (background_color_override_enabled_)
     return background_color_override_;
@@ -737,13 +714,15 @@
 // code needs to be refactored  (http://crbug.com/629721).
 bool WebFrameWidgetImpl::GetCompositionCharacterBounds(
     WebVector<WebRect>& bounds) {
-  WebRange range = CompositionRange();
+  WebInputMethodController* controller = GetActiveWebInputMethodController();
+  if (!controller)
+    return false;
+
+  WebRange range = controller->CompositionRange();
   if (range.IsEmpty())
     return false;
 
   LocalFrame* frame = FocusedLocalFrameInWidget();
-  if (!frame)
-    return false;
 
   WebLocalFrameImpl* web_local_frame = WebLocalFrameImpl::FromFrame(frame);
   size_t character_count = range.length();
diff --git a/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.h b/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.h
index 3c32ba64..81bd4dea 100644
--- a/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.h
+++ b/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.h
@@ -95,7 +95,6 @@
                            float browser_controls_delta) override;
   void MouseCaptureLost() override;
   void SetFocus(bool enable) override;
-  WebRange CompositionRange() override;
   WebColor BackgroundColor() const override;
   bool SelectionBounds(WebRect& anchor, WebRect& focus) const override;
   bool SelectionTextDirection(WebTextDirection& start,
diff --git a/third_party/WebKit/Source/core/frame/WebViewFrameWidget.cpp b/third_party/WebKit/Source/core/frame/WebViewFrameWidget.cpp
index eb91d98..4d61003 100644
--- a/third_party/WebKit/Source/core/frame/WebViewFrameWidget.cpp
+++ b/third_party/WebKit/Source/core/frame/WebViewFrameWidget.cpp
@@ -130,10 +130,6 @@
   return web_view_->SetFocus(enable);
 }
 
-WebRange WebViewFrameWidget::CompositionRange() {
-  return web_view_->CompositionRange();
-}
-
 bool WebViewFrameWidget::SelectionBounds(WebRect& anchor,
                                          WebRect& focus) const {
   return web_view_->SelectionBounds(anchor, focus);
diff --git a/third_party/WebKit/Source/core/frame/WebViewFrameWidget.h b/third_party/WebKit/Source/core/frame/WebViewFrameWidget.h
index 3d540f8..7193ef7 100644
--- a/third_party/WebKit/Source/core/frame/WebViewFrameWidget.h
+++ b/third_party/WebKit/Source/core/frame/WebViewFrameWidget.h
@@ -69,7 +69,6 @@
                                          bool has_scrolled_by_touch) override;
   void MouseCaptureLost() override;
   void SetFocus(bool) override;
-  WebRange CompositionRange() override;
   bool SelectionBounds(WebRect& anchor, WebRect& focus) const override;
   bool SelectionTextDirection(WebTextDirection& start,
                               WebTextDirection& end) const override;
diff --git a/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp
index 290611e..f301ef6d 100644
--- a/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp
@@ -141,22 +141,24 @@
 void ObjectPaintInvalidator::InvalidatePaintOfPreviousVisualRect(
     const LayoutBoxModelObject& paint_invalidation_container,
     PaintInvalidationReason reason) {
-  DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV175Enabled());
   // It's caller's responsibility to ensure enclosingSelfPaintingLayer's
   // needsRepaint is set.  Don't set the flag here because getting
   // enclosingSelfPaintLayer has cost and the caller can use various ways (e.g.
   // PaintInvalidatinState::enclosingSelfPaintingLayer()) to reduce the cost.
   DCHECK(!object_.PaintingLayer() || object_.PaintingLayer()->NeedsRepaint());
 
-  // These disablers are valid because we want to use the current
-  // compositing/invalidation status.
-  DisablePaintInvalidationStateAsserts invalidation_disabler;
-  DisableCompositingQueryAsserts compositing_disabler;
+  // For SPv175, raster invalidation will be issued after painting.
+  if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
+    // These disablers are valid because we want to use the current
+    // compositing/invalidation status.
+    DisablePaintInvalidationStateAsserts invalidation_disabler;
+    DisableCompositingQueryAsserts compositing_disabler;
 
-  LayoutRect invalidation_rect = object_.FragmentsVisualRectBoundingBox();
-  InvalidatePaintUsingContainer(paint_invalidation_container, invalidation_rect,
-                                reason);
-  object_.InvalidateDisplayItemClients(reason);
+    LayoutRect invalidation_rect = object_.FragmentsVisualRectBoundingBox();
+    InvalidatePaintUsingContainer(paint_invalidation_container,
+                                  invalidation_rect, reason);
+    object_.InvalidateDisplayItemClients(reason);
+  }
 
   // This method may be used to invalidate paint of an object changing paint
   // invalidation container.  Clear previous visual rect on the original paint
@@ -176,9 +178,6 @@
   TraverseNonCompositingDescendantsInPaintOrder(
       object_, [&paint_invalidation_container](const LayoutObject& object) {
         SetPaintingLayerNeedsRepaintDuringTraverse(object);
-        // For SPv175, raster invalidation will be issued after painting.
-        if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
-          return;
         ObjectPaintInvalidator(object).InvalidatePaintOfPreviousVisualRect(
             paint_invalidation_container, PaintInvalidationReason::kSubtree);
       });
@@ -202,7 +201,6 @@
 void ObjectPaintInvalidator::
     InvalidatePaintIncludingNonSelfPaintingLayerDescendants(
         const LayoutBoxModelObject& paint_invalidation_container) {
-  DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV175Enabled());
   SlowSetPaintingLayerNeedsRepaint();
   InvalidatePaintIncludingNonSelfPaintingLayerDescendantsInternal(
       paint_invalidation_container);
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index 3cdd922..3ff824c7 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -1454,7 +1454,7 @@
   // this object is stacked content, creating this layer may cause this object
   // and its descendants to change paint invalidation container.
   bool did_set_paint_invalidation = false;
-  if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
+  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
       !GetLayoutObject().IsLayoutView() && GetLayoutObject().IsRooted() &&
       GetLayoutObject().StyleRef().IsStacked()) {
     const LayoutBoxModelObject& previous_paint_invalidation_container =
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGElement.cpp
index ae10769..c960c74a 100644
--- a/third_party/WebKit/Source/core/svg/SVGElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGElement.cpp
@@ -167,9 +167,9 @@
 
 String SVGElement::title() const {
   // According to spec, we should not return titles when hovering over root
-  // <svg> elements (those <title> elements are the title of the document, not a
-  // tooltip) so we instantly return.
-  if (IsOutermostSVGSVGElement())
+  // <svg> elements imported as a standalone document(those <title> elements
+  // are the title of the document, not a tooltip) so we instantly return.
+  if (IsSVGSVGElement(*this) && this == GetDocument().documentElement())
     return String();
 
   if (InUseShadowTree()) {
diff --git a/third_party/WebKit/Source/devtools/front_end/color_picker/Spectrum.js b/third_party/WebKit/Source/devtools/front_end/color_picker/Spectrum.js
index 3061ccc..ffc2ee1a 100644
--- a/third_party/WebKit/Source/devtools/front_end/color_picker/Spectrum.js
+++ b/third_party/WebKit/Source/devtools/front_end/color_picker/Spectrum.js
@@ -61,27 +61,28 @@
           new ColorPicker.ContrastOverlay(this._colorElement, this.contentElement, boundToggleColorPicker);
     }
 
-    var toolbar = new UI.Toolbar('spectrum-eye-dropper', this.contentElement);
+    var controlsContainer = this.contentElement.createChild('div', 'controls-container');
+    var toolbar = new UI.Toolbar('spectrum-eye-dropper', controlsContainer);
     this._colorPickerButton = new UI.ToolbarToggle(Common.UIString('Toggle color picker'), 'largeicon-eyedropper');
     this._colorPickerButton.setToggled(true);
     this._colorPickerButton.addEventListener(
         UI.ToolbarButton.Events.Click, this._toggleColorPicker.bind(this, undefined));
     toolbar.appendToolbarItem(this._colorPickerButton);
 
-    this._swatch = new ColorPicker.Spectrum.Swatch(this.contentElement);
+    this._swatch = new ColorPicker.Spectrum.Swatch(controlsContainer);
 
-    this._hueElement = this.contentElement.createChild('div', 'spectrum-hue');
+    this._hueElement = controlsContainer.createChild('div', 'spectrum-hue');
     this._hueSlider = this._hueElement.createChild('div', 'spectrum-slider');
-    this._alphaElement = this.contentElement.createChild('div', 'spectrum-alpha');
+    this._alphaElement = controlsContainer.createChild('div', 'spectrum-alpha');
     this._alphaElementBackground = this._alphaElement.createChild('div', 'spectrum-alpha-background');
     this._alphaSlider = this._alphaElement.createChild('div', 'spectrum-slider');
 
-    var displaySwitcher = this.contentElement.createChild('div', 'spectrum-display-switcher spectrum-switcher');
+    var displaySwitcher = controlsContainer.createChild('div', 'spectrum-display-switcher spectrum-switcher');
     appendSwitcherIcon(displaySwitcher);
     displaySwitcher.addEventListener('click', this._formatViewSwitch.bind(this));
 
     // RGBA/HSLA display.
-    this._displayContainer = this.contentElement.createChild('div', 'spectrum-text source-code');
+    this._displayContainer = controlsContainer.createChild('div', 'spectrum-text source-code');
     this._textValues = [];
     for (var i = 0; i < 4; ++i) {
       var inputValue = UI.createInput('spectrum-text-value');
@@ -96,7 +97,7 @@
     this._textLabels = this._displayContainer.createChild('div', 'spectrum-text-label');
 
     // HEX display.
-    this._hexContainer = this.contentElement.createChild('div', 'spectrum-text spectrum-text-hex source-code');
+    this._hexContainer = controlsContainer.createChild('div', 'spectrum-text spectrum-text-hex source-code');
     this._hexValue = UI.createInput('spectrum-text-value');
     this._hexContainer.appendChild(this._hexValue);
     this._hexValue.maxLength = 9;
@@ -119,13 +120,13 @@
     this._palettes = new Map();
     this._palettePanel = this.contentElement.createChild('div', 'palette-panel');
     this._palettePanelShowing = false;
-    this._paletteContainer = this.contentElement.createChild('div', 'spectrum-palette');
+    this._paletteContainer = controlsContainer.createChild('div', 'spectrum-palette');
     this._paletteContainer.addEventListener('contextmenu', this._showPaletteColorContextMenu.bind(this, -1));
-    this._shadesContainer = this.contentElement.createChild('div', 'palette-color-shades hidden');
+    this._shadesContainer = controlsContainer.createChild('div', 'palette-color-shades hidden');
     UI.installDragHandle(
         this._paletteContainer, this._paletteDragStart.bind(this), this._paletteDrag.bind(this),
         this._paletteDragEnd.bind(this), 'default');
-    var paletteSwitcher = this.contentElement.createChild('div', 'spectrum-palette-switcher spectrum-switcher');
+    var paletteSwitcher = controlsContainer.createChild('div', 'spectrum-palette-switcher spectrum-switcher');
     appendSwitcherIcon(paletteSwitcher);
     paletteSwitcher.addEventListener('click', this._togglePalettePanel.bind(this, true));
 
diff --git a/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css b/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css
index 28880f1b..63375cb 100644
--- a/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css
+++ b/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css
@@ -491,6 +491,10 @@
     visibility: hidden;
 }
 
+.palette-panel-showing > .controls-container {
+    visibility: hidden;
+}
+
 .palette-panel-showing > .palette-panel {
     transform: translateY(calc(-100% + 117px));
     transition-delay: 0s;
diff --git a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp
index 4dd5f5c..d6ddb4e 100644
--- a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp
+++ b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp
@@ -169,7 +169,10 @@
       for (size_t i = 1; i < tokens.size(); i++) {
         if (EqualIgnoringASCIICase(tokens[i], "'self'")) {
           origins.push_back(self_origin->ToUrlOrigin());
-        } else if (EqualIgnoringASCIICase(tokens[i], "'src'")) {
+        } else if (src_origin && EqualIgnoringASCIICase(tokens[i], "'src'")) {
+          // Only iframe allow attribute can define src origin.
+          // When parsing feature policy header, src is disallowed and
+          // src_origin = nullptr.
           origins.push_back(src_origin->ToUrlOrigin());
         } else if (EqualIgnoringASCIICase(tokens[i], "'none'")) {
           continue;
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.cpp b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
index bcc2214..10a637b 100644
--- a/third_party/WebKit/Source/platform/heap/HeapPage.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
@@ -1832,7 +1832,7 @@
 
 void HeapDoesNotContainCache::Flush() {
   if (has_entries_) {
-    for (int i = 0; i < kNumberOfEntries; ++i)
+    for (size_t i = 0; i < kNumberOfEntries; ++i)
       entries_[i] = nullptr;
     has_entries_ = false;
   }
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.h b/third_party/WebKit/Source/platform/heap/HeapPage.h
index 81fd8f5..58a6c79 100644
--- a/third_party/WebKit/Source/platform/heap/HeapPage.h
+++ b/third_party/WebKit/Source/platform/heap/HeapPage.h
@@ -48,52 +48,58 @@
 
 namespace blink {
 
-const size_t kBlinkPageSizeLog2 = 17;
-const size_t kBlinkPageSize = 1 << kBlinkPageSizeLog2;
-const size_t kBlinkPageOffsetMask = kBlinkPageSize - 1;
-const size_t kBlinkPageBaseMask = ~kBlinkPageOffsetMask;
+// TODO(palmer): Document the reason for 17.
+constexpr size_t kBlinkPageSizeLog2 = 17;
+constexpr size_t kBlinkPageSize = 1 << kBlinkPageSizeLog2;
+constexpr size_t kBlinkPageOffsetMask = kBlinkPageSize - 1;
+constexpr size_t kBlinkPageBaseMask = ~kBlinkPageOffsetMask;
 
-// We allocate pages at random addresses but in groups of
-// blinkPagesPerRegion at a given random address. We group pages to
-// not spread out too much over the address space which would blow
-// away the page tables and lead to bad performance.
-const size_t kBlinkPagesPerRegion = 10;
+// We allocate pages at random addresses but in groups of kBlinkPagesPerRegion
+// at a given random address. We group pages to not spread out too much over the
+// address space which would blow away the page tables and lead to bad
+// performance.
+constexpr size_t kBlinkPagesPerRegion = 10;
 
 // TODO(nya): Replace this with something like #if ENABLE_NACL.
 #if 0
-// NaCl's system page size is 64 KB. This causes a problem in Oilpan's heap
-// layout because Oilpan allocates two guard pages for each blink page
-// (whose size is 128 KB). So we don't use guard pages in NaCl.
-const size_t blinkGuardPageSize = 0;
+// NaCl's system page size is 64 KiB. This causes a problem in Oilpan's heap
+// layout because Oilpan allocates two guard pages for each Blink page (whose
+// size is kBlinkPageSize = 2^17 = 128 KiB). So we don't use guard pages in
+// NaCl.
+constexpr size_t kBlinkGuardPageSize = 0;
 #else
-const size_t kBlinkGuardPageSize = base::kSystemPageSize;
+constexpr size_t kBlinkGuardPageSize = base::kSystemPageSize;
 #endif
 
-// Double precision floats are more efficient when 8 byte aligned, so we 8 byte
-// align all allocations even on 32 bit.
-const size_t kAllocationGranularity = 8;
-const size_t kAllocationMask = kAllocationGranularity - 1;
-const size_t kObjectStartBitMapSize =
+// Double precision floats are more efficient when 8-byte aligned, so we 8-byte
+// align all allocations (even on 32 bit systems).
+static_assert(8 == sizeof(double), "We expect sizeof(double) to be 8");
+constexpr size_t kAllocationGranularity = sizeof(double);
+constexpr size_t kAllocationMask = kAllocationGranularity - 1;
+// Round up to the next integer number of 8 * kAllocationGranularity byte
+// units:
+constexpr size_t kObjectStartBitMapSize =
     (kBlinkPageSize + ((8 * kAllocationGranularity) - 1)) /
     (8 * kAllocationGranularity);
-const size_t kReservedForObjectBitMap =
+constexpr size_t kReservedForObjectBitMap =
     ((kObjectStartBitMapSize + kAllocationMask) & ~kAllocationMask);
-const size_t kMaxHeapObjectSizeLog2 = 27;
-const size_t kMaxHeapObjectSize = 1 << kMaxHeapObjectSizeLog2;
-const size_t kLargeObjectSizeThreshold = kBlinkPageSize / 2;
+// TODO(palmer): Document the reason for 27.
+constexpr size_t kMaxHeapObjectSizeLog2 = 27;
+constexpr size_t kMaxHeapObjectSize = 1 << kMaxHeapObjectSizeLog2;
+constexpr size_t kLargeObjectSizeThreshold = kBlinkPageSize / 2;
 
 // A zap value used for freed memory that is allowed to be added to the free
-// list in the next addToFreeList().
-const uint8_t kReuseAllowedZapValue = 0x2a;
+// list in the next call to AddToFreeList.
+constexpr uint8_t kReuseAllowedZapValue = 0x2a;
 // A zap value used for freed memory that is forbidden to be added to the free
-// list in the next addToFreeList().
-const uint8_t kReuseForbiddenZapValue = 0x2c;
+// list in the next call to AddToFreeList.
+constexpr uint8_t kReuseForbiddenZapValue = 0x2c;
 
-// In non-production builds, memory is zapped when it's freed. The zapped
-// memory is zeroed out when the memory is reused in
-// ThreadHeap::allocateObject().
-// In production builds, memory is not zapped (for performance). The memory
-// is just zeroed out when it is added to the free list.
+// In non-production builds, memory is zapped when it's freed. The zapped memory
+// is zeroed out when the memory is reused in ThreadHeap::AllocateObject.
+//
+// In production builds, memory is not zapped (for performance). The memory is
+// just zeroed out when it is added to the free list.
 #if defined(MEMORY_SANITIZER)
 // TODO(kojii): We actually need __msan_poison/unpoison here, but it'll be
 // added later.
@@ -133,48 +139,49 @@
 // object that has the following layout:
 //
 // | random magic value (32 bits) | <- present on 64-bit platforms only
-// | gcInfoIndex (14 bits)        |
+// | gc_info_index (14 bits)      |
 // | DOM mark bit (1 bit)         |
 // | size (14 bits)               |
 // | dead bit (1 bit)             |
 // | freed bit (1 bit)            |
 // | mark bit (1 bit)             |
 //
-// - For non-large objects, 14 bits are enough for |size| because the Blink
-//   page size is 2^17 bytes and each object is guaranteed to be aligned on a
-//   2^3 byte boundary.
+// - For non-large objects, 14 bits are enough for |size| because the Blink page
+//   size is 2^kBlinkPageSizeLog2 (kBlinkPageSizeLog2 = 17) bytes, and each
+//   object is guaranteed to be aligned on a kAllocationGranularity-byte
+//   boundary.
 // - For large objects, |size| is 0. The actual size of a large object is
-//   stored in |LargeObjectPage::m_payloadSize|.
+//   stored in |LargeObjectPage::payload_size_|.
 // - 1 bit used to mark DOM trees for V8.
-// - 14 bits are enough for |gcInfoIndex| because there are fewer than 2^14
+// - 14 bits are enough for |gc_info_index| because there are fewer than 2^14
 //   types in Blink.
-const size_t kHeaderWrapperMarkBitMask = 1u << 17;
-const size_t kHeaderGCInfoIndexShift = 18;
-const size_t kHeaderGCInfoIndexMask = (static_cast<size_t>((1 << 14) - 1))
-                                      << kHeaderGCInfoIndexShift;
-const size_t kHeaderSizeMask = (static_cast<size_t>((1 << 14) - 1)) << 3;
-const size_t kHeaderMarkBitMask = 1;
-const size_t kHeaderFreedBitMask = 2;
+constexpr size_t kHeaderWrapperMarkBitMask = 1u << kBlinkPageSizeLog2;
+constexpr size_t kHeaderGCInfoIndexShift = kBlinkPageSizeLog2 + 1;
+constexpr size_t kHeaderGCInfoIndexMask = (static_cast<size_t>((1 << 14) - 1))
+                                          << kHeaderGCInfoIndexShift;
+constexpr size_t kHeaderSizeMask = (static_cast<size_t>((1 << 14) - 1)) << 3;
+constexpr size_t kHeaderMarkBitMask = 1;
+constexpr size_t kHeaderFreedBitMask = 2;
 // TODO(haraken): Remove the dead bit. It is used only by a header of
 // a promptly freed object.
-const size_t kHeaderDeadBitMask = 4;
+constexpr size_t kHeaderDeadBitMask = 4;
 // On free-list entries we reuse the dead bit to distinguish a normal free-list
 // entry from one that has been promptly freed.
-const size_t kHeaderPromptlyFreedBitMask =
+constexpr size_t kHeaderPromptlyFreedBitMask =
     kHeaderFreedBitMask | kHeaderDeadBitMask;
-const size_t kLargeObjectSizeInHeader = 0;
-const size_t kGcInfoIndexForFreeListHeader = 0;
-const size_t kNonLargeObjectPageSizeMax = 1 << 17;
+constexpr size_t kLargeObjectSizeInHeader = 0;
+constexpr size_t kGcInfoIndexForFreeListHeader = 0;
+constexpr size_t kNonLargeObjectPageSizeMax = 1 << kBlinkPageSizeLog2;
 
 static_assert(
     kNonLargeObjectPageSizeMax >= kBlinkPageSize,
-    "max size supported by HeapObjectHeader must at least be blinkPageSize");
+    "max size supported by HeapObjectHeader must at least be kBlinkPageSize");
 
 class PLATFORM_EXPORT HeapObjectHeader {
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
  public:
-  // If |gcInfoIndex| is 0, this header is interpreted as a free list header.
+  // If |gc_info_index| is 0, this header is interpreted as a free list header.
   NO_SANITIZE_ADDRESS
   HeapObjectHeader(size_t size, size_t gc_info_index) {
     // sizeof(HeapObjectHeader) must be equal to or smaller than
@@ -291,15 +298,15 @@
   Address GetAddress() { return reinterpret_cast<Address>(this); }
 
   NO_SANITIZE_ADDRESS
-  void Unlink(FreeListEntry** prev_next) {
-    *prev_next = next_;
+  void Unlink(FreeListEntry** previous_next) {
+    *previous_next = next_;
     next_ = nullptr;
   }
 
   NO_SANITIZE_ADDRESS
-  void Link(FreeListEntry** prev_next) {
-    next_ = *prev_next;
-    *prev_next = this;
+  void Link(FreeListEntry** previous_next) {
+    next_ = *previous_next;
+    *previous_next = this;
   }
 
   NO_SANITIZE_ADDRESS
@@ -354,7 +361,7 @@
 }
 
 // Callback used for unit testing the marking of conservative pointers
-// (|checkAndMarkPointer|). For each pointer that has been discovered to point
+// (|CheckAndMarkPointer|). For each pointer that has been discovered to point
 // to a heap object, the callback is invoked with a pointer to its header. If
 // the callback returns true, the object will not be marked.
 using MarkedPointerCallbackForTesting = bool (*)(HeapObjectHeader*);
@@ -362,16 +369,16 @@
 
 // |BasePage| is a base class for |NormalPage| and |LargeObjectPage|.
 //
-// - |NormalPage| is a page whose size is |blinkPageSize|. A |NormalPage| can
+// - |NormalPage| is a page whose size is |kBlinkPageSize|. A |NormalPage| can
 //   contain multiple objects. An object whose size is smaller than
-//   |largeObjectSizeThreshold| is stored in a |NormalPage|.
+//   |kLargeObjectSizeThreshold| is stored in a |NormalPage|.
 //
 // - |LargeObjectPage| is a page that contains only one object. The object size
-//   is arbitrary. An object whose size is larger than |blinkPageSize| is stored
-//   as a single project in |LargeObjectPage|.
+//   is arbitrary. An object whose size is larger than |kBlinkPageSize| is
+//   stored as a single project in |LargeObjectPage|.
 //
-// Note: An object whose size is between |largeObjectSizeThreshold| and
-// |blinkPageSize| can go to either of |NormalPage| or |LargeObjectPage|.
+// Note: An object whose size is between |kLargeObjectSizeThreshold| and
+// |kBlinkPageSize| can go to either of |NormalPage| or |LargeObjectPage|.
 class BasePage {
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
@@ -406,7 +413,7 @@
   // Check if the given address points to an object in this heap page. If so,
   // find the start of that object and mark it using the given |Visitor|.
   // Otherwise do nothing. The pointer must be within the same aligned
-  // |blinkPageSize| as |this|.
+  // |kBlinkPageSize| as |this|.
   //
   // This is used during conservative stack scanning to conservatively mark all
   // objects that could be referenced from the stack.
@@ -503,7 +510,7 @@
                     ThreadState::GCSnapshotInfo&,
                     HeapSnapshotInfo&) override;
 #if DCHECK_IS_ON()
-  // Returns true for the whole |blinkPageSize| page that the page is on, even
+  // Returns true for the whole |kBlinkPageSize| page that the page is on, even
   // for the header, and the unmapped guard page at the start. That ensures the
   // result can be used to populate the negative page cache.
   bool Contains(Address) override;
@@ -529,7 +536,7 @@
    public:
     // Page compacting into.
     NormalPage* current_page_ = nullptr;
-    // Offset into |m_currentPage| to the next free address.
+    // Offset into |current_page_| to the next free address.
     size_t allocation_point_ = 0;
     // Chain of available pages to use for compaction. Page compaction picks the
     // next one when the current one is exhausted.
@@ -560,11 +567,11 @@
 
   // LargeObjectPage has the following memory layout:
   //
-  //     | metadata | HeapObjectHeader | ObjectPayload |
+  //     | metadata | HeapObjectHeader | payload |
   //
-  // LargeObjectPage::PayloadSize() returns the size of HeapObjectHeader and
-  // ObjectPayload. HeapObjectHeader::PayloadSize() returns just the size of
-  // ObjectPayload.
+  // LargeObjectPage::PayloadSize returns the size of HeapObjectHeader and the
+  // object payload. HeapObjectHeader::PayloadSize returns just the size of the
+  // payload.
   Address Payload() { return GetHeapObjectHeader()->Payload(); }
   size_t PayloadSize() { return payload_size_; }
   Address PayloadEnd() { return Payload() + PayloadSize(); }
@@ -647,7 +654,7 @@
   HeapDoesNotContainCache() : has_entries_(false) {
     // Start by flushing the cache in a non-empty state to initialize all the
     // cache entries.
-    for (int i = 0; i < kNumberOfEntries; ++i)
+    for (size_t i = 0; i < kNumberOfEntries; ++i)
       entries_[i] = nullptr;
   }
 
@@ -667,8 +674,8 @@
   PLATFORM_EXPORT void AddEntry(Address);
 
  private:
-  static const int kNumberOfEntriesLog2 = 12;
-  static const int kNumberOfEntries = 1 << kNumberOfEntriesLog2;
+  static constexpr size_t kNumberOfEntriesLog2 = 12;
+  static constexpr size_t kNumberOfEntries = 1 << kNumberOfEntriesLog2;
 
   static size_t GetHash(Address);
 
@@ -770,15 +777,19 @@
 
   // Index into the page pools. This is used to ensure that the pages of the
   // same type go into the correct page pool and thus avoid type confusion.
+  //
+  // TODO(palmer): Should this be size_t?
   int index_;
 };
 
 class PLATFORM_EXPORT NormalPageArena final : public BaseArena {
  public:
-  NormalPageArena(ThreadState*, int);
+  NormalPageArena(ThreadState*, int index);
   void AddToFreeList(Address address, size_t size) {
 #if DCHECK_IS_ON()
     DCHECK(FindPageFromAddress(address));
+    // TODO(palmer): Do we need to handle about integer overflow here (and in
+    // similar expressions elsewhere)?
     DCHECK(FindPageFromAddress(address + size - 1));
 #endif
     free_list_.AddToFreeList(address, size);
@@ -805,7 +816,7 @@
   }
 
   bool IsLazySweeping() const { return is_lazy_sweeping_; }
-  void SetIsLazySweeping(bool flag) { is_lazy_sweeping_ = flag; }
+  void SetIsLazySweeping(bool sweeping) { is_lazy_sweeping_ = sweeping; }
 
   size_t ArenaSize();
   size_t FreeListSize();
@@ -843,7 +854,7 @@
 
 class LargeObjectArena final : public BaseArena {
  public:
-  LargeObjectArena(ThreadState*, int);
+  LargeObjectArena(ThreadState*, int index);
   Address AllocateLargeObjectPage(size_t, size_t gc_info_index);
   void FreeLargeObjectPage(LargeObjectPage*);
 #if DCHECK_IS_ON()
@@ -854,9 +865,9 @@
   Address LazySweepPages(size_t, size_t gc_info_index) override;
 };
 
-// Mask an address down to the enclosing oilpan heap base page. All Oilpan heap
-// pages are aligned at |blinkPageBase| plus the size of a guard size.
-// This will work only for 1) a pointer pointing to a non-large object and 2) a
+// Mask an address down to the enclosing Oilpan heap base page. All Oilpan heap
+// pages are aligned at |kBlinkPageBase| plus the size of a guard page. This
+// will work only for 1) a pointer pointing to a non-large object and 2) a
 // pointer pointing to the beginning of a large object.
 //
 // FIXME: Remove PLATFORM_EXPORT once we get a proper public interface to our
@@ -874,7 +885,7 @@
 NO_SANITIZE_ADDRESS inline size_t HeapObjectHeader::size() const {
   size_t result = encoded_ & kHeaderSizeMask;
   // Large objects should not refer to header->size(). The actual size of a
-  // large object is stored in |LargeObjectPage::m_payloadSize|.
+  // large object is stored in |LargeObjectPage::payload_size_|.
   DCHECK(result != kLargeObjectSizeInHeader);
   DCHECK(!PageFromObject(this)->IsLargeObjectPage());
   return result;
diff --git a/third_party/WebKit/Source/platform/scheduler/BUILD.gn b/third_party/WebKit/Source/platform/scheduler/BUILD.gn
index c69f4d9..3121d6e 100644
--- a/third_party/WebKit/Source/platform/scheduler/BUILD.gn
+++ b/third_party/WebKit/Source/platform/scheduler/BUILD.gn
@@ -10,6 +10,8 @@
     "base/cancelable_closure_holder.h",
     "base/enqueue_order.cc",
     "base/enqueue_order.h",
+    "base/graceful_queue_shutdown_helper.cc",
+    "base/graceful_queue_shutdown_helper.h",
     "base/intrusive_heap.h",
     "base/lazy_now.cc",
     "base/lazy_now.h",
diff --git a/third_party/WebKit/Source/platform/scheduler/base/graceful_queue_shutdown_helper.cc b/third_party/WebKit/Source/platform/scheduler/base/graceful_queue_shutdown_helper.cc
new file mode 100644
index 0000000..df4d89e
--- /dev/null
+++ b/third_party/WebKit/Source/platform/scheduler/base/graceful_queue_shutdown_helper.cc
@@ -0,0 +1,40 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "platform/scheduler/base/task_queue_impl.h"
+
+namespace blink {
+namespace scheduler {
+namespace internal {
+
+GracefulQueueShutdownHelper::GracefulQueueShutdownHelper()
+    : task_queue_manager_deleted_(false) {}
+
+GracefulQueueShutdownHelper::~GracefulQueueShutdownHelper() {}
+
+void GracefulQueueShutdownHelper::GracefullyShutdownTaskQueue(
+    std::unique_ptr<internal::TaskQueueImpl> task_queue) {
+  base::AutoLock lock(lock_);
+  if (task_queue_manager_deleted_)
+    return;
+  queues_.push_back(std::move(task_queue));
+}
+
+void GracefulQueueShutdownHelper::OnTaskQueueManagerDeleted() {
+  base::AutoLock lock(lock_);
+  task_queue_manager_deleted_ = true;
+  queues_.clear();
+}
+
+std::vector<std::unique_ptr<internal::TaskQueueImpl>>
+GracefulQueueShutdownHelper::TakeQueues() {
+  base::AutoLock lock(lock_);
+  std::vector<std::unique_ptr<internal::TaskQueueImpl>> result;
+  result.swap(queues_);
+  return result;
+}
+
+}  // namespace internal
+}  // namespace scheduler
+}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/graceful_queue_shutdown_helper.h b/third_party/WebKit/Source/platform/scheduler/base/graceful_queue_shutdown_helper.h
new file mode 100644
index 0000000..3421cb6
--- /dev/null
+++ b/third_party/WebKit/Source/platform/scheduler/base/graceful_queue_shutdown_helper.h
@@ -0,0 +1,47 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_GRACEFUL_QUEUE_SHUTDOWN_HELPER_H_
+#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_GRACEFUL_QUEUE_SHUTDOWN_HELPER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+
+namespace blink {
+namespace scheduler {
+namespace internal {
+
+class TaskQueueImpl;
+
+// Thread-safe helper to shutdown queues from any thread.
+class GracefulQueueShutdownHelper
+    : public base::RefCountedThreadSafe<GracefulQueueShutdownHelper> {
+ public:
+  GracefulQueueShutdownHelper();
+  ~GracefulQueueShutdownHelper();
+
+  void GracefullyShutdownTaskQueue(
+      std::unique_ptr<internal::TaskQueueImpl> queue);
+
+  void OnTaskQueueManagerDeleted();
+
+  std::vector<std::unique_ptr<internal::TaskQueueImpl>> TakeQueues();
+
+ private:
+  base::Lock lock_;
+  bool task_queue_manager_deleted_;
+  std::vector<std::unique_ptr<internal::TaskQueueImpl>> queues_;
+
+  DISALLOW_COPY_AND_ASSIGN(GracefulQueueShutdownHelper);
+};
+
+}  // namespace internal
+}  // namespace scheduler
+}  // namespace blink
+
+#endif  // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_GRACEFUL_QUEUE_SHUTDOWN_HELPER_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue.cc
index 1e924f1d..53f1541 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue.cc
@@ -15,9 +15,10 @@
                      const TaskQueue::Spec& spec)
     : impl_(std::move(impl)),
       thread_id_(base::PlatformThread::CurrentId()),
-      shutdown_task_runner_(spec.shutdown_task_runner),
       task_queue_manager_(impl_ ? impl_->GetTaskQueueManagerWeakPtr()
-                                : nullptr) {}
+                                : nullptr),
+      graceful_queue_shutdown_helper_(
+          impl_ ? impl_->GetGracefulQueueShutdownHelper() : nullptr) {}
 
 TaskQueue::~TaskQueue() {
   // scoped_refptr guarantees us that this object isn't used.
@@ -25,13 +26,8 @@
     return;
   if (impl_->IsUnregistered())
     return;
-  // If |shutdown_task_runner_| is not provided, TaskQueue should be
-  // unregistered manually before deletion.
-  DCHECK(shutdown_task_runner_);
-  shutdown_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&TaskQueueManager::GracefullyShutdownTaskQueue,
-                 task_queue_manager_, base::Passed(std::move(impl_))));
+  graceful_queue_shutdown_helper_->GracefullyShutdownTaskQueue(
+      std::move(impl_));
 }
 
 TaskQueue::Task::Task(TaskQueue::PostedTask task,
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue.h
index 307e727a..59bd7b3a6 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue.h
@@ -13,6 +13,7 @@
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 #include "platform/PlatformExport.h"
+#include "platform/scheduler/base/graceful_queue_shutdown_helper.h"
 #include "platform/scheduler/base/moveable_auto_lock.h"
 #include "public/platform/TaskType.h"
 
@@ -129,18 +130,11 @@
       return *this;
     }
 
-    Spec SetShutdownTaskRunner(
-        scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-      shutdown_task_runner = std::move(task_runner);
-      return *this;
-    }
-
     const char* name;
     bool should_monitor_quiescence;
     TimeDomain* time_domain;
     bool should_notify_observers;
     bool should_report_when_execution_blocked;
-    scoped_refptr<base::SingleThreadTaskRunner> shutdown_task_runner;
   };
 
   // Interface to pass per-task metadata to RendererScheduler.
@@ -298,12 +292,10 @@
 
   const base::PlatformThreadId thread_id_;
 
-  // A task runner to post a task to schedule TaskQueueImpl for graceful
-  // shutdown.
-  // Present if this task queue supports graceful shutdown.
-  scoped_refptr<base::SingleThreadTaskRunner> shutdown_task_runner_;
+  const base::WeakPtr<TaskQueueManager> task_queue_manager_;
 
-  base::WeakPtr<TaskQueueManager> task_queue_manager_;
+  const scoped_refptr<internal::GracefulQueueShutdownHelper>
+      graceful_queue_shutdown_helper_;
 
   THREAD_CHECKER(main_thread_checker_);
 
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
index 6fc672b3..44395f6 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
@@ -50,8 +50,7 @@
       should_monitor_quiescence_(spec.should_monitor_quiescence),
       should_notify_observers_(spec.should_notify_observers),
       should_report_when_execution_blocked_(
-          spec.should_report_when_execution_blocked),
-      supports_async_deletion_(!!spec.shutdown_task_runner) {
+          spec.should_report_when_execution_blocked) {
   DCHECK(time_domain);
   time_domain->RegisterQueue(this);
 }
@@ -945,6 +944,12 @@
   return main_thread_only().task_queue_manager->GetWeakPtr();
 }
 
+scoped_refptr<GracefulQueueShutdownHelper>
+TaskQueueImpl::GetGracefulQueueShutdownHelper() {
+  return main_thread_only()
+      .task_queue_manager->GetGracefulQueueShutdownHelper();
+}
+
 void TaskQueueImpl::SetQueueEnabledForTest(bool enabled) {
   main_thread_only().is_enabled_for_test = enabled;
   EnableOrDisableWithSelector(IsQueueEnabled());
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h
index ad09f6a..9fc65585 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h
@@ -19,6 +19,7 @@
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "platform/scheduler/base/enqueue_order.h"
+#include "platform/scheduler/base/graceful_queue_shutdown_helper.h"
 #include "platform/scheduler/base/intrusive_heap.h"
 #include "platform/scheduler/base/task_queue.h"
 #include "platform/wtf/Deque.h"
@@ -213,11 +214,6 @@
     return should_report_when_execution_blocked_;
   }
 
-  // Returns true if the enclosing task queue supports graceful shutdown and
-  // this task queue can be used with
-  // TaskQueueManager::GracefullyShutdownTaskQueue,
-  bool supports_async_deletion() const { return supports_async_deletion_; }
-
   // Enqueues any delayed tasks which should be run now on the
   // |delayed_work_queue|. Returns the subsequent wake-up that is required, if
   // any. Must be called from the main thread.
@@ -270,6 +266,8 @@
 
   base::WeakPtr<TaskQueueManager> GetTaskQueueManagerWeakPtr();
 
+  scoped_refptr<GracefulQueueShutdownHelper> GetGracefulQueueShutdownHelper();
+
   // Returns true if this queue is unregistered or task queue manager is deleted
   // and this queue can be safely deleted on any thread.
   bool IsUnregistered() const;
@@ -420,7 +418,6 @@
   const bool should_monitor_quiescence_;
   const bool should_notify_observers_;
   const bool should_report_when_execution_blocked_;
-  const bool supports_async_deletion_;
 
   DISALLOW_COPY_AND_ASSIGN(TaskQueueImpl);
 };
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
index 9cbb8cd..770f599 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
@@ -42,6 +42,7 @@
 TaskQueueManager::TaskQueueManager(
     scoped_refptr<TaskQueueManagerDelegate> delegate)
     : real_time_domain_(new RealTimeDomain()),
+      graceful_shutdown_helper_(new internal::GracefulQueueShutdownHelper()),
       delegate_(delegate),
       task_was_run_on_quiescence_monitored_queue_(false),
       work_batch_size_(1),
@@ -71,37 +72,15 @@
       TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager",
       this);
 
-  // Queues supporting async deletion should be unregistered first -
-  // their ownership might belong to a task in a shutdown task queue
-  // and shutdown task queue should be unregistered after them.
-  // TODO(altimin): DCHECK that shutdown task queue does not support
-  // async deletion.
-  for (auto it = active_queues_.begin(); it != active_queues_.end();) {
-    internal::TaskQueueImpl* queue = *it;
-    if (queue->supports_async_deletion()) {
-      selector_.RemoveQueue(queue);
-      queue->UnregisterTaskQueue();
-      it = active_queues_.erase(it);
-    } else {
-      ++it;
-    }
-  }
-
   for (internal::TaskQueueImpl* queue : active_queues_) {
     selector_.RemoveQueue(queue);
     queue->UnregisterTaskQueue();
   }
 
   active_queues_.clear();
+  queues_to_gracefully_shutdown_.clear();
 
-  while (!queues_to_gracefully_shutdown_.empty()) {
-    internal::TaskQueueImpl* queue =
-        queues_to_gracefully_shutdown_.begin()->first;
-    selector_.RemoveQueue(queue);
-    queue->UnregisterTaskQueue();
-    queues_to_gracefully_shutdown_.erase(
-        queues_to_gracefully_shutdown_.begin());
-  }
+  graceful_shutdown_helper_->OnTaskQueueManagerDeleted();
 
   selector_.SetTaskQueueSelectorObserver(nullptr);
 
@@ -161,18 +140,6 @@
   queues_to_delete_[task_queue.get()] = std::move(task_queue);
 }
 
-void TaskQueueManager::GracefullyShutdownTaskQueue(
-    std::unique_ptr<internal::TaskQueueImpl> task_queue) {
-  TRACE_EVENT1("renderer.scheduler",
-               "TaskQueueManager::GracefullyShutdownTaskQueue", "queue_name",
-               task_queue->GetName());
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-
-  DCHECK(active_queues_.find(task_queue.get()) != active_queues_.end());
-  active_queues_.erase(task_queue.get());
-  queues_to_gracefully_shutdown_[task_queue.get()] = std::move(task_queue);
-}
-
 void TaskQueueManager::ReloadEmptyWorkQueues(
     const IncomingImmediateWorkMap& queues_to_reload) const {
   // There are two cases where a queue needs reloading.  First, it might be
@@ -657,8 +624,6 @@
   size_t task_count = 0;
   for (auto& queue : active_queues_)
     task_count += queue->GetNumberOfPendingTasks();
-  for (const auto& pair : queues_to_gracefully_shutdown_)
-    task_count += pair.first->GetNumberOfPendingTasks();
   return task_count;
 }
 
@@ -753,11 +718,22 @@
     SweepCanceledDelayedTasksInQueue(pair.first, &time_domain_now);
 }
 
+void TaskQueueManager::TakeQueuesToGracefullyShutdownFromHelper() {
+  std::vector<std::unique_ptr<internal::TaskQueueImpl>> queues =
+      graceful_shutdown_helper_->TakeQueues();
+  for (std::unique_ptr<internal::TaskQueueImpl>& queue : queues) {
+    queues_to_gracefully_shutdown_[queue.get()] = std::move(queue);
+  }
+}
+
 void TaskQueueManager::CleanUpQueues() {
+  TakeQueuesToGracefullyShutdownFromHelper();
+
   for (auto it = queues_to_gracefully_shutdown_.begin();
        it != queues_to_gracefully_shutdown_.end();) {
     if (it->first->IsEmpty()) {
       UnregisterTaskQueueImpl(std::move(it->second));
+      active_queues_.erase(it->first);
       queues_to_gracefully_shutdown_.erase(it++);
     } else {
       ++it;
@@ -766,6 +742,11 @@
   queues_to_delete_.clear();
 }
 
+scoped_refptr<internal::GracefulQueueShutdownHelper>
+TaskQueueManager::GetGracefulQueueShutdownHelper() const {
+  return graceful_shutdown_helper_;
+}
+
 base::WeakPtr<TaskQueueManager> TaskQueueManager::GetWeakPtr() {
   return weak_factory_.GetWeakPtr();
 }
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
index 247dd09..3aca257 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
@@ -19,6 +19,7 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
 #include "platform/scheduler/base/enqueue_order.h"
+#include "platform/scheduler/base/graceful_queue_shutdown_helper.h"
 #include "platform/scheduler/base/moveable_auto_lock.h"
 #include "platform/scheduler/base/task_queue_impl.h"
 #include "platform/scheduler/base/task_queue_selector.h"
@@ -162,11 +163,8 @@
   void UnregisterTaskQueueImpl(
       std::unique_ptr<internal::TaskQueueImpl> task_queue);
 
-  // Notify task queue manager that owning TaskQueue has been deleted.
-  // Task queue manager will continue running tasks and will delete queue when
-  // all tasks are completed.
-  void GracefullyShutdownTaskQueue(
-      std::unique_ptr<internal::TaskQueueImpl> task_queue);
+  scoped_refptr<internal::GracefulQueueShutdownHelper>
+  GetGracefulQueueShutdownHelper() const;
 
   base::WeakPtr<TaskQueueManager> GetWeakPtr();
 
@@ -212,13 +210,14 @@
   };
 
  protected:
-  size_t active_queues_count() const { return active_queues_.size(); }
+  size_t ActiveQueuesCount() { return active_queues_.size(); }
 
-  size_t queues_to_shutdown_count() const {
+  size_t QueuesToShutdownCount() {
+    TakeQueuesToGracefullyShutdownFromHelper();
     return queues_to_gracefully_shutdown_.size();
   }
 
-  size_t queues_to_delete_count() const { return queues_to_delete_.size(); }
+  size_t QueuesToDeleteCount() { return queues_to_delete_.size(); }
 
  private:
   // Represents a scheduled delayed DoWork (if any). Only public for testing.
@@ -327,6 +326,8 @@
   std::unique_ptr<internal::TaskQueueImpl> CreateTaskQueueImpl(
       const TaskQueue::Spec& spec);
 
+  void TakeQueuesToGracefullyShutdownFromHelper();
+
   // Deletes queues marked for deletion and empty queues marked for shutdown.
   void CleanUpQueues();
 
@@ -334,7 +335,9 @@
   std::unique_ptr<RealTimeDomain> real_time_domain_;
 
   // List of task queues managed by this TaskQueueManager.
-  // - active_queues contains queues owned by relevant TaskQueues.
+  // - active_queues contains queues that are still running tasks.
+  //   Most often they are owned by relevant TaskQueues, but
+  //   queues_to_gracefully_shutdown_ are included here too.
   // - queues_to_gracefully_shutdown contains queues which should be deleted
   //   when they become empty.
   // - queues_to_delete contains soon-to-be-deleted queues, because some
@@ -347,6 +350,9 @@
   std::map<internal::TaskQueueImpl*, std::unique_ptr<internal::TaskQueueImpl>>
       queues_to_delete_;
 
+  const scoped_refptr<internal::GracefulQueueShutdownHelper>
+      graceful_shutdown_helper_;
+
   internal::EnqueueOrderGenerator enqueue_order_generator_;
   base::debug::TaskAnnotator task_annotator_;
 
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
index 4a117272..c7a7bd0 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
@@ -54,9 +54,9 @@
       : TaskQueueManager(delegate) {}
 
   using TaskQueueManager::NextTaskDelay;
-  using TaskQueueManager::active_queues_count;
-  using TaskQueueManager::queues_to_shutdown_count;
-  using TaskQueueManager::queues_to_delete_count;
+  using TaskQueueManager::ActiveQueuesCount;
+  using TaskQueueManager::QueuesToShutdownCount;
+  using TaskQueueManager::QueuesToDeleteCount;
 };
 
 class MessageLoopTaskRunner : public TaskQueueManagerDelegateForTest {
@@ -97,12 +97,6 @@
  protected:
   void TearDown() { manager_.reset(); }
 
-  scoped_refptr<TestTaskQueue> CreateTaskQueueWithShutdownTaskRunner(
-      scoped_refptr<base::SingleThreadTaskRunner> shutdown_task_runner) {
-    return manager_->CreateTaskQueue<TestTaskQueue>(
-        TaskQueue::Spec("test").SetShutdownTaskRunner(shutdown_task_runner));
-  }
-
   scoped_refptr<TestTaskQueue> CreateTaskQueueWithSpec(TaskQueue::Spec spec) {
     return manager_->CreateTaskQueue<TestTaskQueue>(spec);
   }
@@ -3144,14 +3138,12 @@
   test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
 
   std::vector<base::TimeTicks> run_times;
-  scoped_refptr<TestTaskQueue> control_tq = CreateTaskQueue();
-  scoped_refptr<TestTaskQueue> main_tq =
-      CreateTaskQueueWithShutdownTaskRunner(control_tq);
+  scoped_refptr<TestTaskQueue> main_tq = CreateTaskQueue();
   base::WeakPtr<TestTaskQueue> main_tq_weak_ptr = main_tq->GetWeakPtr();
 
-  EXPECT_EQ(2u, manager_->active_queues_count());
-  EXPECT_EQ(0u, manager_->queues_to_shutdown_count());
-  EXPECT_EQ(0u, manager_->queues_to_delete_count());
+  EXPECT_EQ(1u, manager_->ActiveQueuesCount());
+  EXPECT_EQ(0u, manager_->QueuesToShutdownCount());
+  EXPECT_EQ(0u, manager_->QueuesToDeleteCount());
 
   for (int i = 1; i <= 5; ++i) {
     main_tq->PostDelayedTask(
@@ -3166,9 +3158,9 @@
 
   test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(1));
 
-  EXPECT_EQ(1u, manager_->active_queues_count());
-  EXPECT_EQ(1u, manager_->queues_to_shutdown_count());
-  EXPECT_EQ(0u, manager_->queues_to_delete_count());
+  EXPECT_EQ(1u, manager_->ActiveQueuesCount());
+  EXPECT_EQ(1u, manager_->QueuesToShutdownCount());
+  EXPECT_EQ(0u, manager_->QueuesToDeleteCount());
 
   test_task_runner_->RunUntilIdle();
 
@@ -3181,9 +3173,9 @@
                   base::TimeTicks() + base::TimeDelta::FromMilliseconds(401),
                   base::TimeTicks() + base::TimeDelta::FromMilliseconds(501)));
 
-  EXPECT_EQ(1u, manager_->active_queues_count());
-  EXPECT_EQ(0u, manager_->queues_to_shutdown_count());
-  EXPECT_EQ(0u, manager_->queues_to_delete_count());
+  EXPECT_EQ(0u, manager_->ActiveQueuesCount());
+  EXPECT_EQ(0u, manager_->QueuesToShutdownCount());
+  EXPECT_EQ(0u, manager_->QueuesToDeleteCount());
 }
 
 TEST_F(TaskQueueManagerTest, GracefulShutdown_ManagerDeletedInFlight) {
@@ -3203,8 +3195,7 @@
   // pages.
   const int N = 100;
   for (int i = 0; i < N; ++i) {
-    scoped_refptr<TestTaskQueue> tq =
-        CreateTaskQueueWithShutdownTaskRunner(control_tq);
+    scoped_refptr<TestTaskQueue> tq = CreateTaskQueue();
     main_tq_weak_ptrs.push_back(tq->GetWeakPtr());
     main_tqs.push_back(std::move(tq));
   }
@@ -3241,14 +3232,12 @@
   test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
 
   std::vector<base::TimeTicks> run_times;
-  scoped_refptr<TestTaskQueue> control_tq = CreateTaskQueue();
-  scoped_refptr<TestTaskQueue> main_tq =
-      CreateTaskQueueWithShutdownTaskRunner(control_tq);
+  scoped_refptr<TestTaskQueue> main_tq = CreateTaskQueue();
   base::WeakPtr<TestTaskQueue> main_tq_weak_ptr = main_tq->GetWeakPtr();
 
-  EXPECT_EQ(2u, manager_->active_queues_count());
-  EXPECT_EQ(0u, manager_->queues_to_shutdown_count());
-  EXPECT_EQ(0u, manager_->queues_to_delete_count());
+  EXPECT_EQ(1u, manager_->ActiveQueuesCount());
+  EXPECT_EQ(0u, manager_->QueuesToShutdownCount());
+  EXPECT_EQ(0u, manager_->QueuesToDeleteCount());
 
   for (int i = 1; i <= 5; ++i) {
     main_tq->PostDelayedTask(
@@ -3263,9 +3252,9 @@
 
   test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(1));
 
-  EXPECT_EQ(1u, manager_->active_queues_count());
-  EXPECT_EQ(1u, manager_->queues_to_shutdown_count());
-  EXPECT_EQ(0u, manager_->queues_to_delete_count());
+  EXPECT_EQ(1u, manager_->ActiveQueuesCount());
+  EXPECT_EQ(1u, manager_->QueuesToShutdownCount());
+  EXPECT_EQ(0u, manager_->QueuesToDeleteCount());
 
   // Ensure that all queues-to-gracefully-shutdown are properly unregistered.
   manager_.reset();
diff --git a/third_party/WebKit/Source/platform/scheduler/test/test_task_queue.cc b/third_party/WebKit/Source/platform/scheduler/test/test_task_queue.cc
index d330cebe1..51c5ec5 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/test_task_queue.cc
+++ b/third_party/WebKit/Source/platform/scheduler/test/test_task_queue.cc
@@ -12,16 +12,9 @@
 TestTaskQueue::TestTaskQueue(std::unique_ptr<internal::TaskQueueImpl> impl,
                              const TaskQueue::Spec& spec)
     : TaskQueue(std::move(impl), spec),
-      automatically_shutdown_(!spec.shutdown_task_runner),
       weak_factory_(this) {}
 
-TestTaskQueue::~TestTaskQueue() {
-  if (automatically_shutdown_) {
-    // Automatically shutdowns task queue upon deletion, given the fact
-    // that TestTaskQueue lives on the main thread.
-    ShutdownTaskQueue();
-  }
-}
+TestTaskQueue::~TestTaskQueue() {}
 
 base::WeakPtr<TestTaskQueue> TestTaskQueue::GetWeakPtr() {
   return weak_factory_.GetWeakPtr();
diff --git a/third_party/WebKit/Source/platform/scheduler/test/test_task_queue.h b/third_party/WebKit/Source/platform/scheduler/test/test_task_queue.h
index a1a217c1..472192c 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/test_task_queue.h
+++ b/third_party/WebKit/Source/platform/scheduler/test/test_task_queue.h
@@ -21,8 +21,6 @@
   base::WeakPtr<TestTaskQueue> GetWeakPtr();
 
  private:
-  bool automatically_shutdown_;
-
   // Used to ensure that task queue is deleted in tests.
   base::WeakPtrFactory<TestTaskQueue> weak_factory_;
 };
diff --git a/third_party/WebKit/public/web/WebInputMethodController.h b/third_party/WebKit/public/web/WebInputMethodController.h
index 161d47f..5436fb24 100644
--- a/third_party/WebKit/public/web/WebInputMethodController.h
+++ b/third_party/WebKit/public/web/WebInputMethodController.h
@@ -68,6 +68,10 @@
 
   // Fetch the current selection range of this frame.
   virtual WebRange GetSelectionOffsets() const = 0;
+
+  // Fetches the character range of the current composition, also called the
+  // "marked range."
+  virtual WebRange CompositionRange() { return WebRange(); };
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/web/WebView.h b/third_party/WebKit/public/web/WebView.h
index 4bde849..ea31725 100644
--- a/third_party/WebKit/public/web/WebView.h
+++ b/third_party/WebKit/public/web/WebView.h
@@ -90,7 +90,6 @@
   using WebWidget::ApplyViewportDeltas;
   using WebWidget::MouseCaptureLost;
   using WebWidget::SetFocus;
-  using WebWidget::CompositionRange;
   using WebWidget::SelectionBounds;
   using WebWidget::SelectionTextDirection;
   using WebWidget::IsSelectionAnchorFirst;
diff --git a/third_party/WebKit/public/web/WebWidget.h b/third_party/WebKit/public/web/WebWidget.h
index 82ac091..bfce777 100644
--- a/third_party/WebKit/public/web/WebWidget.h
+++ b/third_party/WebKit/public/web/WebWidget.h
@@ -153,10 +153,6 @@
   // Called to inform the WebWidget that it has gained or lost keyboard focus.
   virtual void SetFocus(bool) {}
 
-  // Fetches the character range of the current composition, also called the
-  // "marked range."
-  virtual WebRange CompositionRange() { return WebRange(); }
-
   // Returns the anchor and focus bounds of the current selection.
   // If the selection range is empty, it returns the caret bounds.
   virtual bool SelectionBounds(WebRect& anchor, WebRect& focus) const {
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 23f4fd0..974bf43 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -330,8 +330,10 @@
       'Linux Builder (dbg)(32)': 'debug_bot_x86',
       'Linux Builder': 'release_bot',
       'Deterministic Linux': 'release_bot',
-      'Fuchsia x64': 'release_bot_fuchsia',
+      'Fuchsia ARM64 Cast Audio': 'release_bot_fuchsia_arm64_cast_audio',
       'Fuchsia ARM64': 'release_bot_fuchsia_arm64',
+      'Fuchsia x64 Cast Audio': 'release_bot_fuchsia_cast_audio',
+      'Fuchsia x64': 'release_bot_fuchsia',
     },
 
     'chromium.lkgr': {
@@ -589,8 +591,10 @@
       'chromeos_daisy_chromium_compile_only_ng': 'cros_chrome_sdk',
       'chromium_presubmit': 'presubmit',
       'closure_compilation': 'closure_compilation',
-      'fuchsia_x64': 'release_trybot_fuchsia',
       'fuchsia_arm64': 'release_trybot_fuchsia_arm64',
+      'fuchsia_arm64_cast_audio': 'release_trybot_fuchsia_arm64_cast_audio',
+      'fuchsia_x64': 'release_trybot_fuchsia',
+      'fuchsia_x64_cast_audio': 'release_trybot_fuchsia_cast_audio',
       # TODO(kjellander): Remove linux_arm after tryserver restart.
       'linux_arm': 'release_trybot_arm',
       'linux_arm_dbg': 'debug_trybot_arm',
@@ -1542,10 +1546,18 @@
       'release_bot', 'fuchsia',
     ],
 
+    'release_bot_fuchsia_cast_audio': [
+      'release_bot', 'fuchsia', 'cast', 'cast_audio',
+    ],
+
     'release_bot_fuchsia_arm64': [
       'release_bot', 'fuchsia', 'arm64',
     ],
 
+    'release_bot_fuchsia_arm64_cast_audio': [
+      'release_bot', 'fuchsia', 'arm64', 'cast', 'cast_audio',
+    ],
+
     'release_bot_mac_new_sdk': [
       'release_bot', 'mac_new_sdk',
     ],
@@ -1612,10 +1624,18 @@
       'release_trybot', 'fuchsia',
     ],
 
+    'release_trybot_fuchsia_cast_audio': [
+      'release_trybot', 'fuchsia', 'cast', 'cast_audio',
+    ],
+
     'release_trybot_fuchsia_arm64': [
       'release_trybot', 'fuchsia', 'arm64',
     ],
 
+    'release_trybot_fuchsia_arm64_cast_audio': [
+      'release_trybot', 'fuchsia', 'arm64', 'cast', 'cast_audio',
+    ],
+
     'release_trybot_x86': [
       'release_trybot', 'x86',
     ],
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index b1165612..4521700 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -6616,6 +6616,9 @@
 </enum>
 
 <enum name="ContextualSearchPeekPromoOutcome">
+  <obsolete>
+    Removed because the feature no longer exists.
+  </obsolete>
   <summary>The outcome of the Contextual Search Peek Promo.</summary>
   <int value="0" label="Peek Promo was seen, Panel was opened"/>
   <int value="1" label="Peek Promo was seen, Panel was not opened"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 88aa711..faca053 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -74306,6 +74306,16 @@
   </summary>
 </histogram>
 
+<histogram name="Search.ContextualSearchBarNoOverlap.PeekDuration" units="ms">
+  <owner>donnd@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    The duration that the panel was peeking before being opened when triggered
+    by a tap that was in a part of the screen where it overlaps the Bar. Logged
+    when the panel is closed after being opened. Implemented for Android.
+  </summary>
+</histogram>
+
 <histogram name="Search.ContextualSearchBarOverlap"
     enum="ContextualSearchTapSuppression">
   <owner>donnd@chromium.org</owner>
@@ -74316,6 +74326,16 @@
   </summary>
 </histogram>
 
+<histogram name="Search.ContextualSearchBarOverlap.PeekDuration" units="ms">
+  <owner>donnd@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    The duration that the panel was peeking before being opened when triggered
+    by a tap at the bottom of the screen where it overlaps the Bar.  Logged when
+    the panel is closed after being opened. Implemented for Android.
+  </summary>
+</histogram>
+
 <histogram name="Search.ContextualSearchBarOverlapSeen"
     enum="ContextualSearchBarOverlapSeen">
   <owner>donnd@chromium.org</owner>
@@ -74658,6 +74678,9 @@
 </histogram>
 
 <histogram name="Search.ContextualSearchPeekPromoCount" units="count">
+  <obsolete>
+    Removed because the feature no longer exists.
+  </obsolete>
   <owner>donnd@chromium.org</owner>
   <owner>pedrosimonetti@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
@@ -74672,6 +74695,9 @@
 
 <histogram name="Search.ContextualSearchPeekPromoCountUntilOpened"
     units="count">
+  <obsolete>
+    Removed because the feature no longer exists.
+  </obsolete>
   <owner>donnd@chromium.org</owner>
   <owner>pedrosimonetti@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
@@ -74685,6 +74711,9 @@
 
 <histogram name="Search.ContextualSearchPeekPromoOutcome"
     enum="ContextualSearchPeekPromoOutcome">
+  <obsolete>
+    Removed because the feature no longer exists.
+  </obsolete>
   <owner>donnd@chromium.org</owner>
   <owner>pedrosimonetti@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
diff --git a/tools/perf/page_sets/media_cases.py b/tools/perf/page_sets/media_cases.py
index ab447c5..cd4b97267 100644
--- a/tools/perf/page_sets/media_cases.py
+++ b/tools/perf/page_sets/media_cases.py
@@ -65,7 +65,7 @@
 # The following section contains base classes for pages.
 #
 
-class MediaPage(page_module.Page):
+class _MediaPage(page_module.Page):
 
   def __init__(self, url, page_set, tags, extra_browser_args=None,
                traffic_setting=traffic_setting_module.NONE):
@@ -77,13 +77,13 @@
       for t in tags:
         assert t in _PAGE_TAGS_LIST
     assert not ('src' in tags and 'mse' in tags)
-    super(MediaPage, self).__init__(
+    super(_MediaPage, self).__init__(
         url=url, page_set=page_set, tags=tags, name=name,
         extra_browser_args=extra_browser_args,
         traffic_setting=traffic_setting)
 
 
-class BeginningToEndPlayPage(MediaPage):
+class _BeginningToEndPlayPage(_MediaPage):
   """A normal play page simply plays the given media until the end."""
 
   def __init__(self, url, page_set, tags, extra_browser_args=None,
@@ -91,7 +91,7 @@
     tags.append('beginning_to_end')
     tags.append('src')
     self.add_browser_metrics = True
-    super(BeginningToEndPlayPage, self).__init__(
+    super(_BeginningToEndPlayPage, self).__init__(
         url, page_set, tags, extra_browser_args,
         traffic_setting=traffic_setting)
 
@@ -103,7 +103,8 @@
     if self.page_set.measure_memory:
       action_runner.MeasureMemory()
 
-class SeekPage(MediaPage):
+
+class _SeekPage(_MediaPage):
   """A seek page seeks twice in the video and measures the seek time."""
 
   def __init__(self, url, page_set, tags, extra_browser_args=None,
@@ -113,7 +114,7 @@
     tags.append('src')
     self.skip_basic_metrics = True
     self._action_timeout = action_timeout_in_seconds
-    super(SeekPage, self).__init__(
+    super(_SeekPage, self).__init__(
         url, page_set, tags, extra_browser_args,
         traffic_setting=traffic_setting)
 
@@ -134,7 +135,8 @@
     if self.page_set.measure_memory:
       action_runner.MeasureMemory()
 
-class BackgroundPlaybackPage(MediaPage):
+
+class _BackgroundPlaybackPage(_MediaPage):
   """A Background playback page plays the given media in a background tab.
 
   The motivation for this test case is crbug.com/678663.
@@ -152,7 +154,7 @@
     # not turn off video playback in the background.
     extra_browser_args = extra_browser_args or []
     extra_browser_args.append('--disable-media-suspend')
-    super(BackgroundPlaybackPage, self).__init__(
+    super(_BackgroundPlaybackPage, self).__init__(
         url, page_set, tags, extra_browser_args)
 
   def RunPageInteractions(self, action_runner):
@@ -173,11 +175,18 @@
       action_runner.MeasureMemory()
 
 
-class MSEPage(MediaPage):
+class _MSEPage(_MediaPage):
+  # TODO(crouleau): Figure out a way to make MSE pages provide consistent
+  # data. Currently the data haa a lot of outliers for time_to_play and other
+  # startup metrics. To do this, we must either:
+  # 1. Tell Telemetry to repeat these pages (this requires Telemetry's
+  # providing this option in the API.)
+  # 2. Edit the page to reload and run multiple times (you can clear the cache
+  # with tab.CleanCache). This requires crbug/775264.
 
   def __init__(self, url, page_set, tags, extra_browser_args=None):
     tags.append('mse')
-    super(MSEPage, self).__init__(
+    super(_MSEPage, self).__init__(
         url, page_set, tags, extra_browser_args)
 
   def RunPageInteractions(self, action_runner):
@@ -188,284 +197,6 @@
       raise RuntimeError(action_runner.EvaluateJavaScript('window.__testError'))
 
 
-#
-# The following section contains concrete test page definitions.
-#
-
-class Page2(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page2, self).__init__(
-      url=_URL_BASE+'video.html?src=crowd.ogg&type=audio',
-      page_set=page_set,
-      tags=['vorbis', 'audio_only'])
-
-
-class Page4(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page4, self).__init__(
-      url=_URL_BASE + 'video.html?src=crowd1080.webm',
-      page_set=page_set,
-      tags=['is_50fps', 'vp8', 'vorbis', 'audio_video'])
-
-
-class Page7(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page7, self).__init__(
-      url=_URL_BASE + 'video.html?src=tulip2.ogg&type=audio',
-      page_set=page_set,
-      tags=['vorbis', 'audio_only'])
-
-
-class Page8(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page8, self).__init__(
-      url=_URL_BASE + 'video.html?src=tulip2.wav&type=audio',
-      page_set=page_set,
-      tags=['pcm', 'audio_only'])
-
-
-class Page11(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page11, self).__init__(
-      url=_URL_BASE + 'video.html?src=crowd1080.mp4',
-      page_set=page_set,
-      tags=['is_50fps', 'h264', 'aac', 'audio_video'])
-
-
-class Page12(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page12, self).__init__(
-      url=_URL_BASE + 'video.html?src=crowd2160.mp4',
-      page_set=page_set,
-      tags=['is_4k', 'is_50fps', 'h264', 'aac', 'audio_video'])
-
-
-class Page13(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page13, self).__init__(
-      url=_URL_BASE + 'video.html?src=tulip2.mp3&type=audio',
-      page_set=page_set,
-      tags=['mp3', 'audio_only'])
-
-
-class Page14(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page14, self).__init__(
-      url=_URL_BASE + 'video.html?src=tulip2.mp4',
-      page_set=page_set,
-      tags=['h264', 'aac', 'audio_video'])
-
-
-class Page15(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page15, self).__init__(
-      url=_URL_BASE + 'video.html?src=tulip2.m4a&type=audio',
-      page_set=page_set,
-      tags=['aac', 'audio_only'])
-
-
-class Page16(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page16, self).__init__(
-      url=_URL_BASE + 'video.html?src=garden2_10s.webm',
-      page_set=page_set,
-      tags=['is_4k', 'vp8', 'vorbis', 'audio_video'])
-
-
-class Page17(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page17, self).__init__(
-      url=_URL_BASE + 'video.html?src=garden2_10s.mp4',
-      page_set=page_set,
-      tags=['is_4k', 'h264', 'aac', 'audio_video'])
-
-
-class Page19(SeekPage):
-
-  def __init__(self, page_set):
-    super(Page19, self).__init__(
-      url=_URL_BASE + 'video.html?src=tulip2.ogg&type=audio&seek',
-      page_set=page_set,
-      tags=['vorbis', 'audio_only'])
-
-
-class Page20(SeekPage):
-
-  def __init__(self, page_set):
-    super(Page20, self).__init__(
-      url=_URL_BASE + 'video.html?src=tulip2.wav&type=audio&seek',
-      page_set=page_set,
-      tags=['pcm', 'audio_only'])
-
-
-class Page23(SeekPage):
-
-  def __init__(self, page_set):
-    super(Page23, self).__init__(
-      url=_URL_BASE + 'video.html?src=tulip2.mp3&type=audio&seek',
-      page_set=page_set,
-      tags=['mp3', 'audio_only'])
-
-
-class Page24(SeekPage):
-
-  def __init__(self, page_set):
-    super(Page24, self).__init__(
-      url=_URL_BASE + 'video.html?src=tulip2.mp4&seek',
-      page_set=page_set,
-      tags=['h264', 'aac', 'audio_video'])
-
-
-class Page25(SeekPage):
-
-  def __init__(self, page_set):
-    super(Page25, self).__init__(
-      url=_URL_BASE + 'video.html?src=garden2_10s.webm&seek',
-      page_set=page_set,
-      tags=['is_4k', 'vp8', 'vorbis', 'audio_video'])
-
-
-class Page26(SeekPage):
-
-  def __init__(self, page_set):
-    super(Page26, self).__init__(
-      url=_URL_BASE + 'video.html?src=garden2_10s.mp4&seek',
-      page_set=page_set,
-      tags=['is_4k', 'h264', 'aac', 'audio_video'])
-
-
-class Page30(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page30, self).__init__(
-      url=_URL_BASE + 'video.html?src=tulip2.vp9.webm',
-      page_set=page_set,
-      tags=['vp9', 'opus', 'audio_video'])
-
-
-class Page31(SeekPage):
-
-  def __init__(self, page_set):
-    super(Page31, self).__init__(
-      url=_URL_BASE + 'video.html?src=tulip2.vp9.webm&seek',
-      page_set=page_set,
-      tags=['vp9', 'opus', 'audio_video'])
-
-
-class Page32(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page32, self).__init__(
-      url=_URL_BASE + 'video.html?src=crowd1080_vp9.webm',
-      page_set=page_set,
-      tags=['vp9', 'video_only'])
-
-
-class Page33(SeekPage):
-
-  def __init__(self, page_set):
-    super(Page33, self).__init__(
-      url=_URL_BASE + 'video.html?src=crowd1080_vp9.webm&seek',
-      page_set=page_set,
-      tags=['vp9', 'video_only', 'seek'])
-
-
-class Page34(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page34, self).__init__(
-      url=_URL_BASE + 'video.html?src=crowd720_vp9.webm',
-      page_set=page_set,
-      tags=['vp9', 'video_only'])
-
-
-class Page36(SeekPage):
-
-  def __init__(self, page_set):
-    super(Page36, self).__init__(
-      url=(_URL_BASE + 'video.html?src='
-           'smpte_3840x2160_60fps_vp9.webm&seek'),
-      page_set=page_set,
-      tags=['is_4k', 'vp9', 'video_only'],
-      action_timeout_in_seconds=120)
-
-
-class Page37(BackgroundPlaybackPage):
-
-  def __init__(self, page_set):
-    super(Page37, self).__init__(
-      url=_URL_BASE + 'video.html?src=tulip2.vp9.webm&background',
-      page_set=page_set,
-      tags=['vp9', 'opus', 'audio_video'])
-
-
-class Page38(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page38, self).__init__(
-      url=_URL_BASE + 'video.html?src=tulip2.mp4&busyjs',
-      page_set=page_set,
-      tags=['h264', 'aac', 'audio_video', 'busyjs'])
-
-
-class Page39(MSEPage):
-
-  def __init__(self, page_set):
-    super(Page39, self).__init__(
-      url=_URL_BASE + 'mse.html?media=aac_audio.mp4,h264_video.mp4',
-      page_set=page_set,
-      tags=['h264', 'aac', 'audio_video'])
-
-
-class Page40(MSEPage):
-
-  def __init__(self, page_set):
-    super(Page40, self).__init__(
-      url=(_URL_BASE + 'mse.html?'
-           'media=aac_audio.mp4,h264_video.mp4&waitForPageLoaded=true'),
-      page_set=page_set,
-      tags=['h264', 'aac', 'audio_video'])
-
-
-class Page41(MSEPage):
-
-  def __init__(self, page_set):
-    super(Page41, self).__init__(
-      url=_URL_BASE + 'mse.html?media=aac_audio.mp4',
-      page_set=page_set,
-      tags=['aac', 'audio_only'])
-
-
-class Page42(MSEPage):
-
-  def __init__(self, page_set):
-    super(Page42, self).__init__(
-      url=_URL_BASE + 'mse.html?media=h264_video.mp4',
-      page_set=page_set,
-      tags=['h264', 'video_only'])
-
-
-class Page43(BeginningToEndPlayPage):
-
-  def __init__(self, page_set):
-    super(Page43, self).__init__(
-      url=_URL_BASE + 'video.html?src=tulip2.vp9.webm',
-      page_set=page_set,
-      tags=['vp9', 'opus', 'audio_video'],
-      traffic_setting=traffic_setting_module.REGULAR_3G)
-
-
 class MediaCasesStorySet(story.StorySet):
   """
   Description: Video Stack Perf pages that report time_to_play, seek time and
@@ -477,60 +208,132 @@
 
     self.measure_memory = measure_memory
 
-    # TODO(crouleau): Clean up this PageX stuff. Either
-    # 1. Add magic that will add all pages to the StorySet
-    # automatically so that the following is unnecessary. See
-    # https://stackoverflow.com/questions/1796180. Just add all classes with
-    # name like "PageX" where X is a number.
-    # or
-    # 2. Don't use classes at all and instead just have a list containing
-    # configuration for each one.
+    pages = [
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=crowd.ogg&type=audio',
+            page_set=self,
+            tags=['vorbis', 'audio_only']),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=crowd1080.webm',
+            page_set=self,
+            tags=['is_50fps', 'vp8', 'vorbis', 'audio_video']),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=tulip2.ogg&type=audio',
+            page_set=self,
+            tags=['vorbis', 'audio_only']),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=tulip2.wav&type=audio',
+            page_set=self,
+            tags=['pcm', 'audio_only']),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=crowd1080.mp4',
+            page_set=self,
+            tags=['is_50fps', 'h264', 'aac', 'audio_video']),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=crowd2160.mp4',
+            page_set=self,
+            tags=['is_4k', 'is_50fps', 'h264', 'aac', 'audio_video']),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=tulip2.mp3&type=audio',
+            page_set=self,
+            tags=['mp3', 'audio_only']),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=tulip2.mp4',
+            page_set=self,
+            tags=['h264', 'aac', 'audio_video']),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=tulip2.m4a&type=audio',
+            page_set=self,
+            tags=['aac', 'audio_only']),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=garden2_10s.webm',
+            page_set=self,
+            tags=['is_4k', 'vp8', 'vorbis', 'audio_video']),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=garden2_10s.mp4',
+            page_set=self,
+            tags=['is_4k', 'h264', 'aac', 'audio_video']),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=tulip2.vp9.webm',
+            page_set=self,
+            tags=['vp9', 'opus', 'audio_video'],
+            traffic_setting=traffic_setting_module.REGULAR_3G),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=tulip2.vp9.webm',
+            page_set=self,
+            tags=['vp9', 'opus', 'audio_video']),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=crowd1080_vp9.webm',
+            page_set=self,
+            tags=['vp9', 'video_only']),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=crowd720_vp9.webm',
+            page_set=self,
+            tags=['vp9', 'video_only']),
+        _BeginningToEndPlayPage(
+            url=_URL_BASE + 'video.html?src=tulip2.mp4&busyjs',
+            page_set=self,
+            tags=['h264', 'aac', 'audio_video', 'busyjs']),
+        _SeekPage(
+            url=_URL_BASE + 'video.html?src=tulip2.ogg&type=audio&seek',
+            page_set=self,
+            tags=['vorbis', 'audio_only']),
+        _SeekPage(
+            url=_URL_BASE + 'video.html?src=tulip2.wav&type=audio&seek',
+            page_set=self,
+            tags=['pcm', 'audio_only']),
+        _SeekPage(
+            url=_URL_BASE + 'video.html?src=tulip2.mp3&type=audio&seek',
+            page_set=self,
+            tags=['mp3', 'audio_only']),
+        _SeekPage(
+            url=_URL_BASE + 'video.html?src=tulip2.mp4&seek',
+            page_set=self,
+            tags=['h264', 'aac', 'audio_video']),
+        _SeekPage(
+            url=_URL_BASE + 'video.html?src=garden2_10s.webm&seek',
+            page_set=self,
+            tags=['is_4k', 'vp8', 'vorbis', 'audio_video']),
+        _SeekPage(
+            url=_URL_BASE + 'video.html?src=garden2_10s.mp4&seek',
+            page_set=self,
+            tags=['is_4k', 'h264', 'aac', 'audio_video']),
+        _SeekPage(
+            url=_URL_BASE + 'video.html?src=tulip2.vp9.webm&seek',
+            page_set=self,
+            tags=['vp9', 'opus', 'audio_video']),
+        _SeekPage(
+            url=_URL_BASE + 'video.html?src=crowd1080_vp9.webm&seek',
+            page_set=self,
+            tags=['vp9', 'video_only', 'seek']),
+        _SeekPage(
+            url=(_URL_BASE + 'video.html?src='
+                 'smpte_3840x2160_60fps_vp9.webm&seek'),
+            page_set=self,
+            tags=['is_4k', 'vp9', 'video_only'],
+            action_timeout_in_seconds=120),
+        _BackgroundPlaybackPage(
+            url=_URL_BASE + 'video.html?src=tulip2.vp9.webm&background',
+            page_set=self,
+            tags=['vp9', 'opus', 'audio_video']),
+        _MSEPage(
+            url=_URL_BASE + 'mse.html?media=aac_audio.mp4,h264_video.mp4',
+            page_set=self,
+            tags=['h264', 'aac', 'audio_video']),
+        _MSEPage(
+            url=(_URL_BASE + 'mse.html?'
+                 'media=aac_audio.mp4,h264_video.mp4&waitForPageLoaded=true'),
+            page_set=self,
+            tags=['h264', 'aac', 'audio_video']),
+        _MSEPage(
+            url=_URL_BASE + 'mse.html?media=aac_audio.mp4',
+            page_set=self,
+            tags=['aac', 'audio_only']),
+        _MSEPage(
+            url=_URL_BASE + 'mse.html?media=h264_video.mp4',
+            page_set=self,
+            tags=['h264', 'video_only']),
+    ]
 
-    # Normal play tests.
-    self.AddStory(Page2(self))
-    self.AddStory(Page4(self))
-    self.AddStory(Page7(self))
-    self.AddStory(Page8(self))
-    self.AddStory(Page11(self))
-    self.AddStory(Page12(self))
-    self.AddStory(Page13(self))
-    self.AddStory(Page14(self))
-    self.AddStory(Page15(self))
-    self.AddStory(Page16(self))
-    self.AddStory(Page17(self))
-    self.AddStory(Page30(self))
-    self.AddStory(Page32(self))
-    self.AddStory(Page34(self))
-
-    # Seek tests.
-    self.AddStory(Page19(self))
-    self.AddStory(Page20(self))
-    self.AddStory(Page23(self))
-    self.AddStory(Page24(self))
-    self.AddStory(Page25(self))
-    self.AddStory(Page26(self))
-    self.AddStory(Page31(self))
-    self.AddStory(Page33(self))
-    self.AddStory(Page36(self))
-
-    # Background playback tests.
-    self.AddStory(Page37(self))
-
-    # Tests with high JS load.
-    self.AddStory(Page38(self))
-
-    # Tests with a simulated constrained network connection.
-    self.AddStory(Page43(self))
-
-    # MSE tests.
-    # TODO(crouleau): Figure out a way to make MSE pages provide consistent
-    # data. Currently the data haa a lot of outliers for time_to_play and other
-    # startup metrics. To do this, we must either:
-    # 1. Tell Telemetry to repeat these pages (this requires Telemetry's
-    # providing this option in the API.)
-    # 2. Edit the page to reload and run multiple times (you can clear the cache
-    # with tab.CleanCache). This requires crbug/775264.
-    self.AddStory(Page39(self))
-    self.AddStory(Page40(self))
-    self.AddStory(Page41(self))
-    self.AddStory(Page42(self))
+    for page in pages:
+      self.AddStory(page)
diff --git a/ui/app_list/app_list_constants.cc b/ui/app_list/app_list_constants.cc
index 3ac054c2c..221c716 100644
--- a/ui/app_list/app_list_constants.cc
+++ b/ui/app_list/app_list_constants.cc
@@ -43,8 +43,7 @@
 const SkColor kResultDimmedTextColor = SkColorSetRGB(0x84, 0x84, 0x84);
 const SkColor kResultURLTextColor = SkColorSetRGB(0x00, 0x99, 0x33);
 
-const SkColor kGridTitleColor = SkColorSetRGB(0x33, 0x33, 0x33);
-const SkColor kGridTitleColorFullscreen = SK_ColorWHITE;
+const SkColor kGridTitleColor = SK_ColorWHITE;
 
 const int kGridTileWidth = 96;
 const int kGridTileHeight = 99;
@@ -57,16 +56,14 @@
 
 const SkColor kFolderTitleColor = SkColorSetRGB(0x33, 0x33, 0x33);
 const SkColor kFolderTitleHintTextColor = SkColorSetRGB(0xA0, 0xA0, 0xA0);
-// Color of the folder ink bubble.
-const SkColor kFolderBubbleColor = SK_ColorWHITE;
-// Color of folder bubble color (12% white) in full screen mode.
-const SkColor kFolderBubbleColorFullScreen =
-    SkColorSetARGB(0x1F, 0xFF, 0xFF, 0xFF);
+// Color of the folder ink bubble, 12% white..
+const SkColor kFolderBubbleColor = SkColorSetARGB(0x1F, 0xFF, 0xFF, 0xFF);
 // Color of the folder bubble shadow.
 const SkColor kFolderShadowColor = SkColorSetRGB(0xBF, 0xBF, 0xBF);
 const float kFolderBubbleOpacity = 0.12f;
 const float kFolderBubbleRadius = 23;
 const float kFolderBubbleOffsetY = 1;
+const int kFolderBackgroundBubbleRadius = 288;
 
 const SkColor kCardBackgroundColor = SK_ColorWHITE;
 const SkColor kCardBackgroundColorFullscreen = SkColorSetRGB(0xFA, 0xFA, 0xFC);
@@ -282,22 +279,20 @@
   return icon_shadows;
 }
 
-const gfx::FontList& FullscreenAppListAppTitleFont() {
-  // The max line height of app titles while the fullscreen launcher is enabled,
-  // which is determined by the sizes of app tile views, its paddings, and the
-  // icon.
-  constexpr int kFullscreenAppTitleMaxLineHeight = 16;
+const gfx::FontList& AppListAppTitleFont() {
+  // The max line height of app titles which is determined by the sizes of app
+  // tile views, its paddings, and the icon.
+  constexpr int kAppTitleMaxLineHeight = 16;
 
-  // The font for app titles while the fullscreen launcher is enabled. We're
-  // getting the largest font that doesn't exceed
-  // |kFullscreenAppTitleMaxLineHeight|.
-  // Note: we resize the font to 1px larger, otherwise it looks too small.
-  static const gfx::FontList kFullscreenAppListAppTitleFont =
+  // The font for app titles. We're getting the largest font that doesn't exceed
+  // |kAppTitleMaxLineHeight|.Note: we resize the font to 1px larger,
+  // otherwise it looks too small.
+  static const gfx::FontList kAppListAppTitleFont =
       ui::ResourceBundle::GetSharedInstance()
           .GetFontList(ui::ResourceBundle::LargeFont)
-          .DeriveWithHeightUpperBound(kFullscreenAppTitleMaxLineHeight)
+          .DeriveWithHeightUpperBound(kAppTitleMaxLineHeight)
           .DeriveWithSizeDelta(1);
-  return kFullscreenAppListAppTitleFont;
+  return kAppListAppTitleFont;
 }
 
 }  // namespace app_list
diff --git a/ui/app_list/app_list_constants.h b/ui/app_list/app_list_constants.h
index 4d4717bd0..d2a401f8 100644
--- a/ui/app_list/app_list_constants.h
+++ b/ui/app_list/app_list_constants.h
@@ -42,7 +42,6 @@
 APP_LIST_EXPORT extern const SkColor kResultURLTextColor;
 
 APP_LIST_EXPORT extern const SkColor kGridTitleColor;
-APP_LIST_EXPORT extern const SkColor kGridTitleColorFullscreen;
 
 APP_LIST_EXPORT extern const int kGridTileWidth;
 APP_LIST_EXPORT extern const int kGridTileHeight;
@@ -56,12 +55,13 @@
 APP_LIST_EXPORT extern const SkColor kFolderTitleColor;
 APP_LIST_EXPORT extern const SkColor kFolderTitleHintTextColor;
 APP_LIST_EXPORT extern const SkColor kFolderBubbleColor;
-APP_LIST_EXPORT extern const SkColor kFolderBubbleColorFullScreen;
 APP_LIST_EXPORT extern const SkColor kFolderShadowColor;
 APP_LIST_EXPORT extern const float kFolderBubbleOpacity;
 APP_LIST_EXPORT extern const float kFolderBubbleRadius;
 APP_LIST_EXPORT extern const float kFolderBubbleOffsetY;
 
+APP_LIST_EXPORT extern const int kFolderBackgroundBubbleRadius;
+
 APP_LIST_EXPORT extern const SkColor kCardBackgroundColor;
 APP_LIST_EXPORT extern const SkColor kCardBackgroundColorFullscreen;
 
@@ -213,7 +213,7 @@
 APP_LIST_EXPORT const gfx::ShadowValues& IconStartShadows();
 APP_LIST_EXPORT const gfx::ShadowValues& IconEndShadows();
 
-APP_LIST_EXPORT const gfx::FontList& FullscreenAppListAppTitleFont();
+APP_LIST_EXPORT const gfx::FontList& AppListAppTitleFont();
 
 }  // namespace app_list
 
diff --git a/ui/app_list/folder_image.cc b/ui/app_list/folder_image.cc
index e83cdd5..662ee44 100644
--- a/ui/app_list/folder_image.cc
+++ b/ui/app_list/folder_image.cc
@@ -86,7 +86,7 @@
   bubble_center.Offset(0, -kFolderBubbleOffsetY);
   flags.setStyle(cc::PaintFlags::kFill_Style);
   flags.setAntiAlias(true);
-  flags.setColor(FolderImage::GetFolderBubbleSkColor());
+  flags.setColor(kFolderBubbleColor);
   canvas->DrawCircle(bubble_center, kFolderBubbleRadius, flags);
 
   if (icons_.size() == 0)
@@ -166,12 +166,6 @@
   return top_icon_bounds;
 }
 
-// static
-SkColor FolderImage::GetFolderBubbleSkColor() {
-  return features::IsFullscreenAppListEnabled() ? kFolderBubbleColorFullScreen
-                                                : kFolderBubbleColor;
-}
-
 gfx::Rect FolderImage::GetTargetIconRectInFolderForItem(
     AppListItem* item,
     const gfx::Rect& folder_icon_bounds) const {
diff --git a/ui/app_list/folder_image.h b/ui/app_list/folder_image.h
index 26ac6488..0cbd124 100644
--- a/ui/app_list/folder_image.h
+++ b/ui/app_list/folder_image.h
@@ -57,8 +57,6 @@
   static std::vector<gfx::Rect> GetTopIconsBounds(
       const gfx::Rect& folder_icon_bounds);
 
-  static SkColor GetFolderBubbleSkColor();
-
   // Returns the target icon bounds for |item| to fly back to its parent folder
   // icon in animation UI. If |item| is one of the top item icon, this will
   // match its corresponding top item icon in the folder icon. Otherwise,
diff --git a/ui/app_list/views/all_apps_tile_item_view.cc b/ui/app_list/views/all_apps_tile_item_view.cc
index f26e155..3adc034 100644
--- a/ui/app_list/views/all_apps_tile_item_view.cc
+++ b/ui/app_list/views/all_apps_tile_item_view.cc
@@ -9,7 +9,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_features.h"
 #include "ui/app_list/resources/grit/app_list_resources.h"
 #include "ui/app_list/views/app_list_view.h"
 #include "ui/app_list/views/contents_view.h"
@@ -70,8 +69,7 @@
                             AppListModel::STATE_LAST);
 
   contents_view_->SetActiveState(AppListModel::STATE_APPS);
-  if (features::IsFullscreenAppListEnabled())
-    app_list_view_->SetState(AppListView::FULLSCREEN_ALL_APPS);
+  app_list_view_->SetState(AppListView::FULLSCREEN_ALL_APPS);
 }
 
 }  // namespace app_list
diff --git a/ui/app_list/views/app_list_folder_view.cc b/ui/app_list/views/app_list_folder_view.cc
index 42e2c4e6..577b0e5b 100644
--- a/ui/app_list/views/app_list_folder_view.cc
+++ b/ui/app_list/views/app_list_folder_view.cc
@@ -56,7 +56,6 @@
       model_(model),
       folder_item_(NULL),
       hide_for_reparent_(false),
-      is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()),
       is_app_list_focus_enabled_(features::IsAppListFocusEnabled()) {
   AddChildView(folder_header_view_);
   view_model_->Add(folder_header_view_, kIndexFolderHeader);
@@ -111,8 +110,8 @@
   UpdateFolderNameVisibility(true);
 
   ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator());
-  animation.SetTweenType(
-      show ? kFolderFadeInTweenType : kFolderFadeOutTweenType);
+  animation.SetTweenType(show ? kFolderFadeInTweenType
+                              : kFolderFadeOutTweenType);
   animation.AddObserver(this);
   animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
       show ? kFolderTransitionInDurationMs : kFolderTransitionOutDurationMs));
@@ -122,14 +121,8 @@
 }
 
 gfx::Size AppListFolderView::CalculatePreferredSize() const {
-  if (is_fullscreen_app_list_enabled_)
-    return gfx::Size(kAppsFolderPreferredWidth, kAppsFolderPreferredHeight);
-
-  const gfx::Size header_size = folder_header_view_->GetPreferredSize();
-  const gfx::Size grid_size = items_grid_view_->GetPreferredSize();
-  int width = std::max(header_size.width(), grid_size.width());
-  int height = header_size.height() + grid_size.height();
-  return gfx::Size(width, height);
+  gfx::Size size(kAppsFolderPreferredWidth, kAppsFolderPreferredHeight);
+  return size;
 }
 
 void AppListFolderView::Layout() {
@@ -221,15 +214,13 @@
   // root level grid view.
   gfx::RectF rect_f(original_drag_view->bounds());
   views::View::ConvertRectToTarget(items_grid_view_,
-                                   container_view_->apps_grid_view(),
-                                   &rect_f);
+                                   container_view_->apps_grid_view(), &rect_f);
   gfx::Rect rect_in_root_grid_view = gfx::ToEnclosingRect(rect_f);
 
   container_view_->apps_grid_view()
-      ->InitiateDragFromReparentItemInRootLevelGridView(original_drag_view,
-                                                        rect_in_root_grid_view,
-                                                        drag_point_in_root_grid,
-                                                        has_native_drag);
+      ->InitiateDragFromReparentItemInRootLevelGridView(
+          original_drag_view, rect_in_root_grid_view, drag_point_in_root_grid,
+          has_native_drag);
 }
 
 gfx::Rect AppListFolderView::GetItemIconBoundsAt(int index) {
@@ -256,8 +247,8 @@
     UpdateFolderNameVisibility(false);
 
   container_view_->folder_background_view()->UpdateFolderContainerBubble(
-      show_bubble ? FolderBackgroundView::SHOW_BUBBLE :
-                    FolderBackgroundView::HIDE_BUBBLE);
+      show_bubble ? FolderBackgroundView::SHOW_BUBBLE
+                  : FolderBackgroundView::HIDE_BUBBLE);
 }
 
 void AppListFolderView::UpdateFolderNameVisibility(bool visible) {
@@ -275,8 +266,8 @@
 
   gfx::Point center = GetLocalBounds().CenterPoint();
   float delta = (point - center).Length();
-  return delta > container_view_->folder_background_view()->
-      GetFolderContainerBubbleRadius() + kOutOfFolderContainerBubbleDelta;
+  return delta >
+         kFolderBackgroundBubbleRadius + kOutOfFolderContainerBubbleDelta;
 }
 
 // When user drags a folder item out of the folder boundary ink bubble, the
@@ -296,11 +287,10 @@
     bool has_native_drag) {
   // Convert the drag point relative to the root level AppsGridView.
   gfx::Point to_root_level_grid = drag_point_in_folder_grid;
-  ConvertPointToTarget(items_grid_view_,
-                       container_view_->apps_grid_view(),
+  ConvertPointToTarget(items_grid_view_, container_view_->apps_grid_view(),
                        &to_root_level_grid);
-  StartSetupDragInRootLevelAppsGridView(
-      original_drag_view, to_root_level_grid, has_native_drag);
+  StartSetupDragInRootLevelAppsGridView(original_drag_view, to_root_level_grid,
+                                        has_native_drag);
   container_view_->ReparentFolderItemTransit(folder_item_);
 }
 
diff --git a/ui/app_list/views/app_list_folder_view.h b/ui/app_list/views/app_list_folder_view.h
index e923d31..95346cbf 100644
--- a/ui/app_list/views/app_list_folder_view.h
+++ b/ui/app_list/views/app_list_folder_view.h
@@ -108,22 +108,20 @@
   bool IsOEMFolder() const override;
   void SetRootLevelDragViewVisible(bool visible) override;
 
-  AppsContainerView* container_view_;  // Not owned.
+  AppsContainerView* container_view_;     // Not owned.
   AppListMainView* app_list_main_view_;   // Not Owned.
   FolderHeaderView* folder_header_view_;  // Owned by views hierarchy.
-  AppsGridView* items_grid_view_;  // Owned by the views hierarchy.
+  AppsGridView* items_grid_view_;         // Owned by the views hierarchy.
 
   std::unique_ptr<views::ViewModel> view_model_;
 
-  AppListModel* model_;  // Not owned.
+  AppListModel* model_;             // Not owned.
   AppListFolderItem* folder_item_;  // Not owned.
 
   bool hide_for_reparent_;
 
   base::string16 accessible_name_;
 
-  const bool is_fullscreen_app_list_enabled_;
-
   // Whether the app list focus is enabled.
   const bool is_app_list_focus_enabled_;
 
diff --git a/ui/app_list/views/app_list_item_view.cc b/ui/app_list/views/app_list_item_view.cc
index 4c020d41..fdce98e 100644
--- a/ui/app_list/views/app_list_item_view.cc
+++ b/ui/app_list/views/app_list_item_view.cc
@@ -39,14 +39,9 @@
 
 namespace {
 
-constexpr int kTopPadding = 18;
-constexpr int kIconTitleSpacing = 6;
-
 // Radius of the folder dropping preview circle.
 constexpr int kFolderPreviewRadius = 40;
 
-constexpr int kLeftRightPaddingChars = 1;
-
 // Delay in milliseconds of when the dragging UI should be shown for mouse drag.
 constexpr int kMouseDragUIDelayInMs = 200;
 
@@ -56,11 +51,6 @@
 // 650ms.
 constexpr int kTouchLongpressDelayInMs = 300;
 
-gfx::FontList GetFontList() {
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  return rb.GetFontList(kItemTextFontStyle);
-}
-
 }  // namespace
 
 // static
@@ -75,16 +65,9 @@
       apps_grid_view_(apps_grid_view),
       icon_(new views::ImageView),
       title_(new views::Label),
-      progress_bar_(new views::ProgressBar),
-      is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) {
+      progress_bar_(new views::ProgressBar) {
   if (features::IsAppListFocusEnabled())
     SetFocusBehavior(FocusBehavior::ALWAYS);
-  if (!is_fullscreen_app_list_enabled_) {
-    shadow_animator_.reset(new ImageShadowAnimator(this));
-    shadow_animator_->animation()->SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
-    shadow_animator_->SetStartAndEndShadows(IconStartShadows(),
-                                            IconEndShadows());
-  }
 
   icon_->set_can_process_events_within_subtree(false);
   icon_->SetVerticalAlignment(views::ImageView::LEADING);
@@ -92,19 +75,12 @@
   title_->SetBackgroundColor(SK_ColorTRANSPARENT);
   title_->SetAutoColorReadabilityEnabled(false);
   title_->SetHandlesTooltips(false);
+  const gfx::FontList& font = AppListAppTitleFont();
+  title_->SetFontList(font);
+  title_->SetLineHeight(font.GetHeight());
+  title_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
+  title_->SetEnabledColor(kGridTitleColor);
 
-  if (is_fullscreen_app_list_enabled_) {
-    const gfx::FontList& font = FullscreenAppListAppTitleFont();
-    title_->SetFontList(font);
-    title_->SetLineHeight(font.GetHeight());
-    title_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
-    title_->SetEnabledColor(kGridTitleColorFullscreen);
-  } else {
-    const gfx::FontList& font_list = GetFontList();
-    title_->SetFontList(font_list);
-    title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-    title_->SetEnabledColor(kGridTitleColor);
-  }
   SetTitleSubpixelAA();
 
   AddChildView(icon_);
@@ -136,8 +112,7 @@
   }
 
   gfx::ImageSkia resized(gfx::ImageSkiaOperations::CreateResizedImage(
-      icon,
-      skia::ImageOperations::RESIZE_BEST,
+      icon, skia::ImageOperations::RESIZE_BEST,
       gfx::Size(kGridIconDimension, kGridIconDimension)));
   if (shadow_animator_)
     shadow_animator_->SetOriginalImage(resized);
@@ -343,17 +318,13 @@
 
   gfx::Rect rect(GetContentsBounds());
   if (apps_grid_view_->IsSelectedView(this)) {
-    if (is_fullscreen_app_list_enabled_) {
-      rect.Inset((rect.width() - kGridSelectedSize) / 2,
-                 (rect.height() - kGridSelectedSize) / 2);
-      cc::PaintFlags flags;
-      flags.setAntiAlias(true);
-      flags.setColor(kGridSelectedColor);
-      flags.setStyle(cc::PaintFlags::kFill_Style);
-      canvas->DrawRoundRect(gfx::RectF(rect), kGridSelectedCornerRadius, flags);
-    } else {
-      canvas->FillRect(GetContentsBounds(), kSelectedColor);
-    }
+    rect.Inset((rect.width() - kGridSelectedSize) / 2,
+               (rect.height() - kGridSelectedSize) / 2);
+    cc::PaintFlags flags;
+    flags.setAntiAlias(true);
+    flags.setColor(kGridSelectedColor);
+    flags.setStyle(cc::PaintFlags::kFill_Style);
+    canvas->DrawRoundRect(gfx::RectF(rect), kGridSelectedCornerRadius, flags);
   }
 
   if (ui_state_ == UI_STATE_DROPPING_IN_FOLDER) {
@@ -365,7 +336,7 @@
     cc::PaintFlags flags;
     flags.setStyle(cc::PaintFlags::kFill_Style);
     flags.setAntiAlias(true);
-    flags.setColor(FolderImage::GetFolderBubbleSkColor());
+    flags.setColor(kFolderBubbleColor);
     canvas->DrawCircle(center, kFolderPreviewRadius, flags);
   }
 }
@@ -380,8 +351,8 @@
                                 event.root_location());
 
   if (apps_grid_view_->IsDraggedView(this)) {
-    mouse_drag_timer_.Start(FROM_HERE,
-        base::TimeDelta::FromMilliseconds(kMouseDragUIDelayInMs),
+    mouse_drag_timer_.Start(
+        FROM_HERE, base::TimeDelta::FromMilliseconds(kMouseDragUIDelayInMs),
         this, &AppListItemView::OnMouseDragTimer);
   }
   return true;
@@ -396,51 +367,25 @@
   if (rect.IsEmpty())
     return;
 
-  if (is_fullscreen_app_list_enabled_) {
-    icon_->SetBoundsRect(GetIconBoundsForTargetViewBounds(GetContentsBounds()));
+  icon_->SetBoundsRect(GetIconBoundsForTargetViewBounds(GetContentsBounds()));
 
-    rect.Inset(kGridTitleHorizontalPadding,
-               kGridIconTopPadding + kGridIconDimension + kGridTitleSpacing,
-               kGridTitleHorizontalPadding, 0);
-    rect.set_height(title_->GetPreferredSize().height());
-    title_->SetBoundsRect(rect);
-    SetTitleSubpixelAA();
+  rect.Inset(kGridTitleHorizontalPadding,
+             kGridIconTopPadding + kGridIconDimension + kGridTitleSpacing,
+             kGridTitleHorizontalPadding, 0);
+  rect.set_height(title_->GetPreferredSize().height());
+  title_->SetBoundsRect(rect);
+  SetTitleSubpixelAA();
 
-    gfx::Rect progress_bar_bounds(progress_bar_->GetPreferredSize());
-    progress_bar_bounds.set_x(
-        (GetContentsBounds().width() - progress_bar_bounds.width()) / 2);
-    progress_bar_bounds.set_y(rect.y());
-    progress_bar_->SetBoundsRect(progress_bar_bounds);
-  } else {
-    icon_->SetBoundsRect(GetIconBoundsForTargetViewBounds(GetContentsBounds()));
-
-    const int left_right_padding =
-        title_->font_list().GetExpectedTextWidth(kLeftRightPaddingChars);
-    rect.Inset(left_right_padding, kTopPadding, left_right_padding, 0);
-    const int y = rect.y();
-
-    const gfx::Size title_size = title_->GetPreferredSize();
-    gfx::Rect title_bounds(rect.x() + (rect.width() - title_size.width()) / 2,
-                           y + kGridIconDimension + kIconTitleSpacing,
-                           title_size.width(), title_size.height());
-    title_bounds.Intersect(rect);
-    title_->SetBoundsRect(title_bounds);
-    SetTitleSubpixelAA();
-
-    gfx::Rect progress_bar_bounds(progress_bar_->GetPreferredSize());
-    progress_bar_bounds.set_x(
-        (GetContentsBounds().width() - progress_bar_bounds.width()) / 2);
-    progress_bar_bounds.set_y(title_bounds.y());
-    progress_bar_->SetBoundsRect(progress_bar_bounds);
-  }
+  gfx::Rect progress_bar_bounds(progress_bar_->GetPreferredSize());
+  progress_bar_bounds.set_x(
+      (GetContentsBounds().width() - progress_bar_bounds.width()) / 2);
+  progress_bar_bounds.set_y(rect.y());
+  progress_bar_->SetBoundsRect(progress_bar_bounds);
 }
 
 gfx::Size AppListItemView::CalculatePreferredSize() const {
-  if (is_fullscreen_app_list_enabled_) {
-    return gfx::Size(kGridTileWidth, kGridTileHeight);
-  }
-
-  return views::View::CalculatePreferredSize();
+  gfx::Size size = gfx::Size(kGridTileWidth, kGridTileHeight);
+  return size;
 }
 
 bool AppListItemView::OnKeyPressed(const ui::KeyEvent& event) {
@@ -475,8 +420,7 @@
     apps_grid_view_->ClearAnySelectedView();
 
   // Show dragging UI when it's confirmed without waiting for the timer.
-  if (ui_state_ != UI_STATE_DRAGGING &&
-      apps_grid_view_->dragging() &&
+  if (ui_state_ != UI_STATE_DRAGGING && apps_grid_view_->dragging() &&
       apps_grid_view_->IsDraggedView(this)) {
     mouse_drag_timer_.Stop();
     SetUIState(UI_STATE_DRAGGING);
@@ -589,9 +533,7 @@
 gfx::Rect AppListItemView::GetIconBoundsForTargetViewBounds(
     const gfx::Rect& target_bounds) {
   gfx::Rect rect(target_bounds);
-  rect.Inset(
-      0, is_fullscreen_app_list_enabled_ ? kGridIconTopPadding : kTopPadding, 0,
-      0);
+  rect.Inset(0, kGridIconTopPadding, 0, 0);
   rect.set_height(icon_->GetImage().height());
   rect.ClampToCenteredSize(icon_->GetImage().size());
   return rect;
diff --git a/ui/app_list/views/app_list_item_view.h b/ui/app_list/views/app_list_item_view.h
index d3f38295..0ad68c6 100644
--- a/ui/app_list/views/app_list_item_view.h
+++ b/ui/app_list/views/app_list_item_view.h
@@ -180,8 +180,6 @@
   bool is_installing_ = false;
   bool is_highlighted_ = false;
 
-  const bool is_fullscreen_app_list_enabled_;
-
   base::string16 tooltip_text_;
 
   // A timer to defer showing drag UI when mouse is pressed.
diff --git a/ui/app_list/views/folder_background_view.cc b/ui/app_list/views/folder_background_view.cc
index f27854f..e9cfe74 100644
--- a/ui/app_list/views/folder_background_view.cc
+++ b/ui/app_list/views/folder_background_view.cc
@@ -20,7 +20,6 @@
 
 const float kFolderInkBubbleScale = 1.2f;
 const int kBubbleTransitionDurationMs = 200;
-const int kBubbleRadiusFullScreen = 288;
 
 }  // namespace
 
@@ -72,14 +71,6 @@
   SchedulePaint();
 }
 
-int FolderBackgroundView::GetFolderContainerBubbleRadius() const {
-  return is_fullscreen_app_list_enabled_
-             ? kBubbleRadiusFullScreen
-             : std::max(GetContentsBounds().width(),
-                        GetContentsBounds().height()) /
-                   2;
-}
-
 void FolderBackgroundView::OnPaint(gfx::Canvas* canvas) {
   if (show_state_ == NO_BUBBLE)
     return;
@@ -90,7 +81,7 @@
   flags.setAntiAlias(true);
   flags.setColor(kFolderBubbleColor);
   canvas->DrawCircle(GetContentsBounds().CenterPoint(),
-                     GetFolderContainerBubbleRadius(), flags);
+                     kFolderBackgroundBubbleRadius, flags);
 }
 
 void FolderBackgroundView::OnImplicitAnimationsCompleted() {
diff --git a/ui/app_list/views/folder_background_view.h b/ui/app_list/views/folder_background_view.h
index 338f86c..c1a3cae 100644
--- a/ui/app_list/views/folder_background_view.h
+++ b/ui/app_list/views/folder_background_view.h
@@ -30,9 +30,6 @@
   // Updates the ink bubble's ShowState.
   void UpdateFolderContainerBubble(ShowState state);
 
-  // Returns the radius of the folder container ink bubble.
-  int GetFolderContainerBubbleRadius() const;
-
   void set_folder_view(AppListFolderView* folder_view) {
     folder_view_ = folder_view;
   }
diff --git a/ui/app_list/views/folder_header_view.cc b/ui/app_list/views/folder_header_view.cc
index d298c26..08e8b8f 100644
--- a/ui/app_list/views/folder_header_view.cc
+++ b/ui/app_list/views/folder_header_view.cc
@@ -64,7 +64,7 @@
     // Make folder name font size 14px.
     folder_name_view_->SetFontList(font_list.DeriveWithSizeDelta(-1));
     folder_name_view_->SetBackgroundColor(SK_ColorTRANSPARENT);
-    folder_name_view_->SetTextColor(kGridTitleColorFullscreen);
+    folder_name_view_->SetTextColor(kGridTitleColor);
   } else {
     folder_name_view_->SetFontList(font_list);
     folder_name_view_->SetBackgroundColor(kContentsBackgroundColor);
diff --git a/ui/app_list/views/search_result_tile_item_view.cc b/ui/app_list/views/search_result_tile_item_view.cc
index 67eab22..e1f2c10 100644
--- a/ui/app_list/views/search_result_tile_item_view.cc
+++ b/ui/app_list/views/search_result_tile_item_view.cc
@@ -63,7 +63,7 @@
   SetVisible(false);
 
   if (is_play_store_search_enabled) {
-    const gfx::FontList& font = FullscreenAppListAppTitleFont();
+    const gfx::FontList& font = AppListAppTitleFont();
     rating_ = new views::Label;
     rating_->SetEnabledColor(kSearchAppRatingColor);
     rating_->SetFontList(font);
@@ -120,13 +120,13 @@
   SetPrice(item_->formatted_price());
 
   if (is_fullscreen_app_list_enabled_) {
-    const gfx::FontList& font = FullscreenAppListAppTitleFont();
+    const gfx::FontList& font = AppListAppTitleFont();
     if (item_->display_type() == SearchResult::DISPLAY_RECOMMENDATION) {
       set_is_recommendation(true);
 
       title()->SetFontList(font);
       title()->SetLineHeight(font.GetHeight());
-      title()->SetEnabledColor(kGridTitleColorFullscreen);
+      title()->SetEnabledColor(kGridTitleColor);
     } else if (item_->display_type() == SearchResult::DISPLAY_TILE) {
       // Set solid color background to avoid broken text. See crbug.com/746563.
       if (rating_) {
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index 620c6236..d712c39 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -1129,7 +1129,6 @@
   if (bounds == bounds_)
     return;
 
-  base::Closure closure;
   const gfx::Rect old_bounds = bounds_;
   bounds_ = bounds;
 
diff --git a/ui/events/ozone/BUILD.gn b/ui/events/ozone/BUILD.gn
index 9e5753b..613d448c 100644
--- a/ui/events/ozone/BUILD.gn
+++ b/ui/events/ozone/BUILD.gn
@@ -99,8 +99,6 @@
       "evdev/keyboard_util_evdev.h",
       "evdev/mouse_button_map_evdev.cc",
       "evdev/mouse_button_map_evdev.h",
-      "evdev/scoped_input_device.cc",
-      "evdev/scoped_input_device.h",
       "evdev/tablet_event_converter_evdev.cc",
       "evdev/tablet_event_converter_evdev.h",
       "evdev/touch_evdev_debug_buffer.cc",
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl.cc b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
index dec09f7..161065a 100644
--- a/ui/events/ozone/evdev/event_converter_evdev_impl.cc
+++ b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
@@ -15,7 +15,6 @@
 #include "ui/events/keycodes/dom/keycode_converter.h"
 #include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
 #include "ui/events/ozone/evdev/keyboard_util_evdev.h"
-#include "ui/events/ozone/evdev/scoped_input_device.h"
 
 namespace ui {
 
@@ -31,7 +30,7 @@
 }  // namespace
 
 EventConverterEvdevImpl::EventConverterEvdevImpl(
-    ScopedInputDevice fd,
+    base::ScopedFD fd,
     base::FilePath path,
     int id,
     const EventDeviceInfo& devinfo,
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl.h b/ui/events/ozone/evdev/event_converter_evdev_impl.h
index 778359cd..c2b5f8e4 100644
--- a/ui/events/ozone/evdev/event_converter_evdev_impl.h
+++ b/ui/events/ozone/evdev/event_converter_evdev_impl.h
@@ -8,6 +8,7 @@
 #include <bitset>
 
 #include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "base/message_loop/message_pump_libevent.h"
 #include "ui/events/devices/input_device.h"
@@ -19,7 +20,6 @@
 #include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
 #include "ui/events/ozone/evdev/keyboard_evdev.h"
 #include "ui/events/ozone/evdev/mouse_button_map_evdev.h"
-#include "ui/events/ozone/evdev/scoped_input_device.h"
 
 struct input_event;
 
@@ -30,7 +30,7 @@
 class EVENTS_OZONE_EVDEV_EXPORT EventConverterEvdevImpl
     : public EventConverterEvdev {
  public:
-  EventConverterEvdevImpl(ScopedInputDevice fd,
+  EventConverterEvdevImpl(base::ScopedFD fd,
                           base::FilePath path,
                           int id,
                           const EventDeviceInfo& info,
@@ -66,7 +66,7 @@
   void FlushEvents(const input_event& input);
 
   // Input device file descriptor.
-  ScopedInputDevice input_device_fd_;
+  base::ScopedFD input_device_fd_;
 
   // Input modalities for this device.
   bool has_keyboard_;
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc b/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc
index 5eafa38..3b4c867a 100644
--- a/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc
+++ b/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -21,7 +22,6 @@
 #include "ui/events/ozone/evdev/event_converter_test_util.h"
 #include "ui/events/ozone/evdev/event_factory_evdev.h"
 #include "ui/events/ozone/evdev/keyboard_evdev.h"
-#include "ui/events/ozone/evdev/scoped_input_device.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
 
 namespace ui {
@@ -30,7 +30,7 @@
 
 class MockEventConverterEvdevImpl : public EventConverterEvdevImpl {
  public:
-  MockEventConverterEvdevImpl(ScopedInputDevice fd,
+  MockEventConverterEvdevImpl(base::ScopedFD fd,
                               CursorDelegateEvdev* cursor,
                               DeviceEventDispatcherEvdev* dispatcher)
       : EventConverterEvdevImpl(std::move(fd),
@@ -94,7 +94,7 @@
     int evdev_io[2];
     if (pipe(evdev_io))
       PLOG(FATAL) << "failed pipe";
-    ui::ScopedInputDevice events_in(evdev_io[0]);
+    base::ScopedFD events_in(evdev_io[0]);
     events_out_.reset(evdev_io[1]);
 
     cursor_.reset(new ui::MockCursorEvdev());
@@ -160,7 +160,7 @@
 
   std::vector<std::unique_ptr<ui::Event>> dispatched_events_;
 
-  ui::ScopedInputDevice events_out_;
+  base::ScopedFD events_out_;
 
   DISALLOW_COPY_AND_ASSIGN(EventConverterEvdevImplTest);
 };
diff --git a/ui/events/ozone/evdev/gamepad_event_converter_evdev.cc b/ui/events/ozone/evdev/gamepad_event_converter_evdev.cc
index 1af45d07..c171487 100644
--- a/ui/events/ozone/evdev/gamepad_event_converter_evdev.cc
+++ b/ui/events/ozone/evdev/gamepad_event_converter_evdev.cc
@@ -11,7 +11,6 @@
 #include "base/trace_event/trace_event.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
-#include "ui/events/ozone/evdev/scoped_input_device.h"
 #include "ui/events/ozone/gamepad/gamepad_event.h"
 #include "ui/events/ozone/gamepad/gamepad_provider_ozone.h"
 #include "ui/events/ozone/gamepad/webgamepad_constants.h"
@@ -90,7 +89,7 @@
 }
 
 GamepadEventConverterEvdev::GamepadEventConverterEvdev(
-    ScopedInputDevice fd,
+    base::ScopedFD fd,
     base::FilePath path,
     int id,
     const EventDeviceInfo& devinfo,
diff --git a/ui/events/ozone/evdev/gamepad_event_converter_evdev.h b/ui/events/ozone/evdev/gamepad_event_converter_evdev.h
index cb10ab6..94cf258 100644
--- a/ui/events/ozone/evdev/gamepad_event_converter_evdev.h
+++ b/ui/events/ozone/evdev/gamepad_event_converter_evdev.h
@@ -8,13 +8,13 @@
 #include <vector>
 
 #include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "ui/events/devices/input_device.h"
 #include "ui/events/event.h"
 #include "ui/events/ozone/evdev/event_converter_evdev.h"
 #include "ui/events/ozone/evdev/event_device_info.h"
 #include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
-#include "ui/events/ozone/evdev/scoped_input_device.h"
 #include "ui/events/ozone/gamepad/gamepad_mapping.h"
 #include "ui/events/ozone/gamepad/webgamepad_constants.h"
 
@@ -27,7 +27,7 @@
 class EVENTS_OZONE_EVDEV_EXPORT GamepadEventConverterEvdev
     : public EventConverterEvdev {
  public:
-  GamepadEventConverterEvdev(ScopedInputDevice fd,
+  GamepadEventConverterEvdev(base::ScopedFD fd,
                              base::FilePath path,
                              int id,
                              const EventDeviceInfo& info,
@@ -110,7 +110,7 @@
   std::unique_ptr<GamepadMapper> mapper_;
 
   // Input device file descriptor.
-  ScopedInputDevice input_device_fd_;
+  base::ScopedFD input_device_fd_;
 
   // Callbacks for dispatching events.
   DeviceEventDispatcherEvdev* dispatcher_;
diff --git a/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc b/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc
index a5cabb33..94401e9 100644
--- a/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc
+++ b/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc
@@ -16,6 +16,7 @@
 
 #include "base/bind.h"
 #include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/posix/eintr_wrapper.h"
@@ -75,19 +76,19 @@
         ui::CreateDeviceEventDispatcherEvdevForTest(event_factory_.get());
   }
 
-  ui::GamepadEventConverterEvdev* CreateDevice(
+  std::unique_ptr<ui::GamepadEventConverterEvdev> CreateDevice(
       const ui::DeviceCapabilities& caps) {
     int evdev_io[2];
     if (pipe(evdev_io))
       PLOG(FATAL) << "failed pipe";
-    ui::ScopedInputDevice events_in(evdev_io[0]);
-    ui::ScopedInputDevice events_out(evdev_io[1]);
+    base::ScopedFD events_in(evdev_io[0]);
+    base::ScopedFD events_out(evdev_io[1]);
 
     ui::EventDeviceInfo devinfo;
     CapabilitiesToDeviceInfo(caps, &devinfo);
-    return new ui::GamepadEventConverterEvdev(std::move(events_in),
-                                              base::FilePath(kTestDevicePath),
-                                              1, devinfo, dispatcher_.get());
+    return std::make_unique<ui::GamepadEventConverterEvdev>(
+        std::move(events_in), base::FilePath(kTestDevicePath), 1, devinfo,
+        dispatcher_.get());
   }
 
  private:
@@ -113,7 +114,7 @@
 TEST_F(GamepadEventConverterEvdevTest, XboxGamepadEvents) {
   TestGamepadObserver observer;
   std::unique_ptr<ui::GamepadEventConverterEvdev> dev =
-      base::WrapUnique(CreateDevice(kXboxGamepad));
+      CreateDevice(kXboxGamepad);
 
   struct input_event mock_kernel_queue[] = {
       {{1493076826, 766851}, EV_ABS, 0, 19105},
@@ -178,7 +179,7 @@
 TEST_F(GamepadEventConverterEvdevTest, iBuffaloGamepadEvents) {
   TestGamepadObserver observer;
   std::unique_ptr<ui::GamepadEventConverterEvdev> dev =
-      base::WrapUnique(CreateDevice(kiBuffaloGamepad));
+      CreateDevice(kiBuffaloGamepad);
 
   struct input_event mock_kernel_queue[] = {
       {{1493141044, 176725}, EV_MSC, 4, 90002},
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.cc b/ui/events/ozone/evdev/input_device_factory_evdev.cc
index f442daa..07c321c 100644
--- a/ui/events/ozone/evdev/input_device_factory_evdev.cc
+++ b/ui/events/ozone/evdev/input_device_factory_evdev.cc
@@ -10,6 +10,7 @@
 
 #include <utility>
 
+#include "base/files/scoped_file.h"
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -83,7 +84,7 @@
 
 std::unique_ptr<EventConverterEvdev> CreateConverter(
     const OpenInputDeviceParams& params,
-    ScopedInputDevice fd,
+    base::ScopedFD fd,
     const EventDeviceInfo& devinfo) {
 #if defined(USE_EVDEV_GESTURES)
   // Touchpad or mouse: use gestures library.
@@ -109,10 +110,11 @@
   }
 
   // Graphics tablet
-  if (devinfo.HasTablet())
+  if (devinfo.HasTablet()) {
     return base::WrapUnique<EventConverterEvdev>(new TabletEventConverterEvdev(
         std::move(fd), params.path, params.id, params.cursor, devinfo,
         params.dispatcher));
+  }
 
   if (devinfo.HasGamepad()) {
     return base::WrapUnique<EventConverterEvdev>(new GamepadEventConverterEvdev(
@@ -131,7 +133,7 @@
   const base::FilePath& path = params.path;
   TRACE_EVENT1("evdev", "OpenInputDevice", "path", path.value());
 
-  ScopedInputDevice fd(open(path.value().c_str(), O_RDWR | O_NONBLOCK));
+  base::ScopedFD fd(open(path.value().c_str(), O_RDWR | O_NONBLOCK));
   if (fd.get() < 0) {
     PLOG(ERROR) << "Cannot open " << path.value();
     return nullptr;
@@ -321,11 +323,16 @@
 
   for (const auto& it : converters_) {
     EventConverterEvdev* converter = it.second.get();
-    // The device was activated/deactivated we need to notify so
-    // Interactions MQs can be updated.
-    if (converter->IsEnabled() != IsDeviceEnabled(converter))
+
+    bool should_be_enabled = IsDeviceEnabled(converter);
+    bool was_enabled = converter->IsEnabled();
+    if (should_be_enabled != was_enabled) {
+      converter->SetEnabled(should_be_enabled);
+
+      // The device was activated/deactivated we need to notify so
+      // Interactions MQs can be updated.
       UpdateDirtyFlags(converter);
-    converter->SetEnabled(IsDeviceEnabled(converter));
+    }
 
     if (converter->type() == InputDeviceType::INPUT_DEVICE_INTERNAL &&
         converter->HasKeyboard()) {
@@ -337,6 +344,7 @@
     converter->SetTouchEventLoggingEnabled(
         input_device_settings_.touch_event_logging_enabled);
   }
+
   NotifyDevicesUpdated();
 }
 
@@ -500,10 +508,7 @@
   if (enabled == palm_suppression_enabled_)
     return;
   palm_suppression_enabled_ = enabled;
-
-  for (const auto& it : converters_) {
-    it.second->SetEnabled(IsDeviceEnabled(it.second.get()));
-  }
+  ApplyInputDeviceSettings();
 }
 
 }  // namespace ui
diff --git a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc
index 24c14b5..9ec3121d 100644
--- a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc
+++ b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.cc
@@ -28,7 +28,7 @@
 }  // namespace
 
 EventReaderLibevdevCros::EventReaderLibevdevCros(
-    ScopedInputDevice fd,
+    base::ScopedFD fd,
     const base::FilePath& path,
     int id,
     const EventDeviceInfo& devinfo,
diff --git a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h
index b4480152..a6ed5a4 100644
--- a/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h
+++ b/ui/events/ozone/evdev/libgestures_glue/event_reader_libevdev_cros.h
@@ -10,11 +10,11 @@
 #include <memory>
 
 #include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "ui/events/ozone/evdev/event_converter_evdev.h"
 #include "ui/events/ozone/evdev/event_device_info.h"
-#include "ui/events/ozone/evdev/scoped_input_device.h"
 
 namespace ui {
 
@@ -43,7 +43,7 @@
     virtual void OnLibEvdevCrosStopped(Evdev* evdev, EventStateRec* state) = 0;
   };
 
-  EventReaderLibevdevCros(ScopedInputDevice fd,
+  EventReaderLibevdevCros(base::ScopedFD fd,
                           const base::FilePath& path,
                           int id,
                           const EventDeviceInfo& devinfo,
diff --git a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc
index b953513..d925222 100644
--- a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc
+++ b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc
@@ -34,13 +34,7 @@
 GesturesProp::GesturesProp(const std::string& name,
                            const PropertyType type,
                            const size_t count)
-    : name_(name),
-      type_(type),
-      count_(count),
-      get_(NULL),
-      set_(NULL),
-      handler_data_(NULL) {
-}
+    : name_(name), type_(type), count_(count) {}
 
 std::vector<int> GesturesProp::GetIntValue() const {
   NOTREACHED();
diff --git a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h
index c453b67d..b077cb9bf 100644
--- a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h
+++ b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h
@@ -36,14 +36,14 @@
 // A struct holding device properties that are useful when interacting with
 // the gestures lib.
 struct GestureDeviceProperties {
-  int area_left;
-  int area_right;
-  int area_top;
-  int area_bottom;
-  int res_y;
-  int res_x;
-  int orientation_minimum;
-  int orientation_maximum;
+  int area_left = 0;
+  int area_right = 0;
+  int area_top = 0;
+  int area_bottom = 0;
+  int res_y = 0;
+  int res_x = 0;
+  int orientation_minimum = 0;
+  int orientation_maximum = 0;
   GesturesPropBool raw_passthrough;
   GesturesPropBool dump_debug_log;
 };
@@ -330,9 +330,9 @@
 
   // Handler function pointers and the data to be passed to them when the
   // property is accessed.
-  GesturesPropGetHandler get_;
-  GesturesPropSetHandler set_;
-  void* handler_data_;
+  GesturesPropGetHandler get_ = nullptr;
+  GesturesPropSetHandler set_ = nullptr;
+  void* handler_data_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(GesturesProp);
 };
diff --git a/ui/events/ozone/evdev/scoped_input_device.cc b/ui/events/ozone/evdev/scoped_input_device.cc
deleted file mode 100644
index 3f8f62bd..0000000
--- a/ui/events/ozone/evdev/scoped_input_device.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/ozone/evdev/scoped_input_device.h"
-
-#include <errno.h>
-#include <unistd.h>
-
-#include "base/debug/alias.h"
-#include "base/logging.h"
-#include "base/posix/eintr_wrapper.h"
-
-namespace ui {
-namespace internal {
-
-// static
-void ScopedInputDeviceCloseTraits::Free(int fd) {
-  // It's important to crash here.
-  // There are security implications to not closing a file descriptor
-  // properly. As file descriptors are "capabilities", keeping them open
-  // would make the current process keep access to a resource. Much of
-  // Chrome relies on being able to "drop" such access.
-  // It's especially problematic on Linux with the setuid sandbox, where
-  // a single open directory would bypass the entire security model.
-  int ret = IGNORE_EINTR(close(fd));
-  PCHECK(0 == ret || errno != EBADF);
-}
-
-}  // namespace internal
-}  // namespace ui
diff --git a/ui/events/ozone/evdev/scoped_input_device.h b/ui/events/ozone/evdev/scoped_input_device.h
deleted file mode 100644
index 5278dd0..0000000
--- a/ui/events/ozone/evdev/scoped_input_device.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_EVENTS_OZONE_EVDEV_SCOPED_INPUT_DEVICE_H_
-#define UI_EVENTS_OZONE_EVDEV_SCOPED_INPUT_DEVICE_H_
-
-#include "base/scoped_generic.h"
-#include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
-
-namespace ui {
-namespace internal {
-
-struct EVENTS_OZONE_EVDEV_EXPORT ScopedInputDeviceCloseTraits {
-  static int InvalidValue() { return -1; }
-  static void Free(int fd);
-};
-
-}  // namespace internal
-
-typedef base::ScopedGeneric<int, internal::ScopedInputDeviceCloseTraits>
-    ScopedInputDevice;
-
-}  // namespace ui
-
-#endif  // UI_EVENTS_OZONE_EVDEV_SCOPED_INPUT_DEVICE_H_
diff --git a/ui/events/ozone/evdev/tablet_event_converter_evdev.cc b/ui/events/ozone/evdev/tablet_event_converter_evdev.cc
index 938aa6ed..a242c713 100644
--- a/ui/events/ozone/evdev/tablet_event_converter_evdev.cc
+++ b/ui/events/ozone/evdev/tablet_event_converter_evdev.cc
@@ -31,7 +31,7 @@
 }  // namespace
 
 TabletEventConverterEvdev::TabletEventConverterEvdev(
-    ScopedInputDevice fd,
+    base::ScopedFD fd,
     base::FilePath path,
     int id,
     CursorDelegateEvdev* cursor,
@@ -172,17 +172,18 @@
 
   unsigned int button;
   // These are the same as X11 behaviour
-  if (input.code == BTN_TOUCH)
+  if (input.code == BTN_TOUCH) {
     button = BTN_LEFT;
-  else if (input.code == BTN_STYLUS2)
+  } else if (input.code == BTN_STYLUS2) {
     button = BTN_RIGHT;
-  else if (input.code == BTN_STYLUS)
+  } else if (input.code == BTN_STYLUS) {
     if (one_side_btn_pen_)
       button = BTN_RIGHT;
     else
       button = BTN_MIDDLE;
-  else
+  } else {
     return;
+  }
 
   if (abs_value_dirty_) {
     UpdateCursor();
diff --git a/ui/events/ozone/evdev/tablet_event_converter_evdev.h b/ui/events/ozone/evdev/tablet_event_converter_evdev.h
index 2637a42..6d22b98 100644
--- a/ui/events/ozone/evdev/tablet_event_converter_evdev.h
+++ b/ui/events/ozone/evdev/tablet_event_converter_evdev.h
@@ -6,6 +6,7 @@
 #define UI_EVENTS_OZONE_TABLET_EVENT_CONVERTER_EVDEV_H_
 
 #include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "base/message_loop/message_pump_libevent.h"
 #include "ui/events/event.h"
@@ -14,7 +15,6 @@
 #include "ui/events/ozone/evdev/event_converter_evdev.h"
 #include "ui/events/ozone/evdev/event_device_info.h"
 #include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
-#include "ui/events/ozone/evdev/scoped_input_device.h"
 
 struct input_event;
 
@@ -25,7 +25,7 @@
 class EVENTS_OZONE_EVDEV_EXPORT TabletEventConverterEvdev
     : public EventConverterEvdev {
  public:
-  TabletEventConverterEvdev(ScopedInputDevice fd,
+  TabletEventConverterEvdev(base::ScopedFD fd,
                             base::FilePath path,
                             int id,
                             CursorDelegateEvdev* cursor,
@@ -50,7 +50,7 @@
   void FlushEvents(const input_event& input);
 
   // Input device file descriptor.
-  ScopedInputDevice input_device_fd_;
+  base::ScopedFD input_device_fd_;
 
   // Controller for watching the input fd.
   base::MessagePumpLibevent::FileDescriptorWatcher controller_;
diff --git a/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc b/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc
index 92d7c85..5b59ba02 100644
--- a/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc
+++ b/ui/events/ozone/evdev/tablet_event_converter_evdev_unittest.cc
@@ -15,6 +15,7 @@
 
 #include "base/bind.h"
 #include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/posix/eintr_wrapper.h"
@@ -110,7 +111,7 @@
 
 class MockTabletEventConverterEvdev : public TabletEventConverterEvdev {
  public:
-  MockTabletEventConverterEvdev(ScopedInputDevice fd,
+  MockTabletEventConverterEvdev(base::ScopedFD fd,
                                 base::FilePath path,
                                 CursorDelegateEvdev* cursor,
                                 const EventDeviceInfo& devinfo,
@@ -163,7 +164,7 @@
 };
 
 MockTabletEventConverterEvdev::MockTabletEventConverterEvdev(
-    ScopedInputDevice fd,
+    base::ScopedFD fd,
     base::FilePath path,
     CursorDelegateEvdev* cursor,
     const EventDeviceInfo& devinfo,
@@ -226,7 +227,7 @@
     int evdev_io[2];
     if (pipe(evdev_io))
       PLOG(FATAL) << "failed pipe";
-    ui::ScopedInputDevice events_in(evdev_io[0]);
+    base::ScopedFD events_in(evdev_io[0]);
     events_out_.reset(evdev_io[1]);
 
     ui::EventDeviceInfo devinfo;
@@ -259,7 +260,7 @@
 
   std::vector<std::unique_ptr<ui::Event>> dispatched_events_;
 
-  ui::ScopedInputDevice events_out_;
+  base::ScopedFD events_out_;
 
   DISALLOW_COPY_AND_ASSIGN(TabletEventConverterEvdevTest);
 };
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev.cc b/ui/events/ozone/evdev/touch_event_converter_evdev.cc
index e669a98..4a02b6ca 100644
--- a/ui/events/ozone/evdev/touch_event_converter_evdev.cc
+++ b/ui/events/ozone/evdev/touch_event_converter_evdev.cc
@@ -40,10 +40,10 @@
 const int kMaxTrackingId = 0xffff;  // TRKID_MAX in kernel.
 
 struct TouchCalibration {
-  int bezel_left;
-  int bezel_right;
-  int bezel_top;
-  int bezel_bottom;
+  int bezel_left = 0;
+  int bezel_right = 0;
+  int bezel_top = 0;
+  int bezel_bottom = 0;
 };
 
 // Convert tilt from [min, min + num_values) to [-90deg, +90deg)
@@ -115,7 +115,7 @@
 namespace ui {
 
 TouchEventConverterEvdev::TouchEventConverterEvdev(
-    ScopedInputDevice fd,
+    base::ScopedFD fd,
     base::FilePath path,
     int id,
     const EventDeviceInfo& devinfo,
@@ -129,7 +129,6 @@
                           devinfo.product_id()),
       input_device_fd_(std::move(fd)),
       dispatcher_(dispatcher) {
-
   touch_evdev_debug_buffer_.Initialize(devinfo);
 }
 
@@ -187,7 +186,7 @@
 
   // Apply --touch-calibration.
   if (type() == INPUT_DEVICE_INTERNAL) {
-    TouchCalibration cal = {};
+    TouchCalibration cal;
     GetTouchCalibration(&cal);
     x_min_tuxels_ += cal.bezel_left;
     x_num_tuxels_ -= cal.bezel_left + cal.bezel_right;
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev.h b/ui/events/ozone/evdev/touch_event_converter_evdev.h
index 250b5fde9..90590244 100644
--- a/ui/events/ozone/evdev/touch_event_converter_evdev.h
+++ b/ui/events/ozone/evdev/touch_event_converter_evdev.h
@@ -20,13 +20,13 @@
 
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "base/message_loop/message_pump_libevent.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/ozone/evdev/event_converter_evdev.h"
 #include "ui/events/ozone/evdev/event_device_info.h"
 #include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
-#include "ui/events/ozone/evdev/scoped_input_device.h"
 #include "ui/events/ozone/evdev/touch_evdev_debug_buffer.h"
 
 namespace ui {
@@ -38,7 +38,7 @@
 class EVENTS_OZONE_EVDEV_EXPORT TouchEventConverterEvdev
     : public EventConverterEvdev {
  public:
-  TouchEventConverterEvdev(ScopedInputDevice fd,
+  TouchEventConverterEvdev(base::ScopedFD fd,
                            base::FilePath path,
                            int id,
                            const EventDeviceInfo& devinfo,
@@ -99,7 +99,7 @@
   int NextTrackingId();
 
   // Input device file descriptor.
-  ScopedInputDevice input_device_fd_;
+  base::ScopedFD input_device_fd_;
 
   // Dispatcher for events.
   DeviceEventDispatcherEvdev* dispatcher_;
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc b/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
index 696d94b5..c0294be 100644
--- a/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
+++ b/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "base/posix/eintr_wrapper.h"
@@ -86,7 +87,7 @@
 
 class MockTouchEventConverterEvdev : public TouchEventConverterEvdev {
  public:
-  MockTouchEventConverterEvdev(ScopedInputDevice fd,
+  MockTouchEventConverterEvdev(base::ScopedFD fd,
                                base::FilePath path,
                                const EventDeviceInfo& devinfo,
                                DeviceEventDispatcherEvdev* dispatcher);
@@ -170,7 +171,7 @@
 };
 
 MockTouchEventConverterEvdev::MockTouchEventConverterEvdev(
-    ScopedInputDevice fd,
+    base::ScopedFD fd,
     base::FilePath path,
     const EventDeviceInfo& devinfo,
     DeviceEventDispatcherEvdev* dispatcher)
@@ -219,7 +220,7 @@
     int evdev_io[2];
     if (pipe(evdev_io))
       PLOG(FATAL) << "failed pipe";
-    ScopedInputDevice events_in(evdev_io[0]);
+    base::ScopedFD events_in(evdev_io[0]);
     events_out_.reset(evdev_io[1]);
 
     // Device creation happens on a worker thread since it may involve blocking
@@ -273,7 +274,7 @@
   std::unique_ptr<ui::MockTouchEventConverterEvdev> device_;
   std::unique_ptr<ui::MockDeviceEventDispatcherEvdev> dispatcher_;
 
-  ScopedInputDevice events_out_;
+  base::ScopedFD events_out_;
 
   void DispatchCallback(const GenericEventParams& params) {
     dispatched_events_.push_back(params);
diff --git a/ui/gl/gl_switches.cc b/ui/gl/gl_switches.cc
index a6b027fd..ef08f4e 100644
--- a/ui/gl/gl_switches.cc
+++ b/ui/gl/gl_switches.cc
@@ -119,6 +119,7 @@
 // GpuProcessHost to the GPU Process. Add your switch to this list if you need
 // to read it in the GPU process, else don't add it.
 const char* const kGLSwitchesCopiedFromGpuProcessHost[] = {
+    kDisableDirectComposition,
     kDisableGpuVsync,
     kDisableD3D11,
     kDisableES3GLContext,
diff --git a/ui/message_center/message_center_impl_unittest.cc b/ui/message_center/message_center_impl_unittest.cc
index 0262d59..09630bb 100644
--- a/ui/message_center/message_center_impl_unittest.cc
+++ b/ui/message_center/message_center_impl_unittest.cc
@@ -355,10 +355,15 @@
   popup_timers_controller->OnNotificationDisplayed("id1", DISPLAY_SOURCE_POPUP);
   ASSERT_EQ(popup_timers_controller->timer_finished(), 0);
 
+#if defined(OS_CHROMEOS)
+  const int dismiss_time = kAutocloseDefaultDelaySeconds;
+#else
+  const int dismiss_time = kAutocloseHighPriorityDelaySeconds;
+#endif
+
   // Fast forward the |task_runner| by one second less than the auto-close timer
   // frequency for Web Notifications. (As set by the |notifier_id|.)
-  task_runner->FastForwardBy(
-      base::TimeDelta::FromSeconds(kAutocloseHighPriorityDelaySeconds - 1));
+  task_runner->FastForwardBy(base::TimeDelta::FromSeconds(dismiss_time - 1));
   ASSERT_EQ(popup_timers_controller->timer_finished(), 0);
 
   // Trigger a replacement of the notification in the timer controller.
@@ -366,8 +371,7 @@
 
   // Fast forward the |task_runner| by one second less than the auto-close timer
   // frequency for Web Notifications again. It should have been reset.
-  task_runner->FastForwardBy(
-      base::TimeDelta::FromSeconds(kAutocloseHighPriorityDelaySeconds - 1));
+  task_runner->FastForwardBy(base::TimeDelta::FromSeconds(dismiss_time - 1));
   ASSERT_EQ(popup_timers_controller->timer_finished(), 0);
 
   // Now fast forward the |task_runner| by two seconds (to avoid flakiness),
diff --git a/ui/message_center/popup_timers_controller.cc b/ui/message_center/popup_timers_controller.cc
index 49e5d85..359f104 100644
--- a/ui/message_center/popup_timers_controller.cc
+++ b/ui/message_center/popup_timers_controller.cc
@@ -14,10 +14,20 @@
 namespace {
 
 base::TimeDelta GetTimeoutForNotification(Notification* notification) {
-  if (notification->notifier_id().type == NotifierId::WEB_PAGE ||
-      notification->priority() > DEFAULT_PRIORITY) {
+// Web Notifications are given a longer on-screen time on non-Chrome OS
+// platforms as there is no notification center to dismiss them to.
+#if defined(OS_CHROMEOS)
+  const bool use_high_priority_delay =
+      notification->priority() > DEFAULT_PRIORITY;
+#else
+  const bool use_high_priority_delay =
+      notification->priority() > DEFAULT_PRIORITY ||
+      notification->notifier_id().type == NotifierId::WEB_PAGE;
+#endif
+
+  if (use_high_priority_delay)
     return base::TimeDelta::FromSeconds(kAutocloseHighPriorityDelaySeconds);
-  }
+
   return base::TimeDelta::FromSeconds(kAutocloseDefaultDelaySeconds);
 }
 
diff --git a/ui/message_center/public/cpp/message_center_constants.h b/ui/message_center/public/cpp/message_center_constants.h
index 16796db..cc0489c 100644
--- a/ui/message_center/public/cpp/message_center_constants.h
+++ b/ui/message_center/public/cpp/message_center_constants.h
@@ -93,9 +93,9 @@
 // Not used when --enabled-new-style-notification is set.
 const size_t kNotificationMaximumItems = 5;
 
-// Timing. Web Notifications always use high-priority timings. Given the absence
-// of a notification center on non-Chrome OS platforms, this improves users'
-// ability to interact with the toasts.
+// Timing. Web Notifications always use high-priority timings except on
+// Chrome OS. Given the absence of a notification center on non-Chrome OS
+// platforms, this improves users' ability to interact with the toasts.
 const int kAutocloseDefaultDelaySeconds = 8;
 const int kAutocloseHighPriorityDelaySeconds = 25;
 
diff --git a/ui/message_center/views/bounded_label.cc b/ui/message_center/views/bounded_label.cc
index 64d88e4..334cc34 100644
--- a/ui/message_center/views/bounded_label.cc
+++ b/ui/message_center/views/bounded_label.cc
@@ -346,6 +346,19 @@
   label_->GetAccessibleNodeData(node_data);
 }
 
+views::View* BoundedLabel::GetTooltipHandlerForPoint(const gfx::Point& point) {
+  if (GetSizeForWidthAndLines(width(), -1).height() <=
+      GetHeightForWidth(width())) {
+    return nullptr;
+  }
+  return HitTestPoint(point) ? this : nullptr;
+}
+
+bool BoundedLabel::GetTooltipText(const gfx::Point& p,
+                                  base::string16* tooltip) const {
+  return label_->GetTooltipText(p, tooltip);
+}
+
 void BoundedLabel::OnBoundsChanged(const gfx::Rect& previous_bounds) {
   label_->SetBoundsRect(bounds());
   views::View::OnBoundsChanged(previous_bounds);
diff --git a/ui/message_center/views/bounded_label.h b/ui/message_center/views/bounded_label.h
index 8d204cd..1ae1a16f 100644
--- a/ui/message_center/views/bounded_label.h
+++ b/ui/message_center/views/bounded_label.h
@@ -58,6 +58,9 @@
   void OnPaint(gfx::Canvas* canvas) override;
   bool CanProcessEventsWithinSubtree() const override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+  views::View* GetTooltipHandlerForPoint(const gfx::Point& point) override;
+  bool GetTooltipText(const gfx::Point& p,
+                      base::string16* tooltip) const override;
 
  protected:
   // Overridden from views::View.
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
index d85d1855..671ead04 100644
--- a/ui/message_center/views/notification_view_md.cc
+++ b/ui/message_center/views/notification_view_md.cc
@@ -343,7 +343,7 @@
                                                const gfx::Rect& rect) {
   CHECK_EQ(root, this);
 
-  // TODO(tdanderson): Modify this function to support rect-based event
+  // TODO(tetsui): Modify this function to support rect-based event
   // targeting. Using the center point of |rect| preserves this function's
   // expected behavior for the time being.
   gfx::Point point = rect.CenterPoint();
@@ -487,6 +487,22 @@
   UpdateControlButtonsVisibility();
 }
 
+bool NotificationViewMD::OnMousePressed(const ui::MouseEvent& event) {
+  if (!event.IsOnlyLeftMouseButton())
+    return false;
+
+  // Ignore click of actions row outside action buttons.
+  if (expanded_) {
+    DCHECK(actions_row_);
+    gfx::Point point_in_child = event.location();
+    ConvertPointToTarget(this, actions_row_, &point_in_child);
+    if (actions_row_->HitTestPoint(point_in_child))
+      return true;
+  }
+
+  return MessageView::OnMousePressed(event);
+}
+
 void NotificationViewMD::UpdateWithNotification(
     const Notification& notification) {
   MessageView::UpdateWithNotification(notification);
diff --git a/ui/message_center/views/notification_view_md.h b/ui/message_center/views/notification_view_md.h
index 346fd66..9a752e3 100644
--- a/ui/message_center/views/notification_view_md.h
+++ b/ui/message_center/views/notification_view_md.h
@@ -141,6 +141,7 @@
   gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
   void OnMouseEntered(const ui::MouseEvent& event) override;
   void OnMouseExited(const ui::MouseEvent& event) override;
+  bool OnMousePressed(const ui::MouseEvent& event) override;
 
   // Overridden from MessageView:
   void UpdateWithNotification(const Notification& notification) override;
diff --git a/ui/ozone/demo/gl_renderer.cc b/ui/ozone/demo/gl_renderer.cc
index 53f5e96..a8968703 100644
--- a/ui/ozone/demo/gl_renderer.cc
+++ b/ui/ozone/demo/gl_renderer.cc
@@ -52,8 +52,12 @@
   glClearColor(1 - fraction, fraction, 0.0, 1.0);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-  surface_->SwapBuffersAsync(base::Bind(&GlRenderer::PostRenderFrameTask,
-                                        weak_ptr_factory_.GetWeakPtr()));
+  if (surface_->SupportsAsyncSwap()) {
+    surface_->SwapBuffersAsync(base::Bind(&GlRenderer::PostRenderFrameTask,
+                                          weak_ptr_factory_.GetWeakPtr()));
+  } else {
+    PostRenderFrameTask(surface_->SwapBuffers());
+  }
 }
 
 void GlRenderer::PostRenderFrameTask(gfx::SwapResult result) {
diff --git a/ui/ozone/demo/ozone_demo.cc b/ui/ozone/demo/ozone_demo.cc
index c238a7b0..38d3c919 100644
--- a/ui/ozone/demo/ozone_demo.cc
+++ b/ui/ozone/demo/ozone_demo.cc
@@ -126,6 +126,7 @@
         weak_ptr_factory_(this) {
     platform_window_ =
         ui::OzonePlatform::GetInstance()->CreatePlatformWindow(this, bounds);
+    platform_window_->Show();
   }
   ~DemoWindow() override {}
 
@@ -225,13 +226,12 @@
       scoped_refptr<gl::GLSurface> surface = CreateGLSurface(widget);
       if (!surface)
         LOG(FATAL) << "Failed to create GL surface";
-      if (!surface->SupportsAsyncSwap())
-        LOG(FATAL) << "GL surface must support SwapBuffersAsync";
-      if (surface->IsSurfaceless())
+      if (surface->IsSurfaceless()) {
         return std::make_unique<ui::SurfacelessGlRenderer>(widget, surface,
                                                            size);
-      else
+      } else {
         return std::make_unique<ui::GlRenderer>(widget, surface, size);
+      }
     }
     case SOFTWARE:
       return std::make_unique<ui::SoftwareRenderer>(widget, size);
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index 734ba18..d3febbf7 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -24,6 +24,7 @@
 void WaitForFence(EGLDisplay display, EGLSyncKHR fence) {
   eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
                        EGL_FOREVER_KHR);
+  eglDestroySyncKHR(display, fence);
 }
 
 }  // namespace
@@ -143,7 +144,7 @@
       base::Bind(&WaitForFence, GetDisplay(), fence);
 
   base::Closure fence_retired_callback = base::Bind(
-      &GbmSurfaceless::FenceRetired, weak_factory_.GetWeakPtr(), fence, frame);
+      &GbmSurfaceless::FenceRetired, weak_factory_.GetWeakPtr(), frame);
 
   base::PostTaskWithTraitsAndReply(
       FROM_HERE,
@@ -237,8 +238,7 @@
                           implicit ? attrib_list : NULL);
 }
 
-void GbmSurfaceless::FenceRetired(EGLSyncKHR fence, PendingFrame* frame) {
-  eglDestroySyncKHR(GetDisplay(), fence);
+void GbmSurfaceless::FenceRetired(PendingFrame* frame) {
   frame->ready = true;
   SubmitFrame();
 }
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
index db5491c..58020c3e 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
@@ -78,7 +78,7 @@
   void SubmitFrame();
 
   EGLSyncKHR InsertFence(bool implicit);
-  void FenceRetired(EGLSyncKHR fence, PendingFrame* frame);
+  void FenceRetired(PendingFrame* frame);
 
   void SwapCompleted(const SwapCompletionCallback& callback,
                      gfx::SwapResult result);
diff --git a/ui/views/controls/animated_icon_view.cc b/ui/views/controls/animated_icon_view.cc
index 4cfd59b4..9ad002f 100644
--- a/ui/views/controls/animated_icon_view.cc
+++ b/ui/views/controls/animated_icon_view.cc
@@ -40,6 +40,10 @@
   UpdateStaticImage();
 }
 
+bool AnimatedIconView::IsAnimating() const {
+  return start_time_ != base::TimeTicks();
+}
+
 void AnimatedIconView::OnPaint(gfx::Canvas* canvas) {
   if (!IsAnimating()) {
     views::ImageView::OnPaint(canvas);
@@ -67,10 +71,6 @@
 
 void AnimatedIconView::OnCompositingShuttingDown(ui::Compositor* compositor) {}
 
-bool AnimatedIconView::IsAnimating() const {
-  return start_time_ != base::TimeTicks();
-}
-
 void AnimatedIconView::UpdateStaticImage() {
   gfx::IconDescription description(
       icon_, 0, color_, state_ == START ? base::TimeDelta() : duration_,
diff --git a/ui/views/controls/animated_icon_view.h b/ui/views/controls/animated_icon_view.h
index c3b5df2..af13004c 100644
--- a/ui/views/controls/animated_icon_view.h
+++ b/ui/views/controls/animated_icon_view.h
@@ -34,6 +34,8 @@
   // Jumps to the end or start state.
   void SetState(State state);
 
+  bool IsAnimating() const;
+
   // views::ImageView
   void OnPaint(gfx::Canvas* canvas) override;
 
@@ -42,8 +44,6 @@
   void OnCompositingShuttingDown(ui::Compositor* compositor) override;
 
  private:
-  bool IsAnimating() const;
-
   void UpdateStaticImage();
 
   const gfx::VectorIcon& icon_;
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.js b/ui/webui/resources/cr_components/chromeos/network/network_config.js
index a609bf5f..f7577e6 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_config.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_config.js
@@ -432,12 +432,17 @@
       this.close_();
       return;
     }
-    this.propertiesReceived_ = true;
-    this.networkProperties = properties;
-    this.error_ = properties.ErrorState || '';
 
-    // Set the current shareNetwork_ value when porperties are received.
-    this.setShareNetwork_();
+    if (properties.Type == CrOnc.Type.ETHERNET &&
+        this.get('Ethernet.Authentication', properties) !=
+            CrOnc.Authentication.WEP_8021X) {
+      // Ethernet may have EAP properties set in a separate EthernetEap
+      // configuration. Request that before calling |setNetworkProperties_|.
+      this.networkingPrivate.getNetworks(
+          {networkType: CrOnc.Type.ETHERNET, visible: false, configured: true},
+          this.getEthernetEap_.bind(this, properties));
+      return;
+    }
 
     if (properties.Type == CrOnc.Type.VPN) {
       this.vpnSaveCredentials_ =
@@ -445,6 +450,56 @@
           !!this.get('VPN.IPsec.SaveCredentials', properties) ||
           !!this.get('VPN.L2TP.SaveCredentials', properties);
     }
+
+    this.setNetworkProperties_(properties);
+  },
+
+  /**
+   * @param {!chrome.networkingPrivate.NetworkProperties} properties
+   * @private
+   */
+  setNetworkProperties_: function(properties) {
+    this.propertiesReceived_ = true;
+    this.networkProperties = properties;
+    this.error_ = properties.ErrorState || '';
+
+    // Set the current shareNetwork_ value when porperties are received.
+    this.setShareNetwork_();
+  },
+
+  /**
+   * networkingPrivate.getNetworks callback. Expects an array of Ethernet
+   * networks and looks for an EAP configuration to apply.
+   * @param {!chrome.networkingPrivate.NetworkProperties} properties
+   * @param {!Array<chrome.networkingPrivate.NetworkStateProperties>} networks
+   * @private
+   */
+  getEthernetEap_: function(properties, networks) {
+    if (this.getRuntimeError_()) {
+      this.setNetworkProperties_(properties);
+      return;
+    }
+
+    // Look for an existing EAP configuration. This may be stored in a
+    // separate 'Ethernet EAP Parameters' configuration.
+    var ethernetEap = networks.find(function(network) {
+      return !!network.Ethernet &&
+          network.Ethernet.Authentication == CrOnc.Authentication.WEP_8021X;
+    });
+    if (!ethernetEap) {
+      this.setNetworkProperties_(properties);
+      return;
+    }
+
+    this.networkingPrivate.getProperties(ethernetEap.GUID, (eapProperties) => {
+      if (!this.getRuntimeError_() && eapProperties.Ethernet.EAP) {
+        this.guid = eapProperties.GUID;
+        this.security_ = CrOnc.Security.WPA_EAP;
+        properties.GUID = eapProperties.GUID;
+        properties.Ethernet.EAP = eapProperties.Ethernet.EAP;
+      }
+      this.setNetworkProperties_(properties);
+    });
   },
 
   /**
@@ -597,6 +652,11 @@
       this.set('WiFi.Security', this.security_, this.configProperties_);
       // Set the share value to its default when the security type changes.
       this.setShareNetwork_();
+    } else if (this.type == CrOnc.Type.ETHERNET) {
+      var auth = this.security_ == CrOnc.Security.WPA_EAP ?
+          CrOnc.Authentication.WEP_8021X :
+          CrOnc.Authentication.NONE;
+      this.set('Ethernet.Authentication', auth, this.configProperties_);
     }
     if (this.security_ == CrOnc.Security.WPA_EAP) {
       var eap = this.getEap_(this.configProperties_, true);
@@ -891,9 +951,12 @@
    */
   computeEapOuterItems_: function(
       guid, shareNetwork, shareAllowEnable, shareDefault) {
-    if ((guid && shareNetwork) || (!shareAllowEnable && shareDefault)) {
-      // If a network must be shared, hide the TLS option. Otherwise selecting
-      // TLS will turn off and disable the shared state.
+    // If a network must be shared, hide the TLS option. Otherwise selecting
+    // TLS will turn off and disable the shared state. NOTE: Ethernet EAP may
+    // be set at the Device level, but will be saved as a User configuration.
+    if (this.type != CrOnc.Type.ETHERNET &&
+        ((this.getSource_() != CrOnc.Source.NONE && shareNetwork) ||
+         (!shareAllowEnable && shareDefault))) {
       return [CrOnc.EAPType.LEAP, CrOnc.EAPType.PEAP, CrOnc.EAPType.EAP_TTLS];
     }
     return [
diff --git a/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js b/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
index e51c9ba..3eedf5d 100644
--- a/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
+++ b/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
@@ -124,6 +124,12 @@
 CrOnc.Type = chrome.networkingPrivate.NetworkType;
 
 /** @enum {string} */
+CrOnc.Authentication = {
+  NONE: 'None',
+  WEP_8021X: '8021X',
+};
+
+/** @enum {string} */
 CrOnc.IPsecAuthenticationType = {
   CERT: 'Cert',
   PSK: 'PSK',