diff --git a/DEPS b/DEPS
index 8277514..1fb8244d5 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '7e872caaf618c8c5fc376515143a3176e09bced2',
+  'skia_revision': 'e32500f0642df381fd79731df2f7a4a4a71a46e2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'b55b2e8728512edbb9524fa6fe440d98a4d91859',
+  'v8_revision': '5d7e07ff448d851cb3749c8a55d1f2953fc3e459',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -88,7 +88,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': '015356a98e4430dff9ce7e80ce9d2a62b04c2c4e',
+  'nacl_revision': '01a28a6069a98718184e31c10c5880496a1a9d95',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '7de63c29970bbe9460c5aa03b0297009ad8dee89',
+  'catapult_revision': 'c7c5420fbc58c841a1ae1bc0d8a732cf82469822',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 3a6ab4a4..9ffa555 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -383,6 +383,18 @@
         r'^content[\\\/]public[\\\/]test[\\\/]test_web_ui\.(cc|h)$',
       ),
     ),
+    (
+      'leveldb::DB::Open',
+      (
+        'Instead of leveldb::DB::Open() use leveldb_env::OpenDB() from',
+        'third_party/leveldatabase/env_chromium.h. It exposes databases to',
+        "Chrome's tracing, making their memory usage visible.",
+      ),
+      True,
+      (
+        r'^third_party/leveldatabase/.*\.(cc|h)$',
+      ),
+    )
 )
 
 
diff --git a/android_webview/browser/aw_safe_browsing_resource_throttle.cc b/android_webview/browser/aw_safe_browsing_resource_throttle.cc
index df901c4..ea49f2d1 100644
--- a/android_webview/browser/aw_safe_browsing_resource_throttle.cc
+++ b/android_webview/browser/aw_safe_browsing_resource_throttle.cc
@@ -130,8 +130,13 @@
 
   // Navigate back for back-to-safety on subresources
   if (!proceed && resource.is_subframe) {
-    DCHECK(web_contents->GetController().CanGoBack());
-    web_contents->GetController().GoBack();
+    if (web_contents->GetController().CanGoBack()) {
+      web_contents->GetController().GoBack();
+    } else {
+      web_contents->GetController().LoadURL(
+          ui_manager->default_safe_page(), content::Referrer(),
+          ui::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
+    }
   }
 
   ui_manager->OnBlockingPageDone(
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
index ddcb85d..77f415b 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
@@ -42,6 +42,7 @@
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.common.ContentUrlConstants;
 import org.chromium.net.test.EmbeddedTestServer;
 
 import java.util.ArrayList;
@@ -764,6 +765,34 @@
     @SmallTest
     @Feature({"AndroidWebView"})
     @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
+    public void testSafeBrowsingOnSafeBrowsingHitForSubresourceNoPreviousPage() throws Throwable {
+        mContentsClient.setSafeBrowsingAction(SafeBrowsingAction.BACK_TO_SAFETY);
+        final String responseUrl = mTestServer.getURL(IFRAME_HTML_PATH);
+        final String subresourceUrl = mTestServer.getURL(MALWARE_HTML_PATH);
+        int pageFinishedCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
+        loadUrlAsync(mAwContents, responseUrl);
+
+        // We'll successfully load IFRAME_HTML_PATH, and will soon call onSafeBrowsingHit
+        mContentsClient.getOnPageFinishedHelper().waitForCallback(pageFinishedCount);
+
+        // Wait for the onSafeBrowsingHit to call BACK_TO_SAFETY and navigate back
+        pollUiThread(new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                return ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL.equals(mAwContents.getUrl());
+            }
+        });
+
+        // Check onSafeBrowsingHit arguments
+        assertFalse(mContentsClient.getLastRequest().isMainFrame);
+        assertEquals(subresourceUrl, mContentsClient.getLastRequest().url);
+        assertEquals(AwSafeBrowsingConversionHelper.SAFE_BROWSING_THREAT_MALWARE,
+                mContentsClient.getLastThreatType());
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
     public void testSafeBrowsingOnSafeBrowsingHitForSubresource() throws Throwable {
         mContentsClient.setSafeBrowsingAction(SafeBrowsingAction.BACK_TO_SAFETY);
         loadGreenPage();
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index 4b87ec42..741a8e3 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/android/rules.gni")
+import("//device/vr/features/features.gni")
 import("//testing/test.gni")
 
 # Mark all targets as test only.
@@ -226,6 +227,14 @@
   data = [
     "data/",
   ]
+
+  # We only want to bother including these on bots set up for VR testing
+  if (include_vr_data) {
+    data += [
+      "//chrome/android/shared_preference_files/test/",
+      "//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
+    ]
+  }
   additional_apks = [
     "//android_webview/test/embedded_test_server:aw_net_test_support_apk",
     "//net/android:net_test_support_apk",
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 8b0c498..f71be58 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1227,6 +1227,7 @@
     "system/palette/mock_palette_tool_delegate.cc",
     "system/palette/mock_palette_tool_delegate.h",
     "system/palette/palette_tool_manager_unittest.cc",
+    "system/palette/palette_tray_unittest.cc",
     "system/palette/tools/create_note_unittest.cc",
     "system/palette/tools/metalayer_unittest.cc",
     "system/palette/tools/screenshot_unittest.cc",
diff --git a/ash/mus/manifest.json b/ash/mus/manifest.json
index d05c528..7ec57572 100644
--- a/ash/mus/manifest.json
+++ b/ash/mus/manifest.json
@@ -34,6 +34,7 @@
       "requires": {
         "*": [ "accessibility", "app" ],
         "preferences_forwarder": [ "pref_client" ],
+        "local_state": [ "pref_client" ],
         "ui": [ "display_test", "window_manager" ],
         "touch_hud": [ "mash:launchable" ]
       }
diff --git a/ash/shell.cc b/ash/shell.cc
index 2388832a..eaf3f417 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -420,6 +420,9 @@
 }
 
 PrefService* Shell::GetLocalStatePrefService() const {
+  if (shell_port_->GetAshConfig() == Config::MASH)
+    return local_state_.get();
+
   return shell_delegate_->GetLocalStatePrefService();
 }
 
@@ -633,7 +636,8 @@
       display_configurator_(new display::DisplayConfigurator()),
       native_cursor_manager_(nullptr),
       simulate_modal_window_open_for_testing_(false),
-      is_touch_hud_projection_enabled_(false) {
+      is_touch_hud_projection_enabled_(false),
+      weak_factory_(this) {
   // TODO(sky): better refactor cash/mash dependencies. Perhaps put all cash
   // state on ShellPortClassic. http://crbug.com/671246.
 
@@ -856,10 +860,17 @@
   if (config == Config::MASH && shell_delegate_->GetShellConnector()) {
     auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
     Shell::RegisterPrefs(pref_registry.get());
+    prefs::ConnectToPrefService(shell_delegate_->GetShellConnector(),
+                                std::move(pref_registry),
+                                base::Bind(&Shell::OnPrefServiceInitialized,
+                                           weak_factory_.GetWeakPtr()),
+                                prefs::mojom::kForwarderServiceName);
+    pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
     prefs::ConnectToPrefService(
         shell_delegate_->GetShellConnector(), std::move(pref_registry),
-        base::Bind(&Shell::OnPrefServiceInitialized, base::Unretained(this)),
-        prefs::mojom::kForwarderServiceName);
+        base::Bind(&Shell::OnLocalStatePrefServiceInitialized,
+                   weak_factory_.GetWeakPtr()),
+        prefs::mojom::kLocalStateServiceName);
   }
 
   // Some delegates access ShellPort during their construction. Create them here
@@ -1292,11 +1303,16 @@
 
 void Shell::OnPrefServiceInitialized(
     std::unique_ptr<::PrefService> pref_service) {
-  if (!instance_)
-    return;
   // |pref_service_| is null if can't connect to Chrome (as happens when
   // running mash outside of chrome --mash and chrome isn't built).
   pref_service_ = std::move(pref_service);
 }
 
+void Shell::OnLocalStatePrefServiceInitialized(
+    std::unique_ptr<::PrefService> pref_service) {
+  // |pref_service_| is null if can't connect to Chrome (as happens when
+  // running mash outside of chrome --mash and chrome isn't built).
+  local_state_ = std::move(pref_service);
+}
+
 }  // namespace ash
diff --git a/ash/shell.h b/ash/shell.h
index 8e66de5..08875b5 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -430,7 +430,8 @@
   // desired stored settings.
   PrefService* GetActiveUserPrefService() const;
 
-  // Gets the local state pref service. It will be null under mash.
+  // Gets the local state pref service. It can be null in mash if connecting to
+  // local state pref service has not completed successfully.
   PrefService* GetLocalStatePrefService() const;
 
   // Returns WebNotificationTray on the primary root window.
@@ -659,8 +660,10 @@
   // the profile is available.
   void InitializeShelf();
 
-  // Callback for prefs::ConnectToPrefService.
+  // Callbacks for prefs::ConnectToPrefService.
   void OnPrefServiceInitialized(std::unique_ptr<::PrefService> pref_service);
+  void OnLocalStatePrefServiceInitialized(
+      std::unique_ptr<::PrefService> pref_service);
 
   static Shell* instance_;
 
@@ -722,6 +725,7 @@
   std::unique_ptr<::wm::WindowModalityController> window_modality_controller_;
   std::unique_ptr<app_list::AppList> app_list_;
   std::unique_ptr<::PrefService> pref_service_;
+  std::unique_ptr<::PrefService> local_state_;
   std::unique_ptr<views::corewm::TooltipController> tooltip_controller_;
   LinkHandlerModelFactory* link_handler_model_factory_;
   std::unique_ptr<PowerButtonController> power_button_controller_;
@@ -832,6 +836,8 @@
 
   base::ObserverList<ShellObserver> shell_observers_;
 
+  base::WeakPtrFactory<Shell> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(Shell);
 };
 
diff --git a/ash/system/palette/common_palette_tool.cc b/ash/system/palette/common_palette_tool.cc
index bf38481e..c734883 100644
--- a/ash/system/palette/common_palette_tool.cc
+++ b/ash/system/palette/common_palette_tool.cc
@@ -49,30 +49,23 @@
 void CommonPaletteTool::OnEnable() {
   PaletteTool::OnEnable();
   start_time_ = base::TimeTicks::Now();
-
-  if (highlight_view_)
-    TrayPopupUtils::UpdateCheckMarkVisibility(highlight_view_, true);
 }
 
 void CommonPaletteTool::OnDisable() {
   PaletteTool::OnDisable();
   AddHistogramTimes(GetToolId(), base::TimeTicks::Now() - start_time_);
-
-  if (highlight_view_)
-    TrayPopupUtils::UpdateCheckMarkVisibility(highlight_view_, false);
 }
 
 void CommonPaletteTool::OnViewClicked(views::View* sender) {
+  // The tool should always be disabled when we click it because the bubble
+  // which houses this view is automatically closed when the tool is first
+  // enabled. Then, to open the bubble again we have to click on the palette
+  // tray twice, and the first click will disable any active tools.
+  DCHECK(!enabled());
+
   delegate()->RecordPaletteOptionsUsage(
       PaletteToolIdToPaletteTrayOptions(GetToolId()));
-  if (enabled()) {
-    delegate()->DisableTool(GetToolId());
-    delegate()->RecordPaletteModeCancellation(
-        PaletteToolIdToPaletteModeCancelType(GetToolId(),
-                                             false /*is_switched*/));
-  } else {
-    delegate()->EnableTool(GetToolId());
-  }
+  delegate()->EnableTool(GetToolId());
 }
 
 views::View* CommonPaletteTool::CreateDefaultView(const base::string16& name) {
@@ -80,7 +73,6 @@
       CreateVectorIcon(GetPaletteIcon(), kMenuIconSize, gfx::kChromeIconGrey);
   highlight_view_ = new HoverHighlightView(this);
   highlight_view_->AddIconAndLabel(icon, name);
-  TrayPopupUtils::InitializeAsCheckableRow(highlight_view_, enabled());
   return highlight_view_;
 }
 
diff --git a/ash/system/palette/palette_tool_manager.cc b/ash/system/palette/palette_tool_manager.cc
index 76cdc78..cae6adb 100644
--- a/ash/system/palette/palette_tool_manager.cc
+++ b/ash/system/palette/palette_tool_manager.cc
@@ -82,18 +82,21 @@
   return tool->GetActiveTrayIcon();
 }
 
-std::vector<PaletteToolView> PaletteToolManager::CreateViews() {
+std::vector<PaletteToolView> PaletteToolManager::CreateViewsForGroup(
+    PaletteGroup group) {
   std::vector<PaletteToolView> views;
-  views.reserve(tools_.size());
 
-  for (size_t i = 0; i < tools_.size(); ++i) {
-    views::View* tool_view = tools_[i]->CreateView();
+  for (const auto& tool : tools_) {
+    if (tool->GetGroup() != group)
+      continue;
+
+    views::View* tool_view = tool->CreateView();
     if (!tool_view)
       continue;
 
     PaletteToolView view;
-    view.group = tools_[i]->GetGroup();
-    view.tool_id = tools_[i]->GetToolId();
+    view.group = tool->GetGroup();
+    view.tool_id = tool->GetToolId();
     view.view = tool_view;
     views.push_back(view);
   }
diff --git a/ash/system/palette/palette_tool_manager.h b/ash/system/palette/palette_tool_manager.h
index 001a3409..e325f86f9 100644
--- a/ash/system/palette/palette_tool_manager.h
+++ b/ash/system/palette/palette_tool_manager.h
@@ -86,8 +86,8 @@
   // not available.
   const gfx::VectorIcon& GetActiveTrayIcon(PaletteToolId tool_id) const;
 
-  // Create views for all of the registered tools.
-  std::vector<PaletteToolView> CreateViews();
+  // Create views for all of the registered mode tools with group |group|.
+  std::vector<PaletteToolView> CreateViewsForGroup(PaletteGroup group);
 
   // Called when the views returned by CreateViews have been destroyed. This
   // should clear any (now) stale references.
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc
index 9c623809..bd777333 100644
--- a/ash/system/palette/palette_tray.cc
+++ b/ash/system/palette/palette_tray.cc
@@ -234,7 +234,9 @@
 
 void PaletteTray::BubbleViewDestroyed() {
   palette_tool_manager_->NotifyViewsDestroyed();
-  SetIsActive(false);
+  // The tray button remains active if the current active tool is a mode.
+  SetIsActive(palette_tool_manager_->GetActiveTool(PaletteGroup::MODE) !=
+              PaletteToolId::NONE);
 }
 
 void PaletteTray::OnMouseEnteredView() {}
@@ -334,6 +336,19 @@
     return true;
   }
 
+  // Deactivate the active tool if there is one.
+  PaletteToolId active_tool_id =
+      palette_tool_manager_->GetActiveTool(PaletteGroup::MODE);
+  if (active_tool_id != PaletteToolId::NONE) {
+    palette_tool_manager_->DeactivateTool(active_tool_id);
+    // TODO(sammiequon): Investigate whether we should removed |is_switched|
+    // from PaletteToolIdToPaletteModeCancelType.
+    RecordPaletteModeCancellation(PaletteToolIdToPaletteModeCancelType(
+        active_tool_id, false /*is_switched*/));
+    SetIsActive(false);
+    return true;
+  }
+
   ShowBubble();
   return true;
 }
@@ -373,18 +388,33 @@
       gfx::Insets(0, kPaddingBetweenTitleAndLeftEdge, 0, 0)));
   bubble_view->AddChildView(title_view);
 
-  // Add horizontal separator.
-  views::Separator* separator = new views::Separator();
-  separator->SetColor(kPaletteSeparatorColor);
-  separator->SetBorder(views::CreateEmptyBorder(gfx::Insets(
-      kPaddingBetweenTitleAndSeparator, 0, kMenuSeparatorVerticalPadding, 0)));
-  bubble_view->AddChildView(separator);
+  // Function for creating a separator.
+  auto build_separator = []() {
+    auto* separator = new views::Separator();
+    separator->SetColor(kPaletteSeparatorColor);
+    separator->SetBorder(views::CreateEmptyBorder(
+        gfx::Insets(kPaddingBetweenTitleAndSeparator, 0,
+                    kMenuSeparatorVerticalPadding, 0)));
+    return separator;
+  };
+
+  // Add horizontal separator between the title and the tools.
+  bubble_view->AddChildView(build_separator());
 
   // Add palette tools.
   // TODO(tdanderson|jdufault): Use SystemMenuButton to get the material design
   // ripples.
-  std::vector<PaletteToolView> views = palette_tool_manager_->CreateViews();
-  for (const PaletteToolView& view : views)
+  std::vector<PaletteToolView> action_views =
+      palette_tool_manager_->CreateViewsForGroup(PaletteGroup::ACTION);
+  for (const PaletteToolView& view : action_views)
+    bubble_view->AddChildView(view.view);
+
+  // Add horizontal separator between action tools and mode tools.
+  bubble_view->AddChildView(build_separator());
+
+  std::vector<PaletteToolView> mode_views =
+      palette_tool_manager_->CreateViewsForGroup(PaletteGroup::MODE);
+  for (const PaletteToolView& view : mode_views)
     bubble_view->AddChildView(view.view);
 
   // Show the bubble.
@@ -399,7 +429,7 @@
 void PaletteTray::UpdateTrayIcon() {
   icon_->SetImage(CreateVectorIcon(
       palette_tool_manager_->GetActiveTrayIcon(
-          palette_tool_manager_->GetActiveTool(ash::PaletteGroup::MODE)),
+          palette_tool_manager_->GetActiveTool(PaletteGroup::MODE)),
       kTrayIconSize, kShelfIconColor));
 }
 
@@ -419,4 +449,12 @@
              ShouldShowOnDisplay(this) && IsInUserSession());
 }
 
+// TestApi. For testing purposes.
+PaletteTray::TestApi::TestApi(PaletteTray* palette_tray)
+    : palette_tray_(palette_tray) {
+  DCHECK(palette_tray_);
+}
+
+PaletteTray::TestApi::~TestApi() {}
+
 }  // namespace ash
diff --git a/ash/system/palette/palette_tray.h b/ash/system/palette/palette_tray.h
index f8375c8..a3c0774 100644
--- a/ash/system/palette/palette_tray.h
+++ b/ash/system/palette/palette_tray.h
@@ -27,8 +27,8 @@
 
 namespace ash {
 
-class TrayBubbleWrapper;
 class PaletteToolManager;
+class TrayBubbleWrapper;
 
 // The PaletteTray shows the palette in the bottom area of the screen. This
 // class also controls the lifetime for all of the tools available in the
@@ -40,6 +40,26 @@
                                public PaletteToolManager::Delegate,
                                public ui::InputDeviceEventObserver {
  public:
+  // For testing.
+  class TestApi {
+   public:
+    explicit TestApi(PaletteTray* palette_tray);
+    ~TestApi();
+
+    PaletteToolManager* GetPaletteToolManager() {
+      return palette_tray_->palette_tool_manager_.get();
+    }
+
+    TrayBubbleWrapper* GetTrayBubbleWrapper() {
+      return palette_tray_->bubble_.get();
+    }
+
+   private:
+    PaletteTray* palette_tray_ = nullptr;  // not owned
+
+    DISALLOW_COPY_AND_ASSIGN(TestApi);
+  };
+
   explicit PaletteTray(Shelf* shelf);
   ~PaletteTray() override;
 
diff --git a/ash/system/palette/palette_tray_unittest.cc b/ash/system/palette/palette_tray_unittest.cc
new file mode 100644
index 0000000..dc429dd2
--- /dev/null
+++ b/ash/system/palette/palette_tray_unittest.cc
@@ -0,0 +1,104 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/palette/palette_tray.h"
+
+#include "ash/ash_switches.h"
+#include "ash/shell_test_api.h"
+#include "ash/system/palette/test_palette_delegate.h"
+#include "ash/system/status_area_widget.h"
+#include "ash/system/status_area_widget_test_helper.h"
+#include "ash/test/ash_test_base.h"
+#include "base/command_line.h"
+#include "ui/events/event.h"
+
+namespace ash {
+
+class PaletteTrayTest : public AshTestBase {
+ public:
+  PaletteTrayTest() {}
+  ~PaletteTrayTest() override {}
+
+  void SetUp() override {
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        switches::kAshForceEnableStylusTools);
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        switches::kAshEnablePaletteOnAllDisplays);
+
+    AshTestBase::SetUp();
+
+    palette_tray_ =
+        StatusAreaWidgetTestHelper::GetStatusAreaWidget()->palette_tray();
+    test_api_ = base::MakeUnique<PaletteTray::TestApi>(palette_tray_);
+
+    ShellTestApi().SetPaletteDelegate(base::MakeUnique<TestPaletteDelegate>());
+  }
+
+  // Performs a tap on the palette tray button.
+  void PerformTap() {
+    ui::GestureEvent tap(0, 0, 0, base::TimeTicks(),
+                         ui::GestureEventDetails(ui::ET_GESTURE_TAP));
+    palette_tray_->PerformAction(tap);
+  }
+
+ protected:
+  PaletteTray* palette_tray_ = nullptr;  // not owned
+
+  std::unique_ptr<PaletteTray::TestApi> test_api_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PaletteTrayTest);
+};
+
+// Verify the palette tray button exists and is visible with the flags we added
+// during setup.
+TEST_F(PaletteTrayTest, PaletteTrayIsVisible) {
+  ASSERT_TRUE(palette_tray_);
+  EXPECT_TRUE(palette_tray_->visible());
+}
+
+// Verify taps on the palette tray button results in expected behaviour.
+TEST_F(PaletteTrayTest, PaletteTrayWorkflow) {
+  // Verify the palette tray button is not active, and the palette tray bubble
+  // is not shown initially.
+  EXPECT_FALSE(palette_tray_->is_active());
+  EXPECT_FALSE(test_api_->GetTrayBubbleWrapper());
+
+  // Verify that by tapping the palette tray button, the button will become
+  // active and the palette tray bubble will be open.
+  PerformTap();
+  EXPECT_TRUE(palette_tray_->is_active());
+  EXPECT_TRUE(test_api_->GetTrayBubbleWrapper());
+
+  // Verify that activating a mode tool will close the palette tray bubble, but
+  // leave the palette tray button active.
+  test_api_->GetPaletteToolManager()->ActivateTool(
+      PaletteToolId::LASER_POINTER);
+  EXPECT_TRUE(test_api_->GetPaletteToolManager()->IsToolActive(
+      PaletteToolId::LASER_POINTER));
+  EXPECT_TRUE(palette_tray_->is_active());
+  EXPECT_FALSE(test_api_->GetTrayBubbleWrapper());
+
+  // Verify that tapping the palette tray while a tool is active will deactivate
+  // the tool, and the palette tray button will not be active.
+  PerformTap();
+  EXPECT_FALSE(palette_tray_->is_active());
+  EXPECT_FALSE(test_api_->GetPaletteToolManager()->IsToolActive(
+      PaletteToolId::LASER_POINTER));
+
+  // Verify that activating a action tool will close the palette tray bubble and
+  // the palette tray button is will not be active.
+  PerformTap();
+  ASSERT_TRUE(test_api_->GetTrayBubbleWrapper());
+  test_api_->GetPaletteToolManager()->ActivateTool(
+      PaletteToolId::CAPTURE_SCREEN);
+  EXPECT_FALSE(test_api_->GetPaletteToolManager()->IsToolActive(
+      PaletteToolId::CAPTURE_SCREEN));
+  // Wait for the tray bubble widget to close.
+  RunAllPendingInMessageLoop();
+  EXPECT_FALSE(test_api_->GetTrayBubbleWrapper());
+  EXPECT_FALSE(palette_tray_->is_active());
+}
+
+}  // namespace ash
diff --git a/ash/wm/lock_action_handler_layout_manager.cc b/ash/wm/lock_action_handler_layout_manager.cc
index e8ced5aa..23f4eec 100644
--- a/ash/wm/lock_action_handler_layout_manager.cc
+++ b/ash/wm/lock_action_handler_layout_manager.cc
@@ -15,6 +15,7 @@
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/wm_event.h"
+#include "ui/wm/core/window_animations.h"
 
 namespace ash {
 
@@ -33,6 +34,9 @@
 
 void LockActionHandlerLayoutManager::OnWindowAddedToLayout(
     aura::Window* child) {
+  ::wm::SetWindowVisibilityAnimationType(
+      child, ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
+
   wm::WindowState* window_state =
       LockWindowState::SetLockWindowStateWithShelfExcluded(child);
   wm::WMEvent event(wm::WM_EVENT_ADDED_TO_WORKSPACE);
diff --git a/base/debug/activity_tracker.cc b/base/debug/activity_tracker.cc
index 3ff8928..cff1e47 100644
--- a/base/debug/activity_tracker.cc
+++ b/base/debug/activity_tracker.cc
@@ -49,7 +49,7 @@
 
 // An atomically incrementing number, used to check for recreations of objects
 // in the same memory space.
-StaticAtomicSequenceNumber g_next_id;
+AtomicSequenceNumber g_next_id;
 
 union ThreadRef {
   int64_t as_id;
diff --git a/base/lazy_instance_unittest.cc b/base/lazy_instance_unittest.cc
index ba18ddd..d126c5db 100644
--- a/base/lazy_instance_unittest.cc
+++ b/base/lazy_instance_unittest.cc
@@ -13,8 +13,8 @@
 
 namespace {
 
-base::StaticAtomicSequenceNumber constructed_seq_;
-base::StaticAtomicSequenceNumber destructed_seq_;
+base::AtomicSequenceNumber constructed_seq_;
+base::AtomicSequenceNumber destructed_seq_;
 
 class ConstructAndDestructLogger {
  public:
diff --git a/base/message_loop/message_loop_task_runner_unittest.cc b/base/message_loop/message_loop_task_runner_unittest.cc
index 5fa01f0..32017f1 100644
--- a/base/message_loop/message_loop_task_runner_unittest.cc
+++ b/base/message_loop/message_loop_task_runner_unittest.cc
@@ -89,7 +89,7 @@
 
   void BlockTaskThreadHelper() { thread_sync_.Wait(); }
 
-  static StaticAtomicSequenceNumber g_order;
+  static AtomicSequenceNumber g_order;
 
   std::unique_ptr<MessageLoop> current_loop_;
   Thread task_thread_;
@@ -98,7 +98,7 @@
   base::WaitableEvent thread_sync_;
 };
 
-StaticAtomicSequenceNumber MessageLoopTaskRunnerTest::g_order;
+AtomicSequenceNumber MessageLoopTaskRunnerTest::g_order;
 
 TEST_F(MessageLoopTaskRunnerTest, PostTaskAndReply_Basic) {
   MessageLoop* task_run_on = NULL;
diff --git a/base/os_compat_android.h b/base/os_compat_android.h
index 0f254449..bfdf2c8 100644
--- a/base/os_compat_android.h
+++ b/base/os_compat_android.h
@@ -25,4 +25,8 @@
   return flock(fd, cmd);
 }
 
+// In case __USE_FILE_OFFSET64 is not used, we need to call pwrite64() instead
+// of pwrite()
+#define pwrite(fd, buf, count, offset) pwrite64(fd, buf, count, offset)
+
 #endif  // BASE_OS_COMPAT_ANDROID_H_
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc
index 1991ff5..6e8370e 100644
--- a/base/profiler/stack_sampling_profiler.cc
+++ b/base/profiler/stack_sampling_profiler.cc
@@ -179,7 +179,7 @@
     CallStackProfiles profiles;
 
     // Sequence number for generating new profiler ids.
-    static StaticAtomicSequenceNumber next_profiler_id;
+    static AtomicSequenceNumber next_profiler_id;
   };
 
   // Gets the single instance of this class.
@@ -365,7 +365,7 @@
   event->Signal();
 }
 
-StaticAtomicSequenceNumber
+AtomicSequenceNumber
     StackSamplingProfiler::SamplingThread::CollectionContext::next_profiler_id;
 
 StackSamplingProfiler::SamplingThread::SamplingThread()
diff --git a/base/sequence_token.cc b/base/sequence_token.cc
index 264e3b6..0bf2b44 100644
--- a/base/sequence_token.cc
+++ b/base/sequence_token.cc
@@ -13,9 +13,9 @@
 
 namespace {
 
-base::StaticAtomicSequenceNumber g_sequence_token_generator;
+base::AtomicSequenceNumber g_sequence_token_generator;
 
-base::StaticAtomicSequenceNumber g_task_token_generator;
+base::AtomicSequenceNumber g_task_token_generator;
 
 LazyInstance<ThreadLocalPointer<const SequenceToken>>::Leaky
     tls_current_sequence_token = LAZY_INSTANCE_INITIALIZER;
diff --git a/base/task_scheduler/scheduler_worker.cc b/base/task_scheduler/scheduler_worker.cc
index 26033d1b..07353443 100644
--- a/base/task_scheduler/scheduler_worker.cc
+++ b/base/task_scheduler/scheduler_worker.cc
@@ -15,7 +15,6 @@
 #if defined(OS_MACOSX)
 #include "base/mac/scoped_nsautorelease_pool.h"
 #elif defined(OS_WIN)
-#include "base/win/com_init_check_hook.h"
 #include "base/win/scoped_com_initializer.h"
 #endif
 
@@ -44,10 +43,7 @@
     // A SchedulerWorker starts out waiting for work.
     outer_->delegate_->WaitForWork(&wake_up_event_);
 
-    // When defined(COM_INIT_CHECK_HOOK_ENABLED), ignore
-    // SchedulerBackwardCompatibility::INIT_COM_STA to find incorrect uses of
-    // COM that should be running in a COM STA Task Runner.
-#if defined(OS_WIN) && !defined(COM_INIT_CHECK_HOOK_ENABLED)
+#if defined(OS_WIN)
     std::unique_ptr<win::ScopedCOMInitializer> com_initializer;
     if (outer_->backward_compatibility_ ==
         SchedulerBackwardCompatibility::INIT_COM_STA) {
diff --git a/base/task_scheduler/scheduler_worker_unittest.cc b/base/task_scheduler/scheduler_worker_unittest.cc
index 4d22f59..ab5982fb2 100644
--- a/base/task_scheduler/scheduler_worker_unittest.cc
+++ b/base/task_scheduler/scheduler_worker_unittest.cc
@@ -30,8 +30,6 @@
 
 #if defined(OS_WIN)
 #include <objbase.h>
-
-#include "base/win/com_init_check_hook.h"
 #endif
 
 using testing::_;
@@ -933,13 +931,7 @@
 
   // The call to CoInitializeEx() should have returned S_FALSE to indicate that
   // the COM library was already initialized on the thread.
-  // See SchedulerWorker::Thread::ThreadMain for why we expect two different
-  // results here.
-#if defined(COM_INIT_CHECK_HOOK_ENABLED)
-  EXPECT_EQ(S_OK, delegate_raw->coinitialize_hresult());
-#else
   EXPECT_EQ(S_FALSE, delegate_raw->coinitialize_hresult());
-#endif
 
   worker->JoinForTesting();
 }
diff --git a/base/threading/sequence_local_storage_slot.cc b/base/threading/sequence_local_storage_slot.cc
index df1c131..b7db40b 100644
--- a/base/threading/sequence_local_storage_slot.cc
+++ b/base/threading/sequence_local_storage_slot.cc
@@ -13,7 +13,7 @@
 namespace internal {
 
 namespace {
-StaticAtomicSequenceNumber g_sequence_local_storage_slot_generator;
+AtomicSequenceNumber g_sequence_local_storage_slot_generator;
 }  // namespace
 
 int GetNextSequenceLocalStorageSlotNumber() {
diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc
index 101058e..43f7921 100644
--- a/base/threading/sequenced_worker_pool.cc
+++ b/base/threading/sequenced_worker_pool.cc
@@ -476,7 +476,7 @@
   // only does threadsafe increment operations, you do not need to hold the
   // lock. This is class-static to make SequenceTokens issued by
   // GetSequenceToken unique across SequencedWorkerPool instances.
-  static base::StaticAtomicSequenceNumber g_last_sequence_number_;
+  static base::AtomicSequenceNumber g_last_sequence_number_;
 
   // This lock protects |everything in this class|. Do not read or modify
   // anything without holding this lock. Do not block while holding this
@@ -675,7 +675,7 @@
 // static
 SequencedWorkerPool::SequenceToken
 SequencedWorkerPool::Inner::GetSequenceToken() {
-  // Need to add one because StaticAtomicSequenceNumber starts at zero, which
+  // Need to add one because AtomicSequenceNumber starts at zero, which
   // is used as a sentinel value in SequenceTokens.
   return SequenceToken(g_last_sequence_number_.GetNext() + 1);
 }
@@ -1420,8 +1420,7 @@
          blocking_shutdown_pending_task_count_ == 0;
 }
 
-base::StaticAtomicSequenceNumber
-SequencedWorkerPool::Inner::g_last_sequence_number_;
+base::AtomicSequenceNumber SequencedWorkerPool::Inner::g_last_sequence_number_;
 
 // SequencedWorkerPool --------------------------------------------------------
 
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index e1b72be0..011a5b2 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -72,7 +72,7 @@
   enable_frame_pointers = true
 } else if (is_win) {
   # 64-bit Windows ABI doesn't support frame pointers.
-  if (target_cpu == "x64") {
+  if (current_cpu == "x64") {
     enable_frame_pointers = false
   } else {
     enable_frame_pointers = true
@@ -83,9 +83,9 @@
   # 32-bit builds (https://bugs.llvm.org/show_bug.cgi?id=18505) so disable them
   # there to avoid the unnecessary overhead.
   enable_frame_pointers = current_cpu != "arm"
-} else if (current_cpu == "arm64") {
+} else if (is_android) {
   # Ensure that stacks from arm64 crash dumps are usable (crbug.com/391706).
-  enable_frame_pointers = true
+  enable_frame_pointers = current_cpu == "arm64"
 } else {
   # Explicitly ask for frame pointers, otherwise:
   # * Stacks may be missing for sanitizer and profiling builds.
diff --git a/cc/animation/animation_id_provider.cc b/cc/animation/animation_id_provider.cc
index 9c87d2049..8d9d62f 100644
--- a/cc/animation/animation_id_provider.cc
+++ b/cc/animation/animation_id_provider.cc
@@ -7,10 +7,10 @@
 
 namespace cc {
 
-base::StaticAtomicSequenceNumber g_next_animation_id;
-base::StaticAtomicSequenceNumber g_next_group_id;
-base::StaticAtomicSequenceNumber g_next_timeline_id;
-base::StaticAtomicSequenceNumber g_next_player_id;
+base::AtomicSequenceNumber g_next_animation_id;
+base::AtomicSequenceNumber g_next_group_id;
+base::AtomicSequenceNumber g_next_timeline_id;
+base::AtomicSequenceNumber g_next_player_id;
 
 int AnimationIdProvider::NextAnimationId() {
   // Animation IDs start from 1.
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 5ce95a85..99b93f9f 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -37,7 +37,7 @@
 
 namespace cc {
 
-base::StaticAtomicSequenceNumber g_next_layer_id;
+base::AtomicSequenceNumber g_next_layer_id;
 
 Layer::Inputs::Inputs(int layer_id)
     : layer_id(layer_id),
diff --git a/cc/paint/paint_image.cc b/cc/paint/paint_image.cc
index d751b47..493e2a6 100644
--- a/cc/paint/paint_image.cc
+++ b/cc/paint/paint_image.cc
@@ -7,7 +7,7 @@
 
 namespace cc {
 namespace {
-base::StaticAtomicSequenceNumber s_next_id_;
+base::AtomicSequenceNumber s_next_id_;
 }
 
 PaintImage::PaintImage() = default;
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index bc9b168..91330124 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -175,7 +175,7 @@
 
 // Generates process-unique IDs to use for tracing a ResourceProvider's
 // resources.
-base::StaticAtomicSequenceNumber g_next_resource_provider_tracing_id;
+base::AtomicSequenceNumber g_next_resource_provider_tracing_id;
 
 }  // namespace
 
diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc
index 4b7fe01..148c35bf 100644
--- a/cc/scheduler/begin_frame_source.cc
+++ b/cc/scheduler/begin_frame_source.cc
@@ -61,7 +61,7 @@
 
 // BeginFrameSource -------------------------------------------------------
 namespace {
-static base::StaticAtomicSequenceNumber g_next_source_id;
+static base::AtomicSequenceNumber g_next_source_id;
 }  // namespace
 
 BeginFrameSource::BeginFrameSource() : source_id_(g_next_source_id.GetNext()) {}
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 3ec934d..29d7f07 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -59,7 +59,7 @@
 #include "ui/gfx/geometry/vector2d_conversions.h"
 
 namespace {
-static base::StaticAtomicSequenceNumber s_layer_tree_host_sequence_number;
+static base::AtomicSequenceNumber s_layer_tree_host_sequence_number;
 }
 
 namespace cc {
diff --git a/chrome/VERSION b/chrome/VERSION
index 8105445..338dcf56 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=61
 MINOR=0
-BUILD=3162
+BUILD=3163
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
index 52bec84..e60a9ff6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
@@ -19,6 +19,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.firstrun.FirstRunStatus;
+import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.preferences.datareduction.DataReductionProxyUma;
 import org.chromium.chrome.browser.search_engines.TemplateUrlService;
@@ -529,7 +530,8 @@
             final boolean isSearchByImageAvailable = isSrcDownloadableScheme
                     && templateUrlServiceInstance.isLoaded()
                     && templateUrlServiceInstance.isSearchByImageAvailable()
-                    && templateUrlServiceInstance.getDefaultSearchEngineTemplateUrl() != null;
+                    && templateUrlServiceInstance.getDefaultSearchEngineTemplateUrl() != null
+                    && !LocaleManager.getInstance().needToCheckForSearchEnginePromo();
 
             if (!isSearchByImageAvailable) {
                 disabledOptions.add(ChromeContextMenuItem.SEARCH_BY_IMAGE);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
index 25ad24ac9a..a316fba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
@@ -32,6 +32,7 @@
 import org.chromium.chrome.browser.search_engines.TemplateUrlService;
 import org.chromium.chrome.browser.searchwidget.SearchWidgetProvider;
 import org.chromium.chrome.browser.util.IntentUtils;
+import org.chromium.ui.base.LocalizationUtils;
 
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Constructor;
@@ -665,7 +666,8 @@
 
     @Override
     public void showInfoPage(int url) {
-        CustomTabActivity.showInfoPage(this, getString(url));
+        CustomTabActivity.showInfoPage(
+                this, LocalizationUtils.substituteLocalePlaceholder(getString(url)));
     }
 
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java
index 1292e346..9fe3fa6e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/LightweightFirstRunActivity.java
@@ -17,6 +17,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
+import org.chromium.ui.base.LocalizationUtils;
 import org.chromium.ui.text.NoUnderlineClickableSpan;
 import org.chromium.ui.text.SpanApplier;
 import org.chromium.ui.text.SpanApplier.SpanInfo;
@@ -39,14 +40,16 @@
             @Override
             public void onClick(View widget) {
                 CustomTabActivity.showInfoPage(LightweightFirstRunActivity.this,
-                        getString(R.string.chrome_terms_of_service_url));
+                        LocalizationUtils.substituteLocalePlaceholder(
+                                getString(R.string.chrome_terms_of_service_url)));
             }
         };
         NoUnderlineClickableSpan clickablePrivacySpan = new NoUnderlineClickableSpan() {
             @Override
             public void onClick(View widget) {
                 CustomTabActivity.showInfoPage(LightweightFirstRunActivity.this,
-                        getString(R.string.chrome_privacy_notice_url));
+                        LocalizationUtils.substituteLocalePlaceholder(
+                                getString(R.string.chrome_privacy_notice_url)));
             }
         };
         ((TextView) findViewById(R.id.lightweight_fre_tos_and_privacy))
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/HyperlinkPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/HyperlinkPreference.java
index ff536fd..c4f7e14 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/HyperlinkPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/HyperlinkPreference.java
@@ -14,6 +14,7 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
+import org.chromium.ui.base.LocalizationUtils;
 
 /**
  * A preference that navigates to an URL.
@@ -36,7 +37,8 @@
 
     @Override
     protected void onClick() {
-        CustomTabActivity.showInfoPage(getContext(), getContext().getString(mUrlResId));
+        CustomTabActivity.showInfoPage(getContext(),
+                LocalizationUtils.substituteLocalePlaceholder(getContext().getString(mUrlResId)));
     }
 
     @Override
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 3b704f4..4a4b99e 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1204,13 +1204,13 @@
         Chrome Privacy Notice
       </message>
       <message name="IDS_CHROME_PRIVACY_NOTICE_URL" desc="URL for the Chrome privacy notice" translateable="false">
-        https://www.google.com/intl/[GRITLANGCODE]/chrome/browser/privacy/
+        https://www.google.com/intl/$LOCALE/chrome/browser/privacy/
       </message>
       <message name="IDS_CHROME_TERMS_OF_SERVICE_URL" desc="URL for Google Chrome Terms of Service" translateable="false">
-        https://www.google.com/intl/[GRITLANGCODE]/chrome/browser/privacy/eula_text.html
+        https://www.google.com/intl/$LOCALE/chrome/browser/privacy/eula_text.html
       </message>
       <message name="IDS_FAMILY_LINK_PRIVACY_POLICY_URL" desc="URL for the Family Link privacy policy" translateable="false">
-        https://families.google.com/intl/[GRITLANGCODE]/familylink/privacy/child-policy/
+        https://families.google.com/intl/$LOCALE/familylink/privacy/child-policy/
       </message>
 
       <!-- JavaScript dialogs -->
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index 9b5f880..fbed099 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -382,7 +382,10 @@
   }
 }
 
-chrome_packaged_services = [ ":chrome_manifest" ]
+chrome_packaged_services = [
+  ":chrome_manifest",
+  "//services/preferences:local_state_manifest",
+]
 
 if (enable_basic_printing || enable_print_preview) {
   chrome_packaged_services +=
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 92c0afb..151f9dc4 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -2176,6 +2176,15 @@
   <message name="IDS_SETTINGS_SITE_SETTINGS_SITE_URL" desc="Label for site URL text entry in site settings.">
     Site URL
   </message>
+  <message name="IDS_SETTINGS_SITE_SETTINGS_ASK_DEFAULT_MENU" desc="Label for the default menu item to ask for permission for a particular site.">
+    Ask (default)
+  </message>
+  <message name="IDS_SETTINGS_SITE_SETTINGS_ALLOW_DEFAULT_MENU" desc="Label for the default menu item to allow a permission for a particular site.">
+    Allow (default)
+  </message>
+  <message name="IDS_SETTINGS_SITE_SETTINGS_BLOCK_DEFAULT_MENU" desc="Label for the default menu item to block a permission for a particular site.">
+    Block (default)
+  </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_ALLOW_MENU" desc="Label for the menu item to allow permission for a particular site.">
     Allow
   </message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index b280ee16..81bb94a 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1398,12 +1398,12 @@
      flag_descriptions::kAshEnableUnifiedDesktopName,
      flag_descriptions::kAshEnableUnifiedDesktopDescription, kOsCrOS,
      SINGLE_VALUE_TYPE(switches::kEnableUnifiedDesktop)},
-    {"enable-easy-unlock-bluetooth-low-energy-detection",
+    {"disable-easy-unlock-bluetooth-low-energy-detection",
      flag_descriptions::kEasyUnlockBluetoothLowEnergyDiscoveryName,
      flag_descriptions::kEasyUnlockBluetoothLowEnergyDiscoveryDescription,
      kOsCrOS,
-     SINGLE_VALUE_TYPE(
-         proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)},
+     SINGLE_DISABLE_VALUE_TYPE(
+         proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)},
     {"spurious-power-button-window",
      flag_descriptions::kSpuriousPowerButtonWindowName,
      flag_descriptions::kSpuriousPowerButtonWindowDescription, kOsCrOS,
diff --git a/chrome/browser/android/history_report/delta_file_backend_leveldb.cc b/chrome/browser/android/history_report/delta_file_backend_leveldb.cc
index 1ded0791c..4dff7767 100644
--- a/chrome/browser/android/history_report/delta_file_backend_leveldb.cc
+++ b/chrome/browser/android/history_report/delta_file_backend_leveldb.cc
@@ -12,6 +12,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/android/history_report/delta_file_commons.h"
+#include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/src/include/leveldb/comparator.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/iterator.h"
@@ -95,16 +96,14 @@
   options.max_open_files = 0;  // Use minimum number of files.
   options.comparator = leveldb_cmp_.get();
   std::string path = path_.value();
-  leveldb::DB* db = NULL;
-  leveldb::Status status = leveldb::DB::Open(options, path, &db);
+  leveldb::Status status = leveldb_env::OpenDB(options, path, &db_);
   if (status.IsCorruption()) {
     LOG(WARNING) << "Deleting possibly-corrupt database";
     base::DeleteFile(path_, true);
-    status = leveldb::DB::Open(options, path, &db);
+    status = leveldb_env::OpenDB(options, path, &db_);
   }
   if (status.ok()) {
-    CHECK(db);
-    db_.reset(db);
+    CHECK(db_);
     return true;
   }
   LOG(WARNING) << "Unable to open " << path_.value() << ": "
diff --git a/chrome/browser/android/history_report/usage_reports_buffer_backend.cc b/chrome/browser/android/history_report/usage_reports_buffer_backend.cc
index c8214a0..6a1aa49a 100644
--- a/chrome/browser/android/history_report/usage_reports_buffer_backend.cc
+++ b/chrome/browser/android/history_report/usage_reports_buffer_backend.cc
@@ -37,19 +37,17 @@
   options.create_if_missing = true;
   options.max_open_files = 0;  // Use minimum number of files.
   std::string path = db_file_name_.value();
-  leveldb::DB* db = NULL;
-  leveldb::Status status = leveldb::DB::Open(options, path, &db);
+  leveldb::Status status = leveldb_env::OpenDB(options, path, &db_);
   UMA_HISTOGRAM_ENUMERATION("LevelDB.Open.UsageReportsBufferBackend",
                             leveldb_env::GetLevelDBStatusUMAValue(status),
                             leveldb_env::LEVELDB_STATUS_MAX);
   if (status.IsCorruption()) {
     LOG(ERROR) << "Deleting corrupt database";
     base::DeleteFile(db_file_name_, true);
-    status = leveldb::DB::Open(options, path, &db);
+    status = leveldb_env::OpenDB(options, path, &db_);
   }
   if (status.ok()) {
-    CHECK(db);
-    db_.reset(db);
+    CHECK(db_);
     return true;
   }
   LOG(WARNING) << "Unable to open " << path << ": "
diff --git a/chrome/browser/autocomplete/search_provider_unittest.cc b/chrome/browser/autocomplete/search_provider_unittest.cc
index 3a3ca7e..8f46b5f 100644
--- a/chrome/browser/autocomplete/search_provider_unittest.cc
+++ b/chrome/browser/autocomplete/search_provider_unittest.cc
@@ -3627,33 +3627,39 @@
       base::string16(), metrics::OmniboxEventProto::INVALID_SPEC, false, true,
       true, true, true, ChromeAutocompleteSchemeClassifier(&profile_));
 
-  // First, verify that without the warm-up feature enabled, the provider
-  // immediately terminates with no matches.
-  provider_->Start(input, false);
-  // RunUntilIdle so that SearchProvider has a chance to create the URLFetchers
-  // (if it wants to, which it shouldn't in this case).
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(provider_->done());
-  EXPECT_TRUE(provider_->matches().empty());
+  {
+    // First, verify that without the warm-up feature enabled, the provider
+    // immediately terminates with no matches.
+    base::test::ScopedFeatureList feature_list;
+    feature_list.InitAndDisableFeature(omnibox::kSearchProviderWarmUpOnFocus);
+    provider_->Start(input, false);
+    // RunUntilIdle so that SearchProvider has a chance to create the
+    // URLFetchers (if it wants to, which it shouldn't in this case).
+    base::RunLoop().RunUntilIdle();
+    EXPECT_TRUE(provider_->done());
+    EXPECT_TRUE(provider_->matches().empty());
+  }
 
-  // Then, check the behavior with the warm-up feature enabled.
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(omnibox::kSearchProviderWarmUpOnFocus);
-  provider_->Start(input, false);
-  // RunUntilIdle so that SearchProvider create the URLFetcher.
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(provider_->done());
-  EXPECT_TRUE(provider_->matches().empty());
-  // Make sure the default provider's suggest service was queried.
-  net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
-      SearchProvider::kDefaultProviderURLFetcherID);
-  EXPECT_TRUE(fetcher);
-  // Even if the fetcher returns results, we should still have no suggestions
-  // (though the provider should now be done).
-  fetcher->set_response_code(200);
-  fetcher->SetResponseString(R"(["",["a", "b"],[],[],{}])");
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
-  RunTillProviderDone();
-  EXPECT_TRUE(provider_->done());
-  EXPECT_TRUE(provider_->matches().empty());
+  {
+    // Then, check the behavior with the warm-up feature enabled.
+    base::test::ScopedFeatureList feature_list;
+    feature_list.InitAndEnableFeature(omnibox::kSearchProviderWarmUpOnFocus);
+    provider_->Start(input, false);
+    // RunUntilIdle so that SearchProvider create the URLFetcher.
+    base::RunLoop().RunUntilIdle();
+    EXPECT_FALSE(provider_->done());
+    EXPECT_TRUE(provider_->matches().empty());
+    // Make sure the default provider's suggest service was queried.
+    net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
+        SearchProvider::kDefaultProviderURLFetcherID);
+    EXPECT_TRUE(fetcher);
+    // Even if the fetcher returns results, we should still have no suggestions
+    // (though the provider should now be done).
+    fetcher->set_response_code(200);
+    fetcher->SetResponseString(R"(["",["a", "b"],[],[],{}])");
+    fetcher->delegate()->OnURLFetchComplete(fetcher);
+    RunTillProviderDone();
+    EXPECT_TRUE(provider_->done());
+    EXPECT_TRUE(provider_->matches().empty());
+  }
 }
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h
index 8b742dc..93dbdfe 100644
--- a/chrome/browser/browser_process.h
+++ b/chrome/browser/browser_process.h
@@ -100,6 +100,10 @@
 class PolicyService;
 }
 
+namespace prefs {
+class InProcessPrefServiceFactory;
+}
+
 namespace printing {
 class BackgroundPrintingManager;
 class PrintJobManager;
@@ -289,6 +293,8 @@
   // Returns the Physical Web data source.
   virtual physical_web::PhysicalWebDataSource* GetPhysicalWebDataSource() = 0;
 
+  virtual prefs::InProcessPrefServiceFactory* pref_service_factory() const = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(BrowserProcess);
 };
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 99bbf83..aa35aa5 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -129,6 +129,7 @@
 #include "net/url_request/url_request_context_getter.h"
 #include "ppapi/features/features.h"
 #include "printing/features/features.h"
+#include "services/preferences/public/cpp/in_process_service_factory.h"
 #include "ui/base/idle/idle.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/message_center/message_center.h"
@@ -226,7 +227,9 @@
       tearing_down_(false),
       download_status_updater_(new DownloadStatusUpdater),
       local_state_task_runner_(local_state_task_runner),
-      cached_default_web_client_state_(shell_integration::UNKNOWN_DEFAULT) {
+      cached_default_web_client_state_(shell_integration::UNKNOWN_DEFAULT),
+      pref_service_factory_(
+          base::MakeUnique<prefs::InProcessPrefServiceFactory>()) {
   g_browser_process = this;
   rappor::SetDefaultServiceAccessor(&GetBrowserRapporService);
   platform_part_.reset(new BrowserProcessPlatformPart());
@@ -821,6 +824,11 @@
 #endif
 }
 
+prefs::InProcessPrefServiceFactory* BrowserProcessImpl::pref_service_factory()
+    const {
+  return pref_service_factory_.get();
+}
+
 // static
 void BrowserProcessImpl::RegisterPrefs(PrefRegistrySimple* registry) {
   registry->RegisterBooleanPref(prefs::kDefaultBrowserSettingEnabled,
@@ -1030,9 +1038,11 @@
   // Register local state preferences.
   chrome::RegisterLocalState(pref_registry.get());
 
+  auto delegate = pref_service_factory_->CreateDelegate();
+  delegate->InitPrefRegistry(pref_registry.get());
   local_state_ = chrome_prefs::CreateLocalState(
       local_state_path, local_state_task_runner_.get(), policy_service(),
-      pref_registry, false);
+      pref_registry, false, std::move(delegate));
 
   pref_change_registrar_.Init(local_state_.get());
 
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index 890e5e9..a7d61321 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -158,6 +158,7 @@
   shell_integration::DefaultWebClientState CachedDefaultWebClientState()
       override;
   physical_web::PhysicalWebDataSource* GetPhysicalWebDataSource() override;
+  prefs::InProcessPrefServiceFactory* pref_service_factory() const override;
 
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
@@ -355,6 +356,8 @@
   std::unique_ptr<physical_web::PhysicalWebDataSource>
       physical_web_data_source_;
 
+  std::unique_ptr<prefs::InProcessPrefServiceFactory> pref_service_factory_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(BrowserProcessImpl);
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 5641f77..84a242f 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -381,7 +381,7 @@
       std::unique_ptr<PrefService> parent_local_state(
           chrome_prefs::CreateLocalState(
               parent_profile, local_state_task_runner,
-              g_browser_process->policy_service(), registry, false));
+              g_browser_process->policy_service(), registry, false, nullptr));
       registry->RegisterStringPref(prefs::kApplicationLocale, std::string());
       // Right now, we only inherit the locale setting from the parent profile.
       local_state->SetString(
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 5453757..91ec579 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -212,6 +212,8 @@
 #include "ppapi/features/features.h"
 #include "ppapi/host/ppapi_host.h"
 #include "printing/features/features.h"
+#include "services/preferences/public/cpp/in_process_service_factory.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
 #include "storage/browser/fileapi/external_mount_points.h"
 #include "third_party/WebKit/public/platform/modules/installedapp/installed_app_provider.mojom.h"
 #include "third_party/WebKit/public/platform/modules/webshare/webshare.mojom.h"
@@ -2967,6 +2969,14 @@
 
 void ChromeContentBrowserClient::RegisterInProcessServices(
     StaticServiceMap* services) {
+  if (g_browser_process->pref_service_factory()) {
+    service_manager::EmbeddedServiceInfo info;
+    info.factory =
+        g_browser_process->pref_service_factory()->CreatePrefServiceFactory();
+    info.task_runner = base::ThreadTaskRunnerHandle::Get();
+    services->insert(
+        std::make_pair(prefs::mojom::kLocalStateServiceName, info));
+  }
 #if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS)
   service_manager::EmbeddedServiceInfo info;
   info.factory = base::Bind(&media::CreateMediaService);
diff --git a/chrome/browser/chromeos/arc/arc_service_launcher.cc b/chrome/browser/chromeos/arc/arc_service_launcher.cc
index f2444f7a..87003f48 100644
--- a/chrome/browser/chromeos/arc/arc_service_launcher.cc
+++ b/chrome/browser/chromeos/arc/arc_service_launcher.cc
@@ -62,13 +62,17 @@
 
 }  // namespace
 
-ArcServiceLauncher::ArcServiceLauncher() {
+ArcServiceLauncher::ArcServiceLauncher()
+    : arc_service_manager_(base::MakeUnique<ArcServiceManager>()),
+      arc_session_manager_(base::MakeUnique<ArcSessionManager>(
+          base::MakeUnique<ArcSessionRunner>(
+              base::Bind(ArcSession::Create,
+                         arc_service_manager_->arc_bridge_service())))) {
   DCHECK(g_arc_service_launcher == nullptr);
   g_arc_service_launcher = this;
 }
 
 ArcServiceLauncher::~ArcServiceLauncher() {
-  DCHECK(!arc_service_manager_);
   DCHECK_EQ(g_arc_service_launcher, this);
   g_arc_service_launcher = nullptr;
 }
@@ -78,17 +82,7 @@
   return g_arc_service_launcher;
 }
 
-void ArcServiceLauncher::Initialize() {
-  arc_service_manager_ = base::MakeUnique<ArcServiceManager>();
-  arc_session_manager_ = base::MakeUnique<ArcSessionManager>(
-      base::MakeUnique<ArcSessionRunner>(base::Bind(
-          ArcSession::Create, arc_service_manager_->arc_bridge_service())));
-}
-
 void ArcServiceLauncher::MaybeSetProfile(Profile* profile) {
-  DCHECK(arc_service_manager_);
-  DCHECK(arc_session_manager_);
-
   if (!IsArcAllowedForProfile(profile))
     return;
 
@@ -173,12 +167,23 @@
 }
 
 void ArcServiceLauncher::Shutdown() {
-  // Destroy in the reverse order of the initialization.
   arc_play_store_enabled_preference_handler_.reset();
-  if (arc_service_manager_)
-    arc_service_manager_->Shutdown();
+  arc_service_manager_->Shutdown();
+  arc_session_manager_->Shutdown();
+}
+
+void ArcServiceLauncher::ResetForTesting() {
+  // First destroy the internal states, then re-initialize them.
+  // These are for workaround of singletonness DCHECK in their ctors/dtors.
+  Shutdown();
   arc_session_manager_.reset();
-  arc_service_manager_.reset();
+
+  // No recreation of arc_service_manager. Pointers to its ArcBridgeService
+  // may be referred from existing KeyedService, so destoying it would cause
+  // unexpected behavior, specifically on test teardown.
+  arc_session_manager_ = base::MakeUnique<ArcSessionManager>(
+      base::MakeUnique<ArcSessionRunner>(base::Bind(
+          ArcSession::Create, arc_service_manager_->arc_bridge_service())));
 }
 
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/arc_service_launcher.h b/chrome/browser/chromeos/arc/arc_service_launcher.h
index e6997fc..93ab8fd 100644
--- a/chrome/browser/chromeos/arc/arc_service_launcher.h
+++ b/chrome/browser/chromeos/arc/arc_service_launcher.h
@@ -26,13 +26,6 @@
   // Returns a global instance.
   static ArcServiceLauncher* Get();
 
-  // Called before the main MessageLooop starts.
-  void Initialize();
-
-  // Called after the main MessageLoop stops, but before the Profile is
-  // destroyed.
-  void Shutdown();
-
   // Called just before most of BrowserContextKeyedService instance creation.
   // Set the given |profile| to ArcSessionManager, if the profile is allowed
   // to use ARC.
@@ -41,6 +34,16 @@
   // Called when the main profile is initialized after user logs in.
   void OnPrimaryUserProfilePrepared(Profile* profile);
 
+  // Called after the main MessageLoop stops, and before the Profile is
+  // destroyed.
+  void Shutdown();
+
+  // Resets internal state for testing. Specifically this needs to be
+  // called if other profile needs to be used in the tests. In that case,
+  // following this call, MaybeSetProfile() and
+  // OnPrimaryUserProfilePrepared() should be called.
+  void ResetForTesting();
+
  private:
   std::unique_ptr<ArcServiceManager> arc_service_manager_;
   std::unique_ptr<ArcSessionManager> arc_session_manager_;
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc
index 5b29c12..0a2942bf 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -459,6 +459,7 @@
     support_host_.reset();
   }
   context_.reset();
+  pai_starter_.reset();
   profile_ = nullptr;
   state_ = State::NOT_INITIALIZED;
   if (scoped_opt_in_tracker_) {
diff --git a/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc b/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc
index 393ec700..eb55871e 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc
@@ -125,8 +125,7 @@
     user_manager_enabler_.reset(new chromeos::ScopedUserManagerEnabler(
         new chromeos::FakeChromeUserManager));
     // Init ArcSessionManager for testing.
-    ArcServiceLauncher::Get()->Shutdown();
-    ArcServiceLauncher::Get()->Initialize();
+    ArcServiceLauncher::Get()->ResetForTesting();
     ArcSessionManager::DisableUIForTesting();
     ArcAuthNotification::DisableForTesting();
     ArcSessionManager::EnableCheckAndroidManagementForTesting();
@@ -183,6 +182,7 @@
     // TODO(hidehiko): Think about a way to test the code cleanly.
     ArcServiceLauncher::Get()->Shutdown();
     profile_.reset();
+    base::RunLoop().RunUntilIdle();
     user_manager_enabler_.reset();
     test_server_.reset();
     chromeos::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(false);
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
index 2889dcd..9e7190a8 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
@@ -93,8 +93,7 @@
         base::MakeUnique<chromeos::ScopedUserManagerEnabler>(
             new chromeos::FakeChromeUserManager());
     // Init ArcSessionManager for testing.
-    ArcServiceLauncher::Get()->Shutdown();
-    ArcServiceLauncher::Get()->Initialize();
+    ArcServiceLauncher::Get()->ResetForTesting();
     ArcSessionManager::DisableUIForTesting();
     ArcAuthNotification::DisableForTesting();
     ArcSessionManager::EnableCheckAndroidManagementForTesting();
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 1397e3db..ab16f4c 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -633,8 +633,7 @@
   network_throttling_observer_.reset(
       new NetworkThrottlingObserver(g_browser_process->local_state()));
 
-  arc_service_launcher_.reset(new arc::ArcServiceLauncher());
-  arc_service_launcher_->Initialize();
+  arc_service_launcher_ = base::MakeUnique<arc::ArcServiceLauncher>();
 
   chromeos::ResourceReporter::GetInstance()->StartMonitoring(
       task_manager::TaskManagerInterface::GetTaskManager());
@@ -1113,6 +1112,12 @@
   // closed above.
   arc_kiosk_app_manager_.reset();
 
+  // All ARC related modules should have been shut down by this point, so
+  // destroy ARC.
+  // Specifically, this should be done after Profile destruction run in
+  // ChromeBrowserMainPartsLinux::PostMainMessageLoopRun().
+  arc_service_launcher_.reset();
+
   if (!ash_util::IsRunningInMash())
     AccessibilityManager::Shutdown();
 
diff --git a/chrome/browser/chromeos/login/easy_unlock/bootstrap_browsertest.cc b/chrome/browser/chromeos/login/easy_unlock/bootstrap_browsertest.cc
index 43d29d0..5210658 100644
--- a/chrome/browser/chromeos/login/easy_unlock/bootstrap_browsertest.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/bootstrap_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include <string>
 
+#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/path_service.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -68,6 +69,9 @@
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         proximity_auth::switches::kForceLoadEasyUnlockAppInTests);
 
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery);
+
     const GURL& server_url = embedded_test_server()->base_url();
     GURL::Replacements replace_host;
     replace_host.SetHostStr("eafe");
diff --git a/chrome/browser/component_updater/recovery_improved_component_installer.cc b/chrome/browser/component_updater/recovery_improved_component_installer.cc
index 3fdf6652..f4ebd95f 100644
--- a/chrome/browser/component_updater/recovery_improved_component_installer.cc
+++ b/chrome/browser/component_updater/recovery_improved_component_installer.cc
@@ -16,11 +16,11 @@
 namespace component_updater {
 
 // The SHA256 of the SubjectPublicKeyInfo used to sign the component CRX.
-// The component id is: iddcipcljjhfegcfaaaapdilddpplalp
+// The component id is: ihnlcenocehgdaegdmhbidjhnhdchfmm
 constexpr uint8_t kPublicKeySHA256[32] = {
-    0x83, 0x32, 0x8f, 0x2b, 0x99, 0x75, 0x46, 0x25, 0x00, 0x00, 0xf3,
-    0x8b, 0x33, 0xff, 0xb0, 0xbf, 0xea, 0xea, 0x19, 0xb3, 0x38, 0xfb,
-    0xdc, 0xb3, 0x28, 0x90, 0x5f, 0xe2, 0xbe, 0x28, 0x89, 0x11};
+    0x87, 0xdb, 0x24, 0xde, 0x24, 0x76, 0x30, 0x46, 0x3c, 0x71, 0x83,
+    0x97, 0xd7, 0x32, 0x75, 0xcc, 0xd5, 0x7f, 0xec, 0x09, 0x60, 0x6d,
+    0x20, 0xc3, 0x81, 0xd7, 0xce, 0x7b, 0x10, 0x15, 0x44, 0xd1};
 
 RecoveryImprovedInstallerTraits::RecoveryImprovedInstallerTraits(
     PrefService* prefs)
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
index 8d9dd197e..f239137 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
@@ -574,8 +574,8 @@
 
 ExtensionFunction::ResponseAction
 EasyUnlockPrivateGetPermitAccessFunction::Run() {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)) {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)) {
     return GetPermitAccessForExperiment();
   }
 
@@ -675,8 +675,8 @@
     devices.Append(device.ToValue());
 
   // Store the BLE device if we are trying out the BLE experiment.
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)) {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)) {
     EasyUnlockService::Get(profile)->SetRemoteBleDevices(devices);
   } else {
     EasyUnlockService::Get(profile)->SetRemoteDevices(devices);
@@ -696,8 +696,8 @@
 bool EasyUnlockPrivateGetRemoteDevicesFunction::RunAsync() {
   // Return the remote devices stored with the native CryptAuthDeviceManager if
   // we are trying out the BLE experiment.
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)) {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)) {
     ReturnDevicesForExperiment();
   } else {
     Profile* profile = Profile::FromBrowserContext(browser_context());
@@ -906,8 +906,8 @@
         EasyUnlockService::GetDeviceId(), account_id.GetUserEmail());
 
     user.ble_discovery_enabled =
-        base::CommandLine::ForCurrentProcess()->HasSwitch(
-            proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery);
+        !base::CommandLine::ForCurrentProcess()->HasSwitch(
+            proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery);
     users.push_back(std::move(user));
   }
   return RespondNow(
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc
index b4b40a72..7a1ad1de 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc
@@ -129,6 +129,9 @@
 
  protected:
   void SetUp() override {
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery);
+
     chromeos::DBusThreadManager::Initialize();
     bluez::BluezDBusManager::Initialize(
         chromeos::DBusThreadManager::Get()->GetSystemBus(),
@@ -563,43 +566,6 @@
 }
 
 // Checks that the chrome.easyUnlockPrivate.getRemoteDevices API returns the
-// natively synced devices if the kEnableBluetoothLowEnergyDiscovery switch is
-// set.
-TEST_F(EasyUnlockPrivateApiTest, GetRemoteDevicesExperimental) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery);
-  EasyUnlockServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-      profile(), &BuildTestEasyUnlockService);
-
-  scoped_refptr<TestableGetRemoteDevicesFunction> function(
-      new TestableGetRemoteDevicesFunction());
-  std::unique_ptr<base::Value> value(
-      extensions::api_test_utils::RunFunctionAndReturnSingleResult(
-          function.get(), "[]", profile()));
-  ASSERT_TRUE(value.get());
-  ASSERT_EQ(base::Value::Type::LIST, value->GetType());
-
-  base::ListValue* list_value = static_cast<base::ListValue*>(value.get());
-  EXPECT_EQ(2u, list_value->GetSize());
-
-  base::Value* remote_device1;
-  base::Value* remote_device2;
-  ASSERT_TRUE(list_value->Get(0, &remote_device1));
-  ASSERT_TRUE(list_value->Get(1, &remote_device2));
-  EXPECT_EQ(base::Value::Type::DICTIONARY, remote_device1->GetType());
-  EXPECT_EQ(base::Value::Type::DICTIONARY, remote_device2->GetType());
-
-  std::string name1, name2;
-  EXPECT_TRUE(static_cast<base::DictionaryValue*>(remote_device1)
-                  ->GetString("name", &name1));
-  EXPECT_TRUE(static_cast<base::DictionaryValue*>(remote_device2)
-                  ->GetString("name", &name2));
-
-  EXPECT_EQ("test phone 1", name1);
-  EXPECT_EQ("test phone 2", name2);
-}
-
-// Checks that the chrome.easyUnlockPrivate.getRemoteDevices API returns the
 // stored value if the kEnableBluetoothLowEnergyDiscovery switch is not set.
 TEST_F(EasyUnlockPrivateApiTest, GetRemoteDevicesNonExperimental) {
   EasyUnlockServiceFactory::GetInstance()->SetTestingFactoryAndUse(
@@ -618,32 +584,6 @@
 }
 
 // Checks that the chrome.easyUnlockPrivate.getPermitAccess API returns the
-// native permit access if the kEnableBluetoothLowEnergyDiscovery switch is
-// set.
-TEST_F(EasyUnlockPrivateApiTest, GetPermitAccessExperimental) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery);
-  EasyUnlockServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-      profile(), &BuildTestEasyUnlockService);
-
-  scoped_refptr<TestableGetPermitAccessFunction> function(
-      new TestableGetPermitAccessFunction());
-  std::unique_ptr<base::Value> value(
-      extensions::api_test_utils::RunFunctionAndReturnSingleResult(
-          function.get(), "[]", profile()));
-  ASSERT_TRUE(value);
-  ASSERT_EQ(base::Value::Type::DICTIONARY, value->GetType());
-  base::DictionaryValue* permit_access =
-      static_cast<base::DictionaryValue*>(value.get());
-
-  std::string user_public_key, user_private_key;
-  EXPECT_TRUE(permit_access->GetString("id", &user_public_key));
-  EXPECT_TRUE(permit_access->GetString("data", &user_private_key));
-  EXPECT_EQ("user public key", user_public_key);
-  EXPECT_EQ("user private key", user_private_key);
-}
-
-// Checks that the chrome.easyUnlockPrivate.getPermitAccess API returns the
 // stored value if the kEnableBluetoothLowEnergyDiscovery switch is not set.
 TEST_F(EasyUnlockPrivateApiTest, GetPermitAccessNonExperimental) {
   EasyUnlockServiceFactory::GetInstance()->SetTestingFactoryAndUse(
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
index c4c6fd7..a22d509 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
@@ -30,7 +30,7 @@
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/cryptohome/mock_async_method_caller.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
-#include "chromeos/dbus/mock_cryptohome_client.h"
+#include "chromeos/dbus/fake_cryptohome_client.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/account_id/account_id.h"
@@ -158,12 +158,6 @@
     extension_ = CreateExtension();
 
     // Set up the default behavior of mocks.
-    ON_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
-        .WillByDefault(WithArgs<3>(Invoke(FakeBoolDBusMethod(
-            chromeos::DBUS_METHOD_CALL_SUCCESS, false))));
-    ON_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
-        .WillByDefault(Invoke(FakeBoolDBusMethod(
-            chromeos::DBUS_METHOD_CALL_SUCCESS, true)));
     ON_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _, _))
         .WillByDefault(Invoke(RegisterKeyCallbackTrue));
     ON_CALL(mock_async_method_caller_,
@@ -219,7 +213,7 @@
         SetAuthenticatedAccountInfo("12345", kUserEmail);
   }
 
-  NiceMock<chromeos::MockCryptohomeClient> mock_cryptohome_client_;
+  chromeos::FakeCryptohomeClient cryptohome_client_;
   NiceMock<cryptohome::MockAsyncMethodCaller> mock_async_method_caller_;
   NiceMock<chromeos::attestation::MockAttestationFlow> mock_attestation_flow_;
   chromeos::ScopedCrosSettingsTestHelper settings_helper_;
@@ -253,7 +247,7 @@
   explicit EPKPChallengeMachineKeyTest(
       ProfileType profile_type = ProfileType::USER_PROFILE)
       : EPKPChallengeKeyTestBase(profile_type),
-        impl_(&mock_cryptohome_client_,
+        impl_(&cryptohome_client_,
               &mock_async_method_caller_,
               &mock_attestation_flow_,
               &stub_install_attributes_),
@@ -305,9 +299,7 @@
 }
 
 TEST_F(EPKPChallengeMachineKeyTest, DoesKeyExistDbusFailed) {
-  EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
-      .WillRepeatedly(WithArgs<3>(Invoke(FakeBoolDBusMethod(
-          chromeos::DBUS_METHOD_CALL_FAILURE, false))));
+  cryptohome_client_.set_tpm_attestation_does_key_exist_should_succeed(false);
 
   EXPECT_EQ(GetCertificateError(kDBusError),
             utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
@@ -331,9 +323,8 @@
 }
 
 TEST_F(EPKPChallengeMachineKeyTest, KeyExists) {
-  EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
-      .WillRepeatedly(WithArgs<3>(Invoke(FakeBoolDBusMethod(
-          chromeos::DBUS_METHOD_CALL_SUCCESS, true))));
+  cryptohome_client_.SetTpmAttestationDeviceCertificate("attest-ent-machine",
+                                                        std::string());
   // GetCertificate must not be called if the key exists.
   EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
       .Times(0);
@@ -342,18 +333,14 @@
 }
 
 TEST_F(EPKPChallengeMachineKeyTest, AttestationNotPrepared) {
-  EXPECT_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
-      .WillRepeatedly(Invoke(
-          FakeBoolDBusMethod(chromeos::DBUS_METHOD_CALL_SUCCESS, false)));
+  cryptohome_client_.set_tpm_attestation_is_prepared(false);
 
   EXPECT_EQ(GetCertificateError(kResetRequired),
             utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
 }
 
 TEST_F(EPKPChallengeMachineKeyTest, AttestationPreparedDbusFailed) {
-  EXPECT_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
-      .WillRepeatedly(
-          Invoke(FakeBoolDBusMethod(chromeos::DBUS_METHOD_CALL_FAILURE, true)));
+  cryptohome_client_.SetServiceIsAvailable(false);
 
   EXPECT_EQ(GetCertificateError(kDBusError),
             utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
@@ -405,7 +392,7 @@
   explicit EPKPChallengeUserKeyTest(
       ProfileType profile_type = ProfileType::USER_PROFILE)
       : EPKPChallengeKeyTestBase(profile_type),
-        impl_(&mock_cryptohome_client_,
+        impl_(&cryptohome_client_,
               &mock_async_method_caller_,
               &mock_attestation_flow_,
               &stub_install_attributes_),
@@ -465,9 +452,7 @@
 }
 
 TEST_F(EPKPChallengeUserKeyTest, DoesKeyExistDbusFailed) {
-  EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
-      .WillRepeatedly(WithArgs<3>(Invoke(FakeBoolDBusMethod(
-          chromeos::DBUS_METHOD_CALL_FAILURE, false))));
+  cryptohome_client_.set_tpm_attestation_does_key_exist_should_succeed(false);
 
   EXPECT_EQ(GetCertificateError(kDBusError),
             utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
@@ -499,9 +484,9 @@
 }
 
 TEST_F(EPKPChallengeUserKeyTest, KeyExists) {
-  EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _, _))
-      .WillRepeatedly(WithArgs<3>(Invoke(FakeBoolDBusMethod(
-          chromeos::DBUS_METHOD_CALL_SUCCESS, true))));
+  cryptohome_client_.SetTpmAttestationUserCertificate(
+      cryptohome::Identification(AccountId::FromUserEmail(kUserEmail)),
+      "attest-ent-user", std::string());
   // GetCertificate must not be called if the key exists.
   EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
       .Times(0);
@@ -557,18 +542,14 @@
 }
 
 TEST_F(EPKPChallengeUserKeyTest, AttestationNotPrepared) {
-  EXPECT_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
-      .WillRepeatedly(Invoke(FakeBoolDBusMethod(
-          chromeos::DBUS_METHOD_CALL_SUCCESS, false)));
+  cryptohome_client_.set_tpm_attestation_is_prepared(false);
 
   EXPECT_EQ(GetCertificateError(kResetRequired),
             utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
 }
 
 TEST_F(EPKPChallengeUserKeyTest, AttestationPreparedDbusFailed) {
-  EXPECT_CALL(mock_cryptohome_client_, TpmAttestationIsPrepared(_))
-      .WillRepeatedly(Invoke(FakeBoolDBusMethod(
-          chromeos::DBUS_METHOD_CALL_FAILURE, true)));
+  cryptohome_client_.SetServiceIsAvailable(false);
 
   EXPECT_EQ(GetCertificateError(kDBusError),
             utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 363854e..88c14c70 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -224,7 +224,7 @@
 const char kEasyUnlockBluetoothLowEnergyDiscoveryName[] =
     "Smart Lock Bluetooth Low Energy Discovery";
 const char kEasyUnlockBluetoothLowEnergyDiscoveryDescription[] =
-    "Enables a Smart Lock setting that allows Chromebook to discover phones "
+    "Disables a Smart Lock setting that allows Chromebook to discover phones "
     "over Bluetooth Low Energy in order to unlock the Chromebook when the "
     "phone is in its proximity.";
 
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc
index 68352c0..4022144 100644
--- a/chrome/browser/media/encrypted_media_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -73,6 +73,8 @@
 const char kExternalClearKeyVerifyCdmHostTestKeySystem[] =
     "org.chromium.externalclearkey.verifycdmhosttest";
 #endif
+const char kExternalClearKeyStorageIdTestKeySystem[] =
+    "org.chromium.externalclearkey.storageidtest";
 
 // Supported media types.
 const char kWebMVorbisAudioOnly[] = "audio/webm; codecs=\"vorbis\"";
@@ -834,4 +836,16 @@
 }
 #endif  // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
 
+IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, StorageIdTest) {
+  // TODO(jrummell): Support Storage ID in mojo CDM. See
+  // http://crbug.com/478960
+  if (IsUsingMojoCdm()) {
+    DVLOG(0) << "Skipping test; Not working with mojo CDM yet.";
+    return;
+  }
+
+  TestNonPlaybackCases(kExternalClearKeyStorageIdTestKeySystem,
+                       kUnitTestSuccess);
+}
+
 }  // namespace chrome
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index 015102b5..1abe721 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -62,6 +62,7 @@
 #include "components/history/core/browser/history_service.h"
 #include "components/metrics/call_stack_profile_metrics_provider.h"
 #include "components/metrics/drive_metrics_provider.h"
+#include "components/metrics/field_trials_provider.h"
 #include "components/metrics/file_metrics_provider.h"
 #include "components/metrics/gpu/gpu_metrics_provider.h"
 #include "components/metrics/metrics_log_uploader.h"
@@ -317,6 +318,9 @@
 
 const char ChromeMetricsServiceClient::kBrowserMetricsName[] = "BrowserMetrics";
 
+// UKM suffix for field trial recording.
+const char kUKMFieldTrialSuffix[] = "UKM";
+
 ChromeMetricsServiceClient::ChromeMetricsServiceClient(
     metrics::MetricsStateManager* state_manager)
     : metrics_state_manager_(state_manager),
@@ -770,6 +774,11 @@
       base::MakeUnique<metrics::NetworkMetricsProvider>(
           base::MakeUnique<metrics::NetworkQualityEstimatorProviderImpl>(
               g_browser_process->io_thread())));
+
+  // TODO(rkaplow): Support synthetic trials for UKM.
+  ukm_service_->RegisterMetricsProvider(
+      base::MakeUnique<variations::FieldTrialsProvider>(nullptr,
+                                                        kUKMFieldTrialSuffix));
 }
 
 bool ChromeMetricsServiceClient::ShouldIncludeProfilerDataInLog() {
diff --git a/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc b/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc
index 51ba299..268e2d6 100644
--- a/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc
+++ b/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc
@@ -22,11 +22,10 @@
 // static
 infobars::InfoBar* GroupedPermissionInfoBarDelegate::Create(
     const base::WeakPtr<PermissionPromptAndroid>& permission_prompt,
-    InfoBarService* infobar_service,
-    const GURL& requesting_origin) {
-  return infobar_service->AddInfoBar(base::MakeUnique<GroupedPermissionInfoBar>(
-      base::WrapUnique(new GroupedPermissionInfoBarDelegate(
-          permission_prompt, requesting_origin))));
+    InfoBarService* infobar_service) {
+  return infobar_service->AddInfoBar(
+      base::MakeUnique<GroupedPermissionInfoBar>(base::WrapUnique(
+          new GroupedPermissionInfoBarDelegate(permission_prompt))));
 }
 
 size_t GroupedPermissionInfoBarDelegate::PermissionCount() const {
@@ -80,11 +79,8 @@
 }
 
 GroupedPermissionInfoBarDelegate::GroupedPermissionInfoBarDelegate(
-    const base::WeakPtr<PermissionPromptAndroid>& permission_prompt,
-    const GURL& requesting_origin)
-    : requesting_origin_(requesting_origin),
-      persist_(true),
-      permission_prompt_(permission_prompt) {
+    const base::WeakPtr<PermissionPromptAndroid>& permission_prompt)
+    : persist_(true), permission_prompt_(permission_prompt) {
   DCHECK(permission_prompt);
 }
 
diff --git a/chrome/browser/permissions/grouped_permission_infobar_delegate_android.h b/chrome/browser/permissions/grouped_permission_infobar_delegate_android.h
index 5ed2657..751e5d2 100644
--- a/chrome/browser/permissions/grouped_permission_infobar_delegate_android.h
+++ b/chrome/browser/permissions/grouped_permission_infobar_delegate_android.h
@@ -26,8 +26,7 @@
 
   static infobars::InfoBar* Create(
       const base::WeakPtr<PermissionPromptAndroid>& permission_prompt,
-      InfoBarService* infobar_service,
-      const GURL& requesting_origin);
+      InfoBarService* infobar_service);
 
   bool persist() const { return persist_; }
   void set_persist(bool persist) { persist_ = persist; }
@@ -49,13 +48,9 @@
   void InfoBarDismissed() override;
   base::string16 GetLinkText() const override;
 
- protected:
-  bool GetAcceptState(size_t position);
-
  private:
   GroupedPermissionInfoBarDelegate(
-      const base::WeakPtr<PermissionPromptAndroid>& permission_prompt,
-      const GURL& requesting_origin);
+      const base::WeakPtr<PermissionPromptAndroid>& permission_prompt);
 
   // ConfirmInfoBarDelegate:
   InfoBarIdentifier GetIdentifier() const override;
@@ -67,7 +62,6 @@
   // InfoBarDelegate:
   bool EqualsDelegate(infobars::InfoBarDelegate* delegate) const override;
 
-  const GURL requesting_origin_;
   // Whether the accept/deny decision is persisted.
   bool persist_;
   base::WeakPtr<PermissionPromptAndroid> permission_prompt_;
diff --git a/chrome/browser/permissions/permission_prompt_android.cc b/chrome/browser/permissions/permission_prompt_android.cc
index 2bdb079..d7f88160 100644
--- a/chrome/browser/permissions/permission_prompt_android.cc
+++ b/chrome/browser/permissions/permission_prompt_android.cc
@@ -41,9 +41,8 @@
   if (!infobar_service)
     return;
 
-  GroupedPermissionInfoBarDelegate::Create(
-      weak_factory_.GetWeakPtr(), infobar_service,
-      delegate_->Requests()[0]->GetOrigin());
+  GroupedPermissionInfoBarDelegate::Create(weak_factory_.GetWeakPtr(),
+                                           infobar_service);
 }
 
 PermissionPromptAndroid::~PermissionPromptAndroid() {}
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 15be438..777bf68 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -821,7 +821,6 @@
     content::WebContents* web_contents =
         browser()->tab_strip_model()->GetActiveWebContents();
     content::TestNavigationObserver observer(web_contents);
-    chrome::FocusLocationBar(browser());
     LocationBar* location_bar = browser()->window()->GetLocationBar();
     ui_test_utils::SendToOmniboxAndSubmit(location_bar, "http://google.com/");
     OmniboxEditModel* model = location_bar->GetOmniboxView()->model();
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc
index e8a9387..bc4a2a7 100644
--- a/chrome/browser/prefs/chrome_pref_service_factory.cc
+++ b/chrome/browser/prefs/chrome_pref_service_factory.cc
@@ -438,7 +438,8 @@
     base::SequencedTaskRunner* pref_io_task_runner,
     policy::PolicyService* policy_service,
     const scoped_refptr<PrefRegistry>& pref_registry,
-    bool async) {
+    bool async,
+    std::unique_ptr<PrefValueStore::Delegate> delegate) {
   sync_preferences::PrefServiceSyncableFactory factory;
   PrepareFactory(&factory, pref_filename, policy_service,
                  NULL,  // supervised_user_settings
@@ -446,7 +447,7 @@
                                    std::unique_ptr<PrefFilter>()),
                  NULL,  // extension_prefs
                  async);
-  return factory.Create(pref_registry.get());
+  return factory.Create(pref_registry.get(), std::move(delegate));
 }
 
 std::unique_ptr<sync_preferences::PrefServiceSyncable> CreateProfilePrefs(
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.h b/chrome/browser/prefs/chrome_pref_service_factory.h
index 8edd77c..efa912d 100644
--- a/chrome/browser/prefs/chrome_pref_service_factory.h
+++ b/chrome/browser/prefs/chrome_pref_service_factory.h
@@ -69,7 +69,8 @@
     base::SequencedTaskRunner* pref_io_task_runner,
     policy::PolicyService* policy_service,
     const scoped_refptr<PrefRegistry>& pref_registry,
-    bool async);
+    bool async,
+    std::unique_ptr<PrefValueStore::Delegate> delegate);
 
 std::unique_ptr<sync_preferences::PrefServiceSyncable> CreateProfilePrefs(
     const base::FilePath& pref_filename,
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 9fe01f7..9ed6c49 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -15,6 +15,7 @@
 #include "chrome/common/pref_names.h"
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
@@ -68,6 +69,8 @@
   base::AutoLock lock(g_instances_lock.Get());
   g_instances.Get().insert(this);
 #endif  // DCHECK_IS_ON()
+
+  BrowserContextDependencyManager::GetInstance()->MarkBrowserContextLive(this);
 }
 
 Profile::~Profile() {
diff --git a/chrome/browser/resources/md_bookmarks/command_manager.js b/chrome/browser/resources/md_bookmarks/command_manager.js
index ce6ae6b1..dee208ef 100644
--- a/chrome/browser/resources/md_bookmarks/command_manager.js
+++ b/chrome/browser/resources/md_bookmarks/command_manager.js
@@ -89,7 +89,7 @@
       this.addShortcut_(Command.EDIT, 'F2', 'Enter');
       this.addShortcut_(Command.DELETE, 'Delete', 'Delete Backspace');
 
-      this.addShortcut_(Command.OPEN, 'Enter', 'Meta|ArrowDown Meta|o');
+      this.addShortcut_(Command.OPEN, 'Enter', 'Meta|o');
       this.addShortcut_(Command.OPEN_NEW_TAB, 'Ctrl|Enter', 'Meta|Enter');
       this.addShortcut_(Command.OPEN_NEW_WINDOW, 'Shift|Enter');
 
@@ -648,8 +648,10 @@
      */
     onKeydown_: function(e) {
       var selection = this.getState().selection.items;
-      if (e.target == document.body)
+      if (e.target == document.body &&
+          !bookmarks.DialogFocusManager.getInstance().hasOpenDialog()) {
         this.handleKeyEvent(e, selection);
+      }
     },
 
     /**
diff --git a/chrome/browser/resources/md_bookmarks/dialog_focus_manager.js b/chrome/browser/resources/md_bookmarks/dialog_focus_manager.js
index ac5d84e..98c0fd3 100644
--- a/chrome/browser/resources/md_bookmarks/dialog_focus_manager.js
+++ b/chrome/browser/resources/md_bookmarks/dialog_focus_manager.js
@@ -44,6 +44,13 @@
       showFn();
     },
 
+    /**
+     * @return {boolean} True if the document currently has an open dialog.
+     */
+    hasOpenDialog: function() {
+      return this.dialogs_.size > 0;
+    },
+
     /** @private */
     updatePreviousFocus_: function() {
       this.previousFocusElement_ = this.getFocusedElement_();
@@ -75,7 +82,7 @@
 
         assert(this.dialogs_.delete(dialog));
         // Focus the originally focused element if there are no more dialogs.
-        if (!this.dialogs_.size)
+        if (!this.hasOpenDialog())
           this.previousFocusElement_.focus();
 
         dialog.removeEventListener('close', closeListener);
diff --git a/chrome/browser/resources/md_bookmarks/item.js b/chrome/browser/resources/md_bookmarks/item.js
index d7103dc..99e210f 100644
--- a/chrome/browser/resources/md_bookmarks/item.js
+++ b/chrome/browser/resources/md_bookmarks/item.js
@@ -134,10 +134,11 @@
     // Ignore double clicks so that Ctrl double-clicking an item won't deselect
     // the item before opening.
     if (e.detail != 2) {
+      var addKey = cr.isMac ? e.metaKey : e.ctrlKey;
       this.dispatch(bookmarks.actions.selectItem(this.itemId, this.getState(), {
-        clear: !e.ctrlKey,
+        clear: !addKey,
         range: e.shiftKey,
-        toggle: e.ctrlKey && !e.shiftKey,
+        toggle: addKey && !e.shiftKey,
       }));
     }
     e.stopPropagation();
diff --git a/chrome/browser/resources/md_bookmarks/list.js b/chrome/browser/resources/md_bookmarks/list.js
index 7d772a19..0b14ed4 100644
--- a/chrome/browser/resources/md_bookmarks/list.js
+++ b/chrome/browser/resources/md_bookmarks/list.js
@@ -156,10 +156,11 @@
     var focusedIndex =
         this.getIndexForItemElement_(/** @type {HTMLElement} */ (e.target));
     var oldFocusedIndex = focusedIndex;
+    var cursorModifier = cr.isMac ? e.metaKey : e.ctrlKey;
     if (e.key == 'ArrowUp') {
       focusedIndex--;
       focusMoved = true;
-    } else if (e.key == 'ArrowDown' && !(cr.isMac && e.metaKey)) {
+    } else if (e.key == 'ArrowDown') {
       focusedIndex++;
       focusMoved = true;
       e.preventDefault();
@@ -169,7 +170,7 @@
     } else if (e.key == 'End') {
       focusedIndex = list.items.length - 1;
       focusMoved = true;
-    } else if (e.key == ' ' && e.ctrlKey) {
+    } else if (e.key == ' ' && cursorModifier) {
       this.dispatch(bookmarks.actions.selectItem(
           this.displayedIds_[focusedIndex], this.getState(), {
             clear: false,
@@ -184,7 +185,7 @@
       focusedIndex = Math.min(list.items.length - 1, Math.max(0, focusedIndex));
       list.focusItem(focusedIndex);
 
-      if (e.ctrlKey && !e.shiftKey) {
+      if (cursorModifier && !e.shiftKey) {
         this.dispatch(
             bookmarks.actions.updateAnchor(this.displayedIds_[focusedIndex]));
       } else {
@@ -197,7 +198,7 @@
         // If the focus moved from something other than a Ctrl + move event,
         // update the selection.
         var config = {
-          clear: !e.ctrlKey,
+          clear: !cursorModifier,
           range: e.shiftKey,
           toggle: false,
         };
diff --git a/chrome/browser/resources/md_bookmarks/toolbar.js b/chrome/browser/resources/md_bookmarks/toolbar.js
index 09b35444..0155ca9 100644
--- a/chrome/browser/resources/md_bookmarks/toolbar.js
+++ b/chrome/browser/resources/md_bookmarks/toolbar.js
@@ -44,9 +44,13 @@
     selectedFolder_: String,
 
     /** @private */
+    selectedFolderChildren_: Number,
+
+    /** @private */
     canSortFolder_: {
       type: Boolean,
-      computed: 'computeCanSortFolder_(canChangeList_, selectedFolder_)',
+      computed: `computeCanSortFolder_(
+          canChangeList_, selectedFolder_, selectedFolderChildren_)`,
     },
 
     /** @private */
@@ -70,6 +74,12 @@
     this.watch('selectedFolder_', function(state) {
       return state.selectedFolder;
     });
+    this.watch('selectedFolderChildren_', (state) => {
+      if (!state.selectedFolder)
+        return 0;
+
+      return state.nodes[state.selectedFolder].children.length;
+    });
     this.updateFromStore();
   },
 
@@ -168,8 +178,7 @@
    * @private
    */
   computeCanSortFolder_: function() {
-    return this.canChangeList_ &&
-        this.getState().nodes[this.selectedFolder_].children.length > 0;
+    return this.canChangeList_ && this.selectedFolderChildren_ > 0;
   },
 
   /**
diff --git a/chrome/browser/resources/settings/people_page/manage_profile.html b/chrome/browser/resources/settings/people_page/manage_profile.html
index cbee2e8b..656400b 100644
--- a/chrome/browser/resources/settings/people_page/manage_profile.html
+++ b/chrome/browser/resources/settings/people_page/manage_profile.html
@@ -19,9 +19,9 @@
     </style>
     <div class="settings-box first">
       <paper-input id="name" value="[[profileName]]" pattern=".*\S.*"
-          auto-validate required on-change="onProfileNameChanged_"
-          on-keydown="onProfileNameKeydown_"
-          disabled="[[isProfileNameDisabled_(syncStatus)]]">
+          on-change="onProfileNameChanged_" on-keydown="onProfileNameKeydown_"
+          disabled="[[isProfileNameDisabled_(syncStatus)]]"
+          auto-validate no-label-float required>
       </paper-input>
     </div>
     <template is="dom-if" if="[[isProfileShortcutSettingVisible_]]">
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index 76a5007..58b78e0 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -201,7 +201,7 @@
           </div>
           <button class="subpage-arrow"
               is="paper-icon-button-light" aria-label="$i18n{lockScreenTitle}"
-              aria-describedby="lockScrenSecondary"></button>
+              aria-describedby="lockScreenSecondary"></button>
         </div>
 </if>
 
diff --git a/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp b/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp
index 653c9fa8..8130e09 100644
--- a/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp
@@ -195,6 +195,7 @@
       'dependencies': [
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
         '<(EXTERNS_GYP):chrome_send',
+        '<(EXTERNS_GYP):settings_private',
         'constants',
         'cookie_tree_node',
       ],
diff --git a/chrome/browser/resources/settings/site_settings/site_details.js b/chrome/browser/resources/settings/site_settings/site_details.js
index 4deaf1e..0a08f0c52 100644
--- a/chrome/browser/resources/settings/site_settings/site_details.js
+++ b/chrome/browser/resources/settings/site_settings/site_details.js
@@ -83,10 +83,8 @@
           exceptionList.forEach(function(exception, i) {
             // |exceptionList| should be in the same order as |categoryList|,
             // which is in the same order as |siteDetailsPermissions|.
-            var element = /** @type{!SiteDetailsPermissionElement} */ (
-                siteDetailsPermissions[i]);
-            element.site = /** @type{!SiteException} */ (
-                element.expandSiteException(exception));
+            siteDetailsPermissions[i].site =
+                /** @type {!RawSiteException} */ (exception);
           });
         });
   },
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.html b/chrome/browser/resources/settings/site_settings/site_details_permission.html
index 22bf311..6e66764 100644
--- a/chrome/browser/resources/settings/site_settings/site_details_permission.html
+++ b/chrome/browser/resources/settings/site_settings/site_details_permission.html
@@ -23,6 +23,13 @@
           <select id="permission" class="md-select"
               aria-labelledby="permissionHeader"
               on-change="onPermissionSelectionChange_">
+            <option id="default" value$="[[ContentSetting.DEFAULT]]">
+              [[defaultSettingString_(
+                  defaultSetting_,
+                  '$i18nPolymer{siteSettingsActionAskDefault}',
+                  '$i18nPolymer{siteSettingsActionAllowDefault}',
+                  '$i18nPolymer{siteSettingsActionBlockDefault}')]]
+            </option>
             <option id="allow" value$="[[ContentSetting.ALLOW]]">
               $i18n{siteSettingsActionAllow}
             </option>
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.js b/chrome/browser/resources/settings/site_settings/site_details_permission.js
index 1eb49eeb..a590d46 100644
--- a/chrome/browser/resources/settings/site_settings/site_details_permission.js
+++ b/chrome/browser/resources/settings/site_settings/site_details_permission.js
@@ -15,9 +15,16 @@
   properties: {
     /**
      * The site that this widget is showing details for.
-     * @type {SiteException}
+     * @type {RawSiteException}
      */
     site: Object,
+
+    /**
+     * The default setting for this permission category.
+     * @type {settings.ContentSetting}
+     * @private
+     */
+    defaultSetting_: String,
   },
 
   observers: ['siteChanged_(site, category)'],
@@ -44,10 +51,20 @@
 
   /**
    * Updates the drop-down value after |site| has changed.
-   * @param {!SiteException} site The site to display.
+   * @param {!RawSiteException} site The site to display.
    * @private
    */
   siteChanged_: function(site) {
+    if (site.source == 'default') {
+      this.defaultSetting_ = site.setting;
+      this.$.permission.value = settings.ContentSetting.DEFAULT;
+      return;
+    }
+    // The default setting is unknown, so consult the C++ backend for it.
+    this.browserProxy.getDefaultValueForContentType(this.category)
+        .then((defaultValue) => {
+          this.defaultSetting_ = defaultValue.setting;
+        });
     this.$.permission.value = site.setting;
   },
 
@@ -86,8 +103,34 @@
    * @private
    */
   onPermissionSelectionChange_: function() {
+    if (this.$.permission.value == settings.ContentSetting.DEFAULT) {
+      this.resetPermission();
+      return;
+    }
     this.browserProxy.setCategoryPermissionForOrigin(
         this.site.origin, this.site.embeddingOrigin, this.category,
         this.$.permission.value, this.site.incognito);
   },
+
+  /**
+   * Updates the string used for this permission category's default setting.
+   * @param {!settings.ContentSetting} defaultSetting Value of the default
+   *    setting for this permission category.
+   * @param {string} askString 'Ask' label, e.g. 'Ask (default)'.
+   * @param {string} allowString 'Allow' label, e.g. 'Allow (default)'.
+   * @param {string} blockString 'Block' label, e.g. 'Blocked (default)'.
+   * @private
+   */
+  defaultSettingString_(defaultSetting, askString, allowString, blockString) {
+    if (defaultSetting == settings.ContentSetting.ASK ||
+        defaultSetting == settings.ContentSetting.IMPORTANT_CONTENT) {
+      return askString;
+    } else if (defaultSetting == settings.ContentSetting.ALLOW) {
+      return allowString;
+    } else if (defaultSetting == settings.ContentSetting.BLOCK) {
+      return blockString;
+    }
+    assertNotReached(
+        `No string for ${this.category}'s default of ${defaultSetting}`);
+  },
 });
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_behavior.js b/chrome/browser/resources/settings/site_settings/site_settings_behavior.js
index 81100e3..762da0c 100644
--- a/chrome/browser/resources/settings/site_settings/site_settings_behavior.js
+++ b/chrome/browser/resources/settings/site_settings/site_settings_behavior.js
@@ -145,13 +145,15 @@
     var origin = exception.origin;
     var embeddingOrigin = exception.embeddingOrigin;
 
-    var enforcement = '';
+    var enforcement = /** @type {?chrome.settingsPrivate.Enforcement} */ (null);
     if (exception.source == 'extension' || exception.source == 'HostedApp' ||
         exception.source == 'platform_app' || exception.source == 'policy') {
       enforcement = chrome.settingsPrivate.Enforcement.ENFORCED;
     }
 
-    var controlledBy = kControlledByLookup[exception.source] || '';
+    var controlledBy = /** @type {!chrome.settingsPrivate.ControlledBy} */ (
+        kControlledByLookup[exception.source] ||
+        chrome.settingsPrivate.ControlledBy.PRIMARY_USER);
 
     return {
       category: this.category,
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js b/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js
index a72a963..bac63cd 100644
--- a/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js
+++ b/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js
@@ -21,11 +21,12 @@
 /**
  * The site exception information passed from the C++ handler.
  * See also: SiteException.
+ * TODO(patricialor): Investigate making the |source| field an enum type.
  * @typedef {{embeddingOrigin: string,
  *            incognito: boolean,
  *            origin: string,
  *            displayName: string,
- *            setting: string,
+ *            setting: !settings.ContentSetting,
  *            source: string}}
  */
 var RawSiteException;
@@ -38,21 +39,15 @@
  *            incognito: boolean,
  *            origin: string,
  *            displayName: string,
- *            setting: string,
- *            enforcement: string,
- *            controlledBy: string}}
+ *            setting: !settings.ContentSetting,
+ *            enforcement: ?chrome.settingsPrivate.Enforcement,
+ *            controlledBy: !chrome.settingsPrivate.ControlledBy}}
  */
 var SiteException;
 
 /**
- * @typedef {{location: string,
- *            notifications: string}}
- */
-var CategoryDefaultsPref;
-
-/**
- * @typedef {{setting: string,
- *            source: ContentSettingProvider}}
+ * @typedef {{setting: !settings.ContentSetting,
+ *            source: !ContentSettingProvider}}
  */
 var DefaultContentSetting;
 
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn
index d48eab04..6a21dbd 100644
--- a/chrome/browser/safe_browsing/BUILD.gn
+++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -43,6 +43,7 @@
 
   deps = [
     "//chrome/app:generated_resources",
+    "//components/chrome_cleaner/public/interfaces",
     "//components/safe_browsing/common:interfaces",
   ]
 
diff --git a/chrome/browser/signin/easy_unlock_auth_attempt.cc b/chrome/browser/signin/easy_unlock_auth_attempt.cc
index cc12f9a6..ab68fbe 100644
--- a/chrome/browser/signin/easy_unlock_auth_attempt.cc
+++ b/chrome/browser/signin/easy_unlock_auth_attempt.cc
@@ -127,8 +127,8 @@
   // TODO(sacomoto): Clean this up when the background app is not needed
   // anymore.
   if (!app_manager_->SendAuthAttemptEvent() &&
-      !base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)) {
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)) {
     Cancel(account_id_);
     return false;
   }
diff --git a/chrome/browser/signin/easy_unlock_auth_attempt_unittest.cc b/chrome/browser/signin/easy_unlock_auth_attempt_unittest.cc
index 003e8b9d..4da7bbbe 100644
--- a/chrome/browser/signin/easy_unlock_auth_attempt_unittest.cc
+++ b/chrome/browser/signin/easy_unlock_auth_attempt_unittest.cc
@@ -6,10 +6,12 @@
 
 #include <stddef.h>
 
+#include "base/command_line.h"
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "chrome/browser/signin/easy_unlock_app_manager.h"
 #include "components/proximity_auth/screenlock_bridge.h"
+#include "components/proximity_auth/switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if defined(OS_CHROMEOS)
@@ -271,6 +273,8 @@
 
 TEST_F(EasyUnlockAuthAttemptUnlockTest,
        StartWhenDispatchingAuthAttemptEventFails) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery);
   InitScreenLock();
   ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
   ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
@@ -429,6 +433,8 @@
 
 TEST_F(EasyUnlockAuthAttemptSigninTest,
        StartWhenDispatchingAuthAttemptEventFails) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery);
   InitScreenLock();
   ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
   ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
diff --git a/chrome/browser/signin/easy_unlock_service.cc b/chrome/browser/signin/easy_unlock_service.cc
index 1137cc55..68fac4798 100644
--- a/chrome/browser/signin/easy_unlock_service.cc
+++ b/chrome/browser/signin/easy_unlock_service.cc
@@ -382,8 +382,8 @@
   if (!GetScreenlockStateHandler())
     return;
 
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery) &&
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery) &&
       !base::CommandLine::ForCurrentProcess()->HasSwitch(
           proximity_auth::switches::kEnableChromeOSLogin)) {
     UpdateScreenlockState(ScreenlockState::PASSWORD_REQUIRED_FOR_LOGIN);
@@ -480,8 +480,8 @@
   // TODO(tengs): We notify ProximityAuthSystem whenever unlock attempts are
   // attempted. However, we ideally should refactor the auth attempt logic to
   // the proximity_auth component.
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery) &&
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery) &&
       proximity_auth_system_) {
     proximity_auth_system_->OnAuthAttempted(account_id);
   }
@@ -704,8 +704,8 @@
   // On device boot, we can't show the initial user state until Bluetooth is
   // detected to be present.
   if (GetType() == TYPE_SIGNIN &&
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery) &&
+      !base::CommandLine::ForCurrentProcess()->HasSwitch(
+          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery) &&
       !base::CommandLine::ForCurrentProcess()->HasSwitch(
           proximity_auth::switches::kEnableChromeOSLogin)) {
     ShowInitialUserState();
@@ -800,8 +800,8 @@
 void EasyUnlockService::SetProximityAuthDevices(
     const AccountId& account_id,
     const cryptauth::RemoteDeviceList& remote_devices) {
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery))
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery))
     return;
 
   if (!proximity_auth_system_) {
diff --git a/chrome/browser/signin/easy_unlock_service_regular.cc b/chrome/browser/signin/easy_unlock_service_regular.cc
index 9732c48e..6d63560 100644
--- a/chrome/browser/signin/easy_unlock_service_regular.cc
+++ b/chrome/browser/signin/easy_unlock_service_regular.cc
@@ -50,6 +50,7 @@
 #include "components/translate/core/browser/translate_download_manager.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_switches.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/common/constants.h"
 #include "google_apis/gaia/gaia_auth_util.h"
@@ -468,8 +469,11 @@
   OnPrefsChanged();
 
 #if defined(OS_CHROMEOS)
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)) {
+  // TODO(tengs): Due to badly configured browser_tests, Chrome crashes during
+  // shutdown. Revisit this condition after migration is fully completed.
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery) &&
+      !base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) {
     pref_manager_.reset(
         new proximity_auth::ProximityAuthPrefManager(profile()->GetPrefs()));
     GetCryptAuthDeviceManager()->AddObserver(this);
diff --git a/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc b/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc
index 18fb6e9..634d7a4 100644
--- a/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc
+++ b/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc
@@ -402,8 +402,8 @@
   // ShowInitialUserState() will display a tooltip explaining that the user must
   // enter their password. We will skip the entire login code path unless the
   // --enable-chromeos-login flag is enabled.
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery) &&
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery) &&
       !base::CommandLine::ForCurrentProcess()->HasSwitch(
           proximity_auth::switches::kEnableChromeOSLogin)) {
     return;
diff --git a/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc b/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc
index 88a5790..d5006b7 100644
--- a/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/env.h"
@@ -74,16 +75,16 @@
 
  private:
   void InitializeLevelDB() {
-    leveldb::DB* db = nullptr;
+    std::unique_ptr<leveldb::DB> db;
     leveldb::Options options;
     options.create_if_missing = true;
     options.max_open_files = 0;  // Use minimum.
     options.env = in_memory_env_.get();
-    leveldb::Status status =
-        leveldb::DB::Open(options, database_dir_.GetPath().AsUTF8Unsafe(), &db);
+    leveldb::Status status = leveldb_env::OpenDB(
+        options, database_dir_.GetPath().AsUTF8Unsafe(), &db);
     ASSERT_TRUE(status.ok());
 
-    db_.reset(new LevelDBWrapper(base::WrapUnique(db)));
+    db_.reset(new LevelDBWrapper(std::move(db)));
   }
 
   base::ScopedTempDir database_dir_;
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
index 8507115..d7a2b2e 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
@@ -222,19 +222,18 @@
   options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   if (env_override)
     options.env = env_override;
-  leveldb::DB* db = nullptr;
+  std::unique_ptr<leveldb::DB> db;
   leveldb::Status db_status =
-      leveldb::DB::Open(options, path.AsUTF8Unsafe(), &db);
+      leveldb_env::OpenDB(options, path.AsUTF8Unsafe(), &db);
   UMA_HISTOGRAM_ENUMERATION("SyncFileSystem.Database.Open",
                             leveldb_env::GetLevelDBStatusUMAValue(db_status),
                             leveldb_env::LEVELDB_STATUS_MAX);
   SyncStatusCode status = LevelDBStatusToSyncStatusCode(db_status);
   if (status != SYNC_STATUS_OK) {
-    delete db;
     return status;
   }
 
-  db_out->reset(new LevelDBWrapper(base::WrapUnique(db)));
+  db_out->reset(new LevelDBWrapper(std::move(db)));
   *created = IsDatabaseEmpty(db_out->get());
   return status;
 }
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk_unittest.cc
index a01b05c..9c5414e 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk_unittest.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/sync_file_system/drive_backend/leveldb_wrapper.h"
 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/env.h"
@@ -116,15 +117,15 @@
   }
 
   std::unique_ptr<LevelDBWrapper> InitializeLevelDB() {
-    leveldb::DB* db = nullptr;
+    std::unique_ptr<leveldb::DB> db;
     leveldb::Options options;
     options.create_if_missing = true;
     options.max_open_files = 0;  // Use minimum.
     options.env = in_memory_env_.get();
-    leveldb::Status status =
-        leveldb::DB::Open(options, database_dir_.GetPath().AsUTF8Unsafe(), &db);
+    leveldb::Status status = leveldb_env::OpenDB(
+        options, database_dir_.GetPath().AsUTF8Unsafe(), &db);
     EXPECT_TRUE(status.ok());
-    return base::MakeUnique<LevelDBWrapper>(base::WrapUnique(db));
+    return base::MakeUnique<LevelDBWrapper>(std::move(db));
   }
 
  private:
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc
index 6578079..eb808178 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_unittest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/env.h"
@@ -81,15 +82,15 @@
 
  private:
   void InitializeLevelDB() {
-    leveldb::DB* db = nullptr;
+    std::unique_ptr<leveldb::DB> db;
     leveldb::Options options;
     options.create_if_missing = true;
     options.max_open_files = 0;  // Use minimum.
     options.env = in_memory_env_.get();
-    leveldb::Status status = leveldb::DB::Open(options, "", &db);
+    leveldb::Status status = leveldb_env::OpenDB(options, "", &db);
     ASSERT_TRUE(status.ok());
 
-    db_.reset(new LevelDBWrapper(base::WrapUnique(db)));
+    db_.reset(new LevelDBWrapper(std::move(db)));
   }
 
   std::unique_ptr<DatabaseContents> contents_;
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
index e0ea089..53e47124 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
@@ -28,6 +28,7 @@
 #include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
 #include "google_apis/drive/drive_api_parser.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/env.h"
@@ -271,17 +272,16 @@
   MetadataDatabase* metadata_database() { return metadata_database_.get(); }
 
   std::unique_ptr<LevelDBWrapper> InitializeLevelDB() {
-    leveldb::DB* db = nullptr;
+    std::unique_ptr<leveldb::DB> db;
     leveldb::Options options;
     options.create_if_missing = true;
     options.max_open_files = 0;  // Use minimum.
     options.env = in_memory_env_.get();
-    leveldb::Status status =
-        leveldb::DB::Open(options, database_dir_.GetPath().AsUTF8Unsafe(), &db);
+    leveldb::Status status = leveldb_env::OpenDB(
+        options, database_dir_.GetPath().AsUTF8Unsafe(), &db);
     EXPECT_TRUE(status.ok());
 
-    std::unique_ptr<LevelDBWrapper> wrapper(
-        new LevelDBWrapper(base::WrapUnique(db)));
+    std::unique_ptr<LevelDBWrapper> wrapper(new LevelDBWrapper(std::move(db)));
 
     wrapper->Put(kDatabaseVersionKey, base::Int64ToString(3));
     SetUpServiceMetadata(wrapper.get());
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc
index a04b0d93..4e62bab 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc
@@ -15,6 +15,7 @@
 #include "storage/browser/fileapi/external_mount_points.h"
 #include "storage/common/fileapi/file_system_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
 #include "url/gurl.h"
@@ -71,7 +72,7 @@
   const char kDemotedDirtyIDKeyPrefix[] = "DEMOTED_DIRTY: ";
 
   // Set up environment.
-  leveldb::DB* db_ptr = nullptr;
+  std::unique_ptr<leveldb::DB> db;
   base::ScopedTempDir base_dir;
   ASSERT_TRUE(base_dir.CreateUniqueTempDir());
   {
@@ -79,10 +80,9 @@
     options.create_if_missing = true;
     std::string db_dir =
         storage::FilePathToString(base_dir.GetPath().Append(kDatabaseName));
-    leveldb::Status status = leveldb::DB::Open(options, db_dir, &db_ptr);
+    leveldb::Status status = leveldb_env::OpenDB(options, db_dir, &db);
     ASSERT_TRUE(status.ok());
   }
-  std::unique_ptr<leveldb::DB> db(db_ptr);
 
   // Setup the database with the schema version 4, without IDs.
   leveldb::WriteBatch batch;
diff --git a/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc b/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc
index c782eac0..1748a98 100644
--- a/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc
@@ -31,6 +31,7 @@
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "google_apis/drive/drive_api_parser.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/env.h"
@@ -80,14 +81,14 @@
 
  protected:
   std::unique_ptr<LevelDBWrapper> OpenLevelDB() {
-    leveldb::DB* db = nullptr;
+    std::unique_ptr<leveldb::DB> db;
     leveldb::Options options;
     options.create_if_missing = true;
     options.env = in_memory_env_.get();
-    leveldb::Status status =
-        leveldb::DB::Open(options, database_dir_.GetPath().AsUTF8Unsafe(), &db);
+    leveldb::Status status = leveldb_env::OpenDB(
+        options, database_dir_.GetPath().AsUTF8Unsafe(), &db);
     EXPECT_TRUE(status.ok());
-    return base::MakeUnique<LevelDBWrapper>(base::WrapUnique(db));
+    return base::MakeUnique<LevelDBWrapper>(std::move(db));
   }
 
   void SetUpInitialData(LevelDBWrapper* db) {
diff --git a/chrome/browser/sync_file_system/local/local_file_change_tracker.cc b/chrome/browser/sync_file_system/local/local_file_change_tracker.cc
index 155d770d..9b81b83 100644
--- a/chrome/browser/sync_file_system/local/local_file_change_tracker.cc
+++ b/chrome/browser/sync_file_system/local/local_file_change_tracker.cc
@@ -492,13 +492,11 @@
   options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   if (env_override_)
     options.env = env_override_;
-  leveldb::DB* db;
-  leveldb::Status status = leveldb::DB::Open(options, path, &db);
+  leveldb::Status status = leveldb_env::OpenDB(options, path, &db_);
   UMA_HISTOGRAM_ENUMERATION("SyncFileSystem.TrackerDB.Open",
                             leveldb_env::GetLevelDBStatusUMAValue(status),
                             leveldb_env::LEVELDB_STATUS_MAX);
   if (status.ok()) {
-    db_.reset(db);
     return SYNC_STATUS_OK;
   }
 
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 30cc41b2..b681af1c 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -1893,6 +1893,12 @@
     {"siteSettingsBlockedRecommended",
      IDS_SETTINGS_SITE_SETTINGS_BLOCKED_RECOMMENDED},
     {"siteSettingsSiteUrl", IDS_SETTINGS_SITE_SETTINGS_SITE_URL},
+    {"siteSettingsActionAskDefault",
+     IDS_SETTINGS_SITE_SETTINGS_ASK_DEFAULT_MENU},
+    {"siteSettingsActionAllowDefault",
+     IDS_SETTINGS_SITE_SETTINGS_ALLOW_DEFAULT_MENU},
+    {"siteSettingsActionBlockDefault",
+     IDS_SETTINGS_SITE_SETTINGS_BLOCK_DEFAULT_MENU},
     {"siteSettingsActionAllow", IDS_SETTINGS_SITE_SETTINGS_ALLOW_MENU},
     {"siteSettingsActionBlock", IDS_SETTINGS_SITE_SETTINGS_BLOCK_MENU},
     {"siteSettingsActionReset", IDS_SETTINGS_SITE_SETTINGS_RESET_MENU},
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chrome/browser/ui/webui/settings/site_settings_handler.cc
index 4022176a..0ecdfb2 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler.cc
@@ -114,23 +114,23 @@
 //    7. User-set global default for a ContentSettingsType.
 //    8. Chrome's built-in default.
 std::string ConvertContentSettingSourceToString(
-    content_settings::SettingSource content_settings_source,
+    const content_settings::SettingInfo& info,
     PermissionStatusSource permission_status_source) {
   // TODO(patricialor): Do some plumbing for sources #1, #2, #3, and #5 through
   // to the Web UI. Currently there aren't strings to represent these sources.
   if (permission_status_source == PermissionStatusSource::KILL_SWITCH)
     return site_settings::kPreferencesSource;  // Source #1.
 
-  if (content_settings_source == content_settings::SETTING_SOURCE_POLICY ||
-      content_settings_source == content_settings::SETTING_SOURCE_SUPERVISED) {
+  if (info.source == content_settings::SETTING_SOURCE_POLICY ||
+      info.source == content_settings::SETTING_SOURCE_SUPERVISED) {
     return site_settings::kPolicyProviderId;  // Source #2.
   }
 
-  if (content_settings_source == content_settings::SETTING_SOURCE_EXTENSION)
+  if (info.source == content_settings::SETTING_SOURCE_EXTENSION)
     return site_settings::kExtensionProviderId;  // Source #3.
 
-  DCHECK_NE(content_settings::SETTING_SOURCE_NONE, content_settings_source);
-  if (content_settings_source == content_settings::SETTING_SOURCE_USER) {
+  DCHECK_NE(content_settings::SETTING_SOURCE_NONE, info.source);
+  if (info.source == content_settings::SETTING_SOURCE_USER) {
     if (permission_status_source ==
             PermissionStatusSource::SAFE_BROWSING_BLACKLIST ||
         permission_status_source ==
@@ -138,7 +138,11 @@
         permission_status_source == PermissionStatusSource::MULTIPLE_IGNORES) {
       return site_settings::kPreferencesSource;  // Source #5.
     }
-    // Source #4, #6, #7, #8. When #4 is the source, |permission_status_source|
+    if (info.primary_pattern == ContentSettingsPattern::Wildcard() &&
+        info.secondary_pattern == ContentSettingsPattern::Wildcard()) {
+      return "default";  // Source #7, #8.
+    }
+    // Source #4, #6. When #4 is the source, |permission_status_source|
     // won't be set to any of the source #5 enum values, as PermissionManager is
     // aware of the difference between these two sources internally. The
     // subtlety here should go away when PermissionManager can handle all
@@ -177,8 +181,8 @@
   }
 
   // Retrieve the source of the content setting.
-  *source_string =
-      ConvertContentSettingSourceToString(info.source, result.source);
+  *source_string = ConvertContentSettingSourceToString(info, result.source);
+
   return result.content_setting;
 }
 
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.h b/chrome/browser/ui/webui/settings/site_settings_handler.h
index 0ccbcd4..e735dd7 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler.h
+++ b/chrome/browser/ui/webui/settings/site_settings_handler.h
@@ -59,6 +59,7 @@
 
  private:
   friend class SiteSettingsHandlerTest;
+  FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, DefaultSettingSource);
   FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, GetAndSetDefault);
   FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, Origins);
   FRIEND_TEST_ALL_PREFIXES(SiteSettingsHandlerTest, ExceptionHelpers);
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
index dd8f370a..0f46e7b 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
@@ -8,10 +8,14 @@
 
 #include "base/test/histogram_tester.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/ui/webui/site_settings_helper.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
+#include "components/content_settings/core/common/pref_names.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -34,6 +38,40 @@
 
 namespace settings {
 
+// Helper class for setting ContentSettings via different sources.
+class ContentSettingSourceSetter {
+ public:
+  ContentSettingSourceSetter(TestingProfile* profile,
+                             ContentSettingsType content_type)
+      : prefs_(profile->GetTestingPrefService()),
+        host_content_settings_map_(
+            HostContentSettingsMapFactory::GetForProfile(profile)),
+        content_type_(content_type) {}
+
+  void SetPolicyDefault(ContentSetting setting) {
+    prefs_->SetManagedPref(GetPrefNameForDefaultPermissionSetting(),
+                           base::MakeUnique<base::Value>(setting));
+  }
+
+  const char* GetPrefNameForDefaultPermissionSetting() {
+    switch (content_type_) {
+      case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
+        return prefs::kManagedDefaultNotificationsSetting;
+      default:
+        // Add support as needed.
+        NOTREACHED();
+        return "";
+    }
+  }
+
+ private:
+  sync_preferences::TestingPrefServiceSyncable* prefs_;
+  HostContentSettingsMap* host_content_settings_map_;
+  ContentSettingsType content_type_;
+
+  DISALLOW_COPY_AND_ASSIGN(ContentSettingSourceSetter);
+};
+
 class SiteSettingsHandlerTest : public testing::Test {
  public:
   SiteSettingsHandlerTest() : handler_(&profile_) {
@@ -50,7 +88,7 @@
     web_ui()->ClearTrackedCalls();
   }
 
-  Profile* profile() { return &profile_; }
+  TestingProfile* profile() { return &profile_; }
   content::TestWebUI* web_ui() { return &web_ui_; }
   SiteSettingsHandler* handler() { return &handler_; }
 
@@ -315,7 +353,61 @@
 
   handler()->HandleGetOriginPermissions(&get_origin_permissions_args);
   // "Ask" is the default value for Notifications.
-  ValidateOrigin(google, google, google, "ask", "preference", 6U);
+  ValidateOrigin(google, google, google, "ask", "default", 6U);
+}
+
+TEST_F(SiteSettingsHandlerTest, DefaultSettingSource) {
+  const std::string google("http://www.google.com");
+  ContentSettingSourceSetter source_setter(profile(),
+                                           CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
+
+  base::ListValue get_origin_permissions_args;
+  get_origin_permissions_args.AppendString(kCallbackId);
+  get_origin_permissions_args.AppendString(google);
+  auto category_list = base::MakeUnique<base::ListValue>();
+  category_list->AppendString("notifications");
+  get_origin_permissions_args.Append(std::move(category_list));
+
+  // Test Chrome built-in defaults are marked as default.
+  handler()->HandleGetOriginPermissions(&get_origin_permissions_args);
+  ValidateOrigin(google, google, google, "ask", "default", 1U);
+
+  base::ListValue default_value_args;
+  default_value_args.AppendString("notifications");
+  default_value_args.AppendString("block");
+  handler()->HandleSetDefaultValueForContentType(&default_value_args);
+  // A user-set global default should also show up as default.
+  handler()->HandleGetOriginPermissions(&get_origin_permissions_args);
+  ValidateOrigin(google, google, google, "block", "default", 3U);
+
+  base::ListValue set_notification_pattern_args;
+  set_notification_pattern_args.AppendString("[*.]google.com");
+  set_notification_pattern_args.AppendString("*");
+  set_notification_pattern_args.AppendString("notifications");
+  set_notification_pattern_args.AppendString("allow");
+  set_notification_pattern_args.AppendBoolean(false);
+  handler()->HandleSetCategoryPermissionForOrigin(
+      &set_notification_pattern_args);
+  // A user-set pattern should not show up as default.
+  handler()->HandleGetOriginPermissions(&get_origin_permissions_args);
+  ValidateOrigin(google, google, google, "allow", "preference", 5U);
+
+  base::ListValue set_notification_origin_args;
+  set_notification_origin_args.AppendString(google);
+  set_notification_origin_args.AppendString(google);
+  set_notification_origin_args.AppendString("notifications");
+  set_notification_origin_args.AppendString("block");
+  set_notification_origin_args.AppendBoolean(false);
+  handler()->HandleSetCategoryPermissionForOrigin(
+      &set_notification_origin_args);
+  // A user-set per-origin permission should not show up as default.
+  handler()->HandleGetOriginPermissions(&get_origin_permissions_args);
+  ValidateOrigin(google, google, google, "block", "preference", 7U);
+
+  // Enterprise-policy set defaults should not show up as default.
+  source_setter.SetPolicyDefault(CONTENT_SETTING_ALLOW);
+  handler()->HandleGetOriginPermissions(&get_origin_permissions_args);
+  ValidateOrigin(google, google, google, "allow", "policy", 8U);
 }
 
 TEST_F(SiteSettingsHandlerTest, ExceptionHelpers) {
diff --git a/chrome/browser/vr/animation_player.cc b/chrome/browser/vr/animation_player.cc
index 225e45f..133cc97 100644
--- a/chrome/browser/vr/animation_player.cc
+++ b/chrome/browser/vr/animation_player.cc
@@ -58,7 +58,11 @@
   // This implies that,
   //   0 = d - o - 2t
   //   o = d - 2t
+  //
+  // Now if there was a previous offset, we must adjust d by that offset before
+  // performing this computation, so it becomes d - o_old - 2t:
   animation->set_time_offset(animation->curve()->Duration() -
+                             animation->time_offset() -
                              (2 * (monotonic_time - animation->start_time())));
 }
 
@@ -68,6 +72,20 @@
       cc::CubicBezierTimingFunction::EaseType::EASE);
 }
 
+base::TimeDelta GetStartTime(cc::Animation* animation) {
+  if (animation->direction() == cc::Animation::Direction::NORMAL) {
+    return base::TimeDelta();
+  }
+  return animation->curve()->Duration();
+}
+
+base::TimeDelta GetEndTime(cc::Animation* animation) {
+  if (animation->direction() == cc::Animation::Direction::REVERSE) {
+    return base::TimeDelta();
+  }
+  return animation->curve()->Duration();
+}
+
 }  // namespace
 
 AnimationPlayer::AnimationPlayer() {}
@@ -143,6 +161,14 @@
   StartAnimations(monotonic_time);
 }
 
+void AnimationPlayer::SetTransitionedProperties(
+    const std::vector<cc::TargetProperty::Type>& properties) {
+  transition_.target_properties.reset();
+  for (auto property : properties) {
+    transition_.target_properties[property] = true;
+  }
+}
+
 void AnimationPlayer::TransitionOpacityTo(base::TimeTicks monotonic_time,
                                           float current,
                                           float target) {
@@ -156,10 +182,17 @@
   cc::Animation* running_animation =
       GetRunningAnimationForProperty(cc::TargetProperty::OPACITY);
 
-  if (running_animation &&
-      target == running_animation->curve()->ToFloatAnimationCurve()->GetValue(
-                    base::TimeDelta())) {
-    ReverseAnimation(monotonic_time, running_animation);
+  if (running_animation) {
+    const cc::FloatAnimationCurve* curve =
+        running_animation->curve()->ToFloatAnimationCurve();
+    if (target == curve->GetValue(GetEndTime(running_animation))) {
+      return;
+    }
+    if (target == curve->GetValue(GetStartTime(running_animation))) {
+      ReverseAnimation(monotonic_time, running_animation);
+      return;
+    }
+  } else if (target == current) {
     return;
   }
 
@@ -195,11 +228,17 @@
   cc::Animation* running_animation =
       GetRunningAnimationForProperty(cc::TargetProperty::TRANSFORM);
 
-  if (running_animation &&
-      target ==
-          running_animation->curve()->ToTransformAnimationCurve()->GetValue(
-              base::TimeDelta())) {
-    ReverseAnimation(monotonic_time, running_animation);
+  if (running_animation) {
+    const cc::TransformAnimationCurve* curve =
+        running_animation->curve()->ToTransformAnimationCurve();
+    if (target == curve->GetValue(GetEndTime(running_animation))) {
+      return;
+    }
+    if (target == curve->GetValue(GetStartTime(running_animation))) {
+      ReverseAnimation(monotonic_time, running_animation);
+      return;
+    }
+  } else if (target == current) {
     return;
   }
 
@@ -232,10 +271,17 @@
   cc::Animation* running_animation =
       GetRunningAnimationForProperty(cc::TargetProperty::BOUNDS);
 
-  if (running_animation &&
-      target == running_animation->curve()->ToSizeAnimationCurve()->GetValue(
-                    base::TimeDelta())) {
-    ReverseAnimation(monotonic_time, running_animation);
+  if (running_animation) {
+    const cc::SizeAnimationCurve* curve =
+        running_animation->curve()->ToSizeAnimationCurve();
+    if (target == curve->GetValue(GetEndTime(running_animation))) {
+      return;
+    }
+    if (target == curve->GetValue(GetStartTime(running_animation))) {
+      ReverseAnimation(monotonic_time, running_animation);
+      return;
+    }
+  } else if (target == current) {
     return;
   }
 
@@ -256,17 +302,24 @@
 }
 
 cc::Animation* AnimationPlayer::GetRunningAnimationForProperty(
-    cc::TargetProperty::Type target_property) {
-  auto it = std::find_if(
-      animations_.begin(), animations_.end(),
-      [target_property](const std::unique_ptr<cc::Animation>& animation) {
-        if (animation->run_state() != cc::Animation::RUNNING &&
-            animation->run_state() != cc::Animation::PAUSED) {
-          return false;
-        }
-        return animation->target_property() == target_property;
-      });
-  return it == animations_.end() ? nullptr : it->get();
+    cc::TargetProperty::Type target_property) const {
+  for (auto& animation : animations_) {
+    if ((animation->run_state() == cc::Animation::RUNNING ||
+         animation->run_state() == cc::Animation::PAUSED) &&
+        animation->target_property() == target_property) {
+      return animation.get();
+    }
+  }
+  return nullptr;
+}
+
+bool AnimationPlayer::IsAnimatingProperty(
+    cc::TargetProperty::Type property) const {
+  for (auto& animation : animations_) {
+    if (animation->target_property() == property)
+      return true;
+  }
+  return false;
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/animation_player.h b/chrome/browser/vr/animation_player.h
index fa20e855..e2d1351 100644
--- a/chrome/browser/vr/animation_player.h
+++ b/chrome/browser/vr/animation_player.h
@@ -60,6 +60,9 @@
     transition_ = transition;
   }
 
+  void SetTransitionedProperties(
+      const std::vector<cc::TargetProperty::Type>& properties);
+
   void TransitionOpacityTo(base::TimeTicks monotonic_time,
                            float current,
                            float target);
@@ -70,10 +73,12 @@
                           const gfx::SizeF& current,
                           const gfx::SizeF& target);
 
+  bool IsAnimatingProperty(cc::TargetProperty::Type property) const;
+
  private:
   void StartAnimations(base::TimeTicks monotonic_time);
   cc::Animation* GetRunningAnimationForProperty(
-      cc::TargetProperty::Type target_property);
+      cc::TargetProperty::Type target_property) const;
 
   cc::AnimationTarget* target_ = nullptr;
   Animations animations_;
diff --git a/chrome/browser/vr/animation_player_unittest.cc b/chrome/browser/vr/animation_player_unittest.cc
index 977dc3d..7cdb4bf 100644
--- a/chrome/browser/vr/animation_player_unittest.cc
+++ b/chrome/browser/vr/animation_player_unittest.cc
@@ -363,4 +363,93 @@
   EXPECT_FLOAT_SIZE_EQ(from, target.size());
 }
 
+TEST(AnimationPlayerTest, DoubleReversedTransitions) {
+  TestAnimationTarget target;
+  AnimationPlayer player;
+  player.set_target(&target);
+  Transition transition;
+  transition.target_properties[cc::TargetProperty::OPACITY] = true;
+  transition.duration = UsToDelta(10000);
+  player.set_transition(transition);
+
+  base::TimeTicks start_time = UsToTicks(1000000);
+  player.Tick(start_time);
+
+  float from = 1.0f;
+  float to = 0.5f;
+  player.TransitionOpacityTo(start_time, from, to);
+
+  EXPECT_EQ(from, target.opacity());
+  player.Tick(start_time);
+
+  player.Tick(start_time + UsToDelta(1000));
+  float value_before_reversing = target.opacity();
+  EXPECT_GT(from, value_before_reversing);
+  EXPECT_LT(to, value_before_reversing);
+
+  player.TransitionOpacityTo(start_time + UsToDelta(1000), target.opacity(),
+                             from);
+  player.Tick(start_time + UsToDelta(1000));
+  EXPECT_FLOAT_EQ(value_before_reversing, target.opacity());
+
+  player.Tick(start_time + UsToDelta(1500));
+  value_before_reversing = target.opacity();
+  // If the code for reversing transitions does not account for an existing time
+  // offset, then reversing a second time will give incorrect values.
+  player.TransitionOpacityTo(start_time + UsToDelta(1500), target.opacity(),
+                             to);
+  player.Tick(start_time + UsToDelta(1500));
+  EXPECT_FLOAT_EQ(value_before_reversing, target.opacity());
+}
+
+TEST(AnimationPlayerTest, RedundantTransition) {
+  TestAnimationTarget target;
+  AnimationPlayer player;
+  player.set_target(&target);
+  Transition transition;
+  transition.target_properties[cc::TargetProperty::OPACITY] = true;
+  transition.duration = UsToDelta(10000);
+  player.set_transition(transition);
+
+  base::TimeTicks start_time = UsToTicks(1000000);
+  player.Tick(start_time);
+
+  float from = 1.0f;
+  float to = 0.5f;
+  player.TransitionOpacityTo(start_time, from, to);
+
+  EXPECT_EQ(from, target.opacity());
+  player.Tick(start_time);
+
+  player.Tick(start_time + UsToDelta(1000));
+  float value_before_redundant_transition = target.opacity();
+
+  // While an existing transition is in progress to the same value, we should
+  // not start a new transition.
+  player.TransitionOpacityTo(start_time, target.opacity(), to);
+
+  EXPECT_EQ(1lu, player.animations().size());
+  EXPECT_EQ(value_before_redundant_transition, target.opacity());
+}
+
+TEST(AnimationPlayerTest, TransitionToSameValue) {
+  TestAnimationTarget target;
+  AnimationPlayer player;
+  player.set_target(&target);
+  Transition transition;
+  transition.target_properties[cc::TargetProperty::OPACITY] = true;
+  transition.duration = UsToDelta(10000);
+  player.set_transition(transition);
+
+  base::TimeTicks start_time = UsToTicks(1000000);
+  player.Tick(start_time);
+
+  // Transitioning to the same value should be a no-op.
+  float from = 1.0f;
+  float to = 1.0f;
+  player.TransitionOpacityTo(start_time, from, to);
+  EXPECT_EQ(from, target.opacity());
+  EXPECT_TRUE(player.animations().empty());
+}
+
 }  // namespace vr
diff --git a/chrome/browser/vr/test/animation_utils.cc b/chrome/browser/vr/test/animation_utils.cc
index c2df8c9..61c4a1e 100644
--- a/chrome/browser/vr/test/animation_utils.cc
+++ b/chrome/browser/vr/test/animation_utils.cc
@@ -45,4 +45,12 @@
   return base::TimeDelta::FromInternalValue(us);
 }
 
+base::TimeTicks MsToTicks(uint64_t ms) {
+  return UsToTicks(1000 * ms);
+}
+
+base::TimeDelta MsToDelta(uint64_t ms) {
+  return UsToDelta(1000 * ms);
+}
+
 }  // namespace vr
diff --git a/chrome/browser/vr/test/animation_utils.h b/chrome/browser/vr/test/animation_utils.h
index aafb878..94186b5 100644
--- a/chrome/browser/vr/test/animation_utils.h
+++ b/chrome/browser/vr/test/animation_utils.h
@@ -26,6 +26,9 @@
 base::TimeTicks UsToTicks(uint64_t us);
 base::TimeDelta UsToDelta(uint64_t us);
 
+base::TimeTicks MsToTicks(uint64_t us);
+base::TimeDelta MsToDelta(uint64_t us);
+
 }  // namespace vr
 
 #endif  // CHROME_BROWSER_VR_TEST_ANIMATION_UTILS_H_
diff --git a/chrome/browser/vr/test/ui_scene_manager_test.cc b/chrome/browser/vr/test/ui_scene_manager_test.cc
index 19387eff..611608e 100644
--- a/chrome/browser/vr/test/ui_scene_manager_test.cc
+++ b/chrome/browser/vr/test/ui_scene_manager_test.cc
@@ -58,4 +58,24 @@
   return true;
 }
 
+void UiSceneManagerTest::AnimateBy(base::TimeDelta delta) {
+  base::TimeTicks target_time = current_time_ + delta;
+  base::TimeDelta frame_time = base::TimeDelta::FromSecondsD(1.0 / 60.0);
+  for (; current_time_ < target_time; current_time_ += frame_time) {
+    scene_->OnBeginFrame(current_time_);
+  }
+  current_time_ = target_time;
+  scene_->OnBeginFrame(current_time_);
+}
+
+bool UiSceneManagerTest::IsAnimating(
+    UiElement* element,
+    const std::vector<cc::TargetProperty::Type>& properties) {
+  for (auto property : properties) {
+    if (!element->animation_player().IsAnimatingProperty(property))
+      return false;
+  }
+  return true;
+}
+
 }  // namespace vr
diff --git a/chrome/browser/vr/test/ui_scene_manager_test.h b/chrome/browser/vr/test/ui_scene_manager_test.h
index 5801f66..e17fe340 100644
--- a/chrome/browser/vr/test/ui_scene_manager_test.h
+++ b/chrome/browser/vr/test/ui_scene_manager_test.h
@@ -5,14 +5,18 @@
 #ifndef CHROME_BROWSER_VR_TEST_UI_SCENE_MANAGER_TEST_H_
 #define CHROME_BROWSER_VR_TEST_UI_SCENE_MANAGER_TEST_H_
 
+#include <vector>
+
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
+#include "cc/trees/target_property.h"
 #include "chrome/browser/vr/elements/ui_element_debug_id.h"
 #include "chrome/browser/vr/test/mock_browser_interface.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace vr {
 
+class UiElement;
 class UiScene;
 class UiSceneManager;
 
@@ -52,10 +56,19 @@
   bool VerifyVisibility(const std::set<UiElementDebugId>& debug_ids,
                         bool visible);
 
+  // Advances current_time_ by delta. This is done in frame increments and
+  // UiScene::OnBeginFrame is called at each increment.
+  void AnimateBy(base::TimeDelta delta);
+
+  // Returns true if the given properties are being animated by the element.
+  bool IsAnimating(UiElement* element,
+                   const std::vector<cc::TargetProperty::Type>& properties);
+
   base::MessageLoop message_loop_;
   std::unique_ptr<MockBrowserInterface> browser_;
   std::unique_ptr<UiScene> scene_;
   std::unique_ptr<UiSceneManager> manager_;
+  base::TimeTicks current_time_;
 };
 
 }  // namespace vr
diff --git a/chrome/browser/vr/transition.cc b/chrome/browser/vr/transition.cc
index 5c2398c..654e816 100644
--- a/chrome/browser/vr/transition.cc
+++ b/chrome/browser/vr/transition.cc
@@ -6,7 +6,14 @@
 
 namespace vr {
 
-Transition::Transition() {}
+namespace {
+static constexpr int kDefaultTransitionDurationMs = 225;
+}  // namespace
+
+Transition::Transition()
+    : duration(
+          base::TimeDelta::FromMilliseconds(kDefaultTransitionDurationMs)) {}
+
 Transition::~Transition() {}
 
 }  // namespace vr
diff --git a/chrome/browser/vr/ui_scene_manager.cc b/chrome/browser/vr/ui_scene_manager.cc
index e9fc0ee..4b623b5 100644
--- a/chrome/browser/vr/ui_scene_manager.cc
+++ b/chrome/browser/vr/ui_scene_manager.cc
@@ -27,6 +27,9 @@
 #include "components/vector_icons/vector_icons.h"
 #include "ui/gfx/transform_util.h"
 
+using cc::TargetProperty::BOUNDS;
+using cc::TargetProperty::TRANSFORM;
+
 namespace vr {
 
 namespace {
@@ -271,6 +274,7 @@
   element->SetTranslate(0, kContentVerticalOffset, -kContentDistance);
   element->set_visible(false);
   element->set_corner_radius(kContentCornerRadius);
+  element->animation_player().SetTransitionedProperties({TRANSFORM, BOUNDS});
   main_content_ = element.get();
   content_elements_.push_back(element.get());
   scene_->AddUiElement(std::move(element));
diff --git a/chrome/browser/vr/ui_scene_manager_unittest.cc b/chrome/browser/vr/ui_scene_manager_unittest.cc
index 7dc06aab..9bd77c1 100644
--- a/chrome/browser/vr/ui_scene_manager_unittest.cc
+++ b/chrome/browser/vr/ui_scene_manager_unittest.cc
@@ -9,12 +9,16 @@
 #include "base/test/scoped_mock_time_message_loop_task_runner.h"
 #include "chrome/browser/vr/elements/ui_element.h"
 #include "chrome/browser/vr/elements/ui_element_debug_id.h"
+#include "chrome/browser/vr/test/animation_utils.h"
 #include "chrome/browser/vr/test/mock_browser_interface.h"
 #include "chrome/browser/vr/test/ui_scene_manager_test.h"
 #include "chrome/browser/vr/ui_scene.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using cc::TargetProperty::BOUNDS;
+using cc::TargetProperty::TRANSFORM;
+
 namespace vr {
 
 namespace {
@@ -266,24 +270,36 @@
   // Hold onto the background color to make sure it changes.
   SkColor initial_background = scene_->GetWorldBackgroundColor();
   VerifyElementsVisible("Initial", kElementsVisibleInBrowsing);
+  UiElement* content_quad = scene_->GetUiElementByDebugId(kContentQuad);
+  gfx::SizeF initial_content_size = content_quad->size();
+  gfx::Transform initial_position =
+      content_quad->transform_operations().Apply();
 
   // In fullscreen mode, content elements should be visible, control elements
   // should be hidden.
   manager_->SetFullscreen(true);
   VerifyElementsVisible("In fullscreen", visible_in_fullscreen);
-  {
-    SCOPED_TRACE("Entered Fullsceen");
-    // Make sure background has changed for fullscreen.
-    EXPECT_NE(initial_background, scene_->GetWorldBackgroundColor());
-  }
+  // Make sure background has changed for fullscreen.
+  EXPECT_NE(initial_background, scene_->GetWorldBackgroundColor());
+  // Should have started transition.
+  EXPECT_TRUE(IsAnimating(content_quad, {TRANSFORM, BOUNDS}));
+  // Finish the transition.
+  AnimateBy(MsToDelta(1000));
+  EXPECT_FALSE(IsAnimating(content_quad, {TRANSFORM, BOUNDS}));
+  EXPECT_NE(initial_content_size, content_quad->size());
+  EXPECT_NE(initial_position, content_quad->transform_operations().Apply());
 
   // Everything should return to original state after leaving fullscreen.
   manager_->SetFullscreen(false);
   VerifyElementsVisible("Restore initial", kElementsVisibleInBrowsing);
-  {
-    SCOPED_TRACE("Exited Fullsceen");
-    EXPECT_EQ(initial_background, scene_->GetWorldBackgroundColor());
-  }
+  EXPECT_EQ(initial_background, scene_->GetWorldBackgroundColor());
+  // Should have started transition.
+  EXPECT_TRUE(IsAnimating(content_quad, {TRANSFORM, BOUNDS}));
+  // Finish the transition.
+  AnimateBy(MsToDelta(1000));
+  EXPECT_FALSE(IsAnimating(content_quad, {TRANSFORM, BOUNDS}));
+  EXPECT_EQ(initial_content_size, content_quad->size());
+  EXPECT_EQ(initial_position, content_quad->transform_operations().Apply());
 }
 
 TEST_F(UiSceneManagerTest, UiUpdatesExitPrompt) {
diff --git a/chrome/renderer/media/chrome_key_systems.cc b/chrome/renderer/media/chrome_key_systems.cc
index 2f51d297..f125c07d 100644
--- a/chrome/renderer/media/chrome_key_systems.cc
+++ b/chrome/renderer/media/chrome_key_systems.cc
@@ -83,6 +83,8 @@
       "org.chromium.externalclearkey.crash";
   static const char kExternalClearKeyVerifyCdmHostTestKeySystem[] =
       "org.chromium.externalclearkey.verifycdmhosttest";
+  static const char kExternalClearKeyStorageIdTestKeySystem[] =
+      "org.chromium.externalclearkey.storageidtest";
 
   std::vector<base::string16> additional_param_names;
   std::vector<base::string16> additional_param_values;
@@ -128,6 +130,10 @@
   // A key system that triggers the verify host files test in ClearKeyCdm.
   concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties(
       kExternalClearKeyVerifyCdmHostTestKeySystem));
+
+  // A key system that fetches the Storage ID in ClearKeyCdm.
+  concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties(
+      kExternalClearKeyStorageIdTestKeySystem));
 }
 
 #if defined(WIDEVINE_CDM_AVAILABLE)
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc
index 803f8fe5..dcf0f6c2 100644
--- a/chrome/test/base/testing_browser_process.cc
+++ b/chrome/test/base/testing_browser_process.cc
@@ -411,6 +411,11 @@
   return nullptr;
 }
 
+prefs::InProcessPrefServiceFactory*
+TestingBrowserProcess::pref_service_factory() const {
+  return nullptr;
+}
+
 void TestingBrowserProcess::SetSystemRequestContext(
     net::URLRequestContextGetter* context_getter) {
   system_request_context_ = context_getter;
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h
index 3f8d891..a146833f 100644
--- a/chrome/test/base/testing_browser_process.h
+++ b/chrome/test/base/testing_browser_process.h
@@ -133,6 +133,7 @@
   shell_integration::DefaultWebClientState CachedDefaultWebClientState()
       override;
   physical_web::PhysicalWebDataSource* GetPhysicalWebDataSource() override;
+  prefs::InProcessPrefServiceFactory* pref_service_factory() const override;
 
   // Set the local state for tests. Consumer is responsible for cleaning it up
   // afterwards (using ScopedTestingLocalState, for example).
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 3bc34cc..fb15631 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -443,8 +443,6 @@
 
   BrowserContext::Initialize(this, profile_path_);
 
-  browser_context_dependency_manager_->MarkBrowserContextLive(this);
-
 #if defined(OS_ANDROID)
   // Make sure token service knows its running in tests.
   OAuth2TokenServiceDelegateAndroid::set_is_testing_profile();
diff --git a/chrome/test/data/webui/md_bookmarks/command_manager_test.js b/chrome/test/data/webui/md_bookmarks/command_manager_test.js
index 1d12f83..fa168fa 100644
--- a/chrome/test/data/webui/md_bookmarks/command_manager_test.js
+++ b/chrome/test/data/webui/md_bookmarks/command_manager_test.js
@@ -58,6 +58,7 @@
     replaceBody(commandManager);
     document.body.appendChild(
         document.createElement('bookmarks-toast-manager'));
+    bookmarks.DialogFocusManager.instance_ = null;
   });
 
   test('Copy URL is only active for single URL items', function() {
@@ -164,7 +165,7 @@
     commandManager.assertLastCommand('redo');
   });
 
-  test.only('Show In Folder is only available during search', function() {
+  test('Show In Folder is only available during search', function() {
     store.data.selection.items = new Set(['12']);
     store.notifyObservers();
 
@@ -344,6 +345,21 @@
     MockInteractions.tap(commandItem[Command.EDIT]);
     commandManager.assertLastCommand(null);
   });
+
+  test('keyboard shortcuts are disabled while a dialog is open', function() {
+    assertFalse(bookmarks.DialogFocusManager.getInstance().hasOpenDialog());
+    items = new Set(['12']);
+    store.data.selection.items = items;
+    store.notifyObservers();
+
+    var editKey = cr.isMac ? 'Enter' : 'F2';
+    MockInteractions.pressAndReleaseKeyOn(document.body, '', '', editKey);
+    commandManager.assertLastCommand(Command.EDIT);
+    assertTrue(bookmarks.DialogFocusManager.getInstance().hasOpenDialog());
+
+    MockInteractions.pressAndReleaseKeyOn(document.body, '', '', 'Delete');
+    commandManager.assertLastCommand(null);
+  });
 });
 
 suite('<bookmarks-item> CommandManager integration', function() {
@@ -421,13 +437,4 @@
 
     assertOpenedTabs(['http://111/', 'http://13/']);
   });
-
-  test('meta-down triggers Open on Mac', function() {
-    if (!cr.isMac)
-      return;
-
-    customClick(items[0]);
-    MockInteractions.pressAndReleaseKeyOn(items[0], 0, 'meta', 'ArrowDown');
-    assertEquals('11', store.data.selectedFolder);
-  });
 });
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 db7ddc0..247c1cfaa 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
@@ -324,22 +324,22 @@
       var focusedItem = items[0];
       focusedItem.focus();
 
-      keydown(focusedItem, ' ', 'ctrl');
+      keydown(focusedItem, ' ', multiKey);
       assertDeepEquals(['2'], normalizeSet(store.data.selection.items));
 
-      keydown(focusedItem, 'ArrowDown', 'ctrl');
+      keydown(focusedItem, 'ArrowDown', multiKey);
       focusedItem = items[1];
       assertDeepEquals(['2'], normalizeSet(store.data.selection.items));
       assertEquals('3', store.data.selection.anchor);
 
-      keydown(focusedItem, 'ArrowDown', 'ctrl');
+      keydown(focusedItem, 'ArrowDown', multiKey);
       focusedItem = items[2];
       assertDeepEquals(['2'], normalizeSet(store.data.selection.items));
 
-      keydown(focusedItem, ' ', 'ctrl');
+      keydown(focusedItem, ' ', multiKey);
       assertDeepEquals(['2', '4'], normalizeSet(store.data.selection.items));
 
-      keydown(focusedItem, ' ', 'ctrl');
+      keydown(focusedItem, ' ', multiKey);
       assertDeepEquals(['2'], normalizeSet(store.data.selection.items));
     });
 
@@ -347,23 +347,23 @@
       var focusedItem = items[0];
       focusedItem.focus();
 
-      keydown(focusedItem, ' ', 'ctrl');
+      keydown(focusedItem, ' ', multiKey);
       assertDeepEquals(['2'], normalizeSet(store.data.selection.items));
 
-      keydown(focusedItem, 'ArrowDown', 'ctrl');
+      keydown(focusedItem, 'ArrowDown', multiKey);
       focusedItem = items[1];
       assertDeepEquals(['2'], normalizeSet(store.data.selection.items));
 
-      keydown(focusedItem, 'ArrowDown', 'ctrl');
+      keydown(focusedItem, 'ArrowDown', multiKey);
       focusedItem = items[2];
       assertDeepEquals(['2'], normalizeSet(store.data.selection.items));
 
-      keydown(focusedItem, 'ArrowDown', ['ctrl', 'shift']);
+      keydown(focusedItem, 'ArrowDown', [multiKey, 'shift']);
       focusedItem = items[3];
       assertDeepEquals(
           ['2', '4', '5'], normalizeSet(store.data.selection.items));
 
-      keydown(focusedItem, 'ArrowDown', ['ctrl', 'shift']);
+      keydown(focusedItem, 'ArrowDown', [multiKey, 'shift']);
       focusedItem = items[3];
       assertDeepEquals(
           ['2', '4', '5', '6'], normalizeSet(store.data.selection.items));
diff --git a/chrome/test/data/webui/md_bookmarks/test_util.js b/chrome/test/data/webui/md_bookmarks/test_util.js
index c1b2279..4499b03d 100644
--- a/chrome/test/data/webui/md_bookmarks/test_util.js
+++ b/chrome/test/data/webui/md_bookmarks/test_util.js
@@ -91,7 +91,8 @@
 }
 
 /**
- * Sends a custom click event to |element|.
+ * Sends a custom click event to |element|. All ctrl-clicks are automatically
+ * rewritten to command-clicks on Mac.
  * @param {HTMLElement} element
  * @param {Object=} config
  */
@@ -111,6 +112,11 @@
       props[key] = config[key];
   }
 
+  if (cr.isMac && props.ctrlKey) {
+    props.ctrlKey = false;
+    props.metaKey = true;
+  }
+
   element.dispatchEvent(new MouseEvent('mousedown', props));
   element.dispatchEvent(new MouseEvent('mouseup', props));
   element.dispatchEvent(new MouseEvent('click', props));
diff --git a/chrome/test/data/webui/md_bookmarks/toolbar_test.js b/chrome/test/data/webui/md_bookmarks/toolbar_test.js
index 9fa23a0..21444a7 100644
--- a/chrome/test/data/webui/md_bookmarks/toolbar_test.js
+++ b/chrome/test/data/webui/md_bookmarks/toolbar_test.js
@@ -127,5 +127,18 @@
 
     assertFalse(toolbar.canSortFolder_);
     assertTrue(toolbar.$$('#sortButton').disabled);
+
+    // Adding a bookmark should enable sorting.
+    store.setReducersEnabled(true);
+    var item = {
+      id: '51',
+      parentId: '5',
+      index: 0,
+      url: 'https://www.example.com',
+    };
+    store.dispatch(bookmarks.actions.createBookmark(
+        item.id, item));
+    assertTrue(toolbar.canSortFolder_);
+    assertFalse(toolbar.$$('#sortButton').disabled);
   });
 });
diff --git a/chrome/test/data/webui/settings/site_details_permission_tests.js b/chrome/test/data/webui/settings/site_details_permission_tests.js
index 997a11e..97a196db 100644
--- a/chrome/test/data/webui/settings/site_details_permission_tests.js
+++ b/chrome/test/data/webui/settings/site_details_permission_tests.js
@@ -12,22 +12,30 @@
 
   /**
    * An example pref with only camera allowed.
+   * @type {SiteSettingsPref}
    */
-  var prefs = {
-    exceptions: {
-      camera: [
-        {
-          embeddingOrigin: '',
-          origin: 'https://www.example.com',
-          setting: 'allow',
-          source: 'preference',
-        },
-      ]
-    }
-  };
+  var prefs;
 
   // Initialize a site-details-permission before each test.
   setup(function() {
+    prefs = {
+      defaults: {
+        camera: {
+          setting: settings.ContentSetting.ALLOW,
+        }
+      },
+      exceptions: {
+        camera: [
+          {
+            embeddingOrigin: '',
+            origin: 'https://www.example.com',
+            setting: settings.ContentSetting.ALLOW,
+            source: 'preference',
+          },
+        ]
+      }
+    };
+
     browserProxy = new TestSiteSettingsPrefsBrowserProxy();
     settings.SiteSettingsPrefsBrowserProxyImpl.instance_ = browserProxy;
     PolymerTest.clearBody();
@@ -45,25 +53,32 @@
   function isAllowed(origin, exceptionList) {
     for (var i = 0; i < exceptionList.length; ++i) {
       if (exceptionList[i].origin == origin)
-        return exceptionList[i].setting == 'allow';
+        return exceptionList[i].setting == settings.ContentSetting.ALLOW;
     }
     return false;
   };
 
   function validatePermissionFlipWorks(origin, expectedContentSetting) {
-    browserProxy.resetResolver('setCategoryPermissionForOrigin');
+    // Flipping a permission typically calls setCategoryPermissionForOrigin, but
+    // clearing it should call resetCategoryPermissionForOrigin.
+    var isReset = expectedContentSetting == settings.ContentSetting.DEFAULT;
+    var expectedMethodCalled = isReset ? 'resetCategoryPermissionForOrigin' :
+                                         'setCategoryPermissionForOrigin';
+    browserProxy.resetResolver(expectedMethodCalled);
 
     // Simulate permission change initiated by the user.
     testElement.$.permission.value = expectedContentSetting;
     testElement.$.permission.dispatchEvent(new CustomEvent('change'));
 
-    return browserProxy.whenCalled('setCategoryPermissionForOrigin')
-        .then(function(args) {
-          assertEquals(origin, args[0]);
-          assertEquals('', args[1]);
-          assertEquals(testElement.category, args[2]);
-          assertEquals(expectedContentSetting, args[3]);
-        });
+    return browserProxy.whenCalled(expectedMethodCalled).then(function(args) {
+      assertEquals(origin, args[0]);
+      assertEquals('', args[1]);
+      assertEquals(testElement.category, args[2]);
+      // Since resetting the permission doesn't return its new value, don't
+      // test it here - checking that the correct method was called is fine.
+      if (!isReset)
+        assertEquals(expectedContentSetting, args[3]);
+    });
   };
 
   test('camera category', function() {
@@ -92,6 +107,60 @@
         .then(function() {
           return validatePermissionFlipWorks(
               origin, settings.ContentSetting.ALLOW);
+        })
+        .then(function() {
+          return validatePermissionFlipWorks(
+              origin, settings.ContentSetting.DEFAULT);
+        });
+  });
+
+  test('default string is correct', function() {
+    var origin = 'https://www.example.com';
+    browserProxy.setPrefs(prefs)
+    testElement.category = settings.ContentSettingsTypes.CAMERA;
+    testElement.label = 'Camera';
+    testElement.site = {
+      origin: origin,
+      embeddingOrigin: '',
+      setting: settings.ContentSetting.ALLOW,
+    };
+
+    return browserProxy.whenCalled('getDefaultValueForContentType')
+        .then(function() {
+          // The default option will always be the first in the menu.
+          assertEquals(
+              'Allow (default)', testElement.$.permission.options[0].text,
+              'Default setting string should match prefs');
+          browserProxy.resetResolver('getDefaultValueForContentType');
+          prefs.defaults.camera.setting = settings.ContentSetting.BLOCK;
+          browserProxy.setPrefs(prefs);
+          // Trigger a call to siteChanged_() by touching |testElement.site|.
+          testElement.site = {
+            origin: origin,
+            embeddingOrigin: '',
+            setting: settings.ContentSetting.BLOCK
+          };
+          return browserProxy.whenCalled('getDefaultValueForContentType');
+        })
+        .then(function() {
+          assertEquals(
+              'Block (default)', testElement.$.permission.options[0].text,
+              'Default setting string should match prefs');
+          browserProxy.resetResolver('getDefaultValueForContentType');
+          prefs.defaults.camera.setting = settings.ContentSetting.ASK;
+          browserProxy.setPrefs(prefs);
+          // Trigger a call to siteChanged_() by touching |testElement.site|.
+          testElement.site = {
+            origin: origin,
+            embeddingOrigin: '',
+            setting: settings.ContentSetting.ASK
+          };
+          return browserProxy.whenCalled('getDefaultValueForContentType');
+        })
+        .then(function() {
+          assertEquals(
+              'Ask (default)', testElement.$.permission.options[0].text,
+              'Default setting string should match prefs');
         });
   });
 });
diff --git a/chrome/test/data/webui/settings/site_details_tests.js b/chrome/test/data/webui/settings/site_details_tests.js
index 37eb131..b2b73f1 100644
--- a/chrome/test/data/webui/settings/site_details_tests.js
+++ b/chrome/test/data/webui/settings/site_details_tests.js
@@ -11,103 +11,141 @@
   var testElement;
 
   /**
-   * An example pref with 1 allowed in each category.
+   * An example pref with 1 pref in each category.
+   * @type {SiteSettingsPref}
    */
-  var prefs = {
-    exceptions: {
-      auto_downloads: [
-        {
-          embeddingOrigin: 'https://foo-allow.com:443',
-          origin: 'https://foo-allow.com:443',
-          setting: 'allow',
-          source: 'preference',
-        },
-      ],
-      background_sync: [
-        {
-          embeddingOrigin: 'https://foo-allow.com:443',
-          origin: 'https://foo-allow.com:443',
-          setting: 'allow',
-          source: 'preference',
-        },
-      ],
-      camera: [
-        {
-          embeddingOrigin: 'https://foo-allow.com:443',
-          origin: 'https://foo-allow.com:443',
-          setting: 'allow',
-          source: 'extension',
-        },
-      ],
-      geolocation: [
-        {
-          embeddingOrigin: 'https://foo-allow.com:443',
-          origin: 'https://foo-allow.com:443',
-          setting: 'block',
-          source: 'policy',
-        },
-      ],
-      images: [
-        {
-          embeddingOrigin: 'https://foo-allow.com:443',
-          origin: 'https://foo-allow.com:443',
-          setting: 'allow',
-          source: 'preference',
-        },
-      ],
-      javascript: [
-        {
-          embeddingOrigin: 'https://foo-allow.com:443',
-          origin: 'https://foo-allow.com:443',
-          setting: 'allow',
-          source: 'preference',
-        },
-      ],
-      mic: [
-        {
-          embeddingOrigin: 'https://foo-allow.com:443',
-          origin: 'https://foo-allow.com:443',
-          setting: 'allow',
-          source: 'preference',
-        },
-      ],
-      notifications: [
-        {
-          embeddingOrigin: 'https://foo-allow.com:443',
-          origin: 'https://foo-allow.com:443',
-          setting: 'allow',
-          source: 'preference',
-        },
-      ],
-      plugins: [
-        {
-          embeddingOrigin: 'https://foo-allow.com:443',
-          origin: 'https://foo-allow.com:443',
-          setting: 'allow',
-          source: 'preference',
-        },
-      ],
-      popups: [
-        {
-          embeddingOrigin: 'https://foo-allow.com:443',
-          origin: 'https://foo-allow.com:443',
-          setting: 'allow',
-          source: 'preference',
-        },
-      ],
-      unsandboxed_plugins: [
-        {
-          embeddingOrigin: 'https://foo-allow.com:443',
-          origin: 'https://foo-allow.com:443',
-          setting: 'allow',
-          source: 'preference',
-        },
-      ],
-    }
-  };
+  var prefs;
 
   // Initialize a site-details before each test.
   setup(function() {
+    prefs = {
+      defaults: {
+        auto_downloads: {
+          setting: settings.ContentSetting.ASK,
+        },
+        background_sync: {
+          setting: settings.ContentSetting.ALLOW,
+        },
+        camera: {
+          setting: settings.ContentSetting.ASK,
+        },
+        geolocation: {
+          setting: settings.ContentSetting.ASK,
+        },
+        images: {
+          setting: settings.ContentSetting.ALLOW,
+        },
+        javascript: {
+          setting: settings.ContentSetting.ALLOW,
+        },
+        mic: {
+          setting: settings.ContentSetting.ASK,
+        },
+        notifications: {
+          setting: settings.ContentSetting.ASK,
+        },
+        plugins: {
+          setting: settings.ContentSetting.ASK,
+        },
+        popups: {
+          setting: settings.ContentSetting.BLOCK,
+        },
+        unsandboxed_plugins: {
+          setting: settings.ContentSetting.ASK,
+        },
+      },
+      exceptions: {
+        auto_downloads: [
+          {
+            embeddingOrigin: 'https://foo.com:443',
+            origin: 'https://foo.com:443',
+            setting: settings.ContentSetting.ALLOW,
+            source: 'preference',
+          },
+        ],
+        background_sync: [
+          {
+            embeddingOrigin: 'https://foo.com:443',
+            origin: 'https://foo.com:443',
+            setting: settings.ContentSetting.ALLOW,
+            source: 'preference',
+          },
+        ],
+        camera: [
+          {
+            embeddingOrigin: 'https://foo.com:443',
+            origin: 'https://foo.com:443',
+            setting: settings.ContentSetting.ALLOW,
+            source: 'preference',
+          },
+        ],
+        geolocation: [
+          {
+            embeddingOrigin: 'https://foo.com:443',
+            origin: 'https://foo.com:443',
+            setting: settings.ContentSetting.ALLOW,
+            source: 'preference',
+          },
+        ],
+        images: [
+          {
+            embeddingOrigin: 'https://foo.com:443',
+            origin: 'https://foo.com:443',
+            setting: settings.ContentSetting.ALLOW,
+            source: 'default',
+          },
+        ],
+        javascript: [
+          {
+            embeddingOrigin: 'https://foo.com:443',
+            origin: 'https://foo.com:443',
+            setting: settings.ContentSetting.ALLOW,
+            source: 'preference',
+          },
+        ],
+        mic: [
+          {
+            embeddingOrigin: 'https://foo.com:443',
+            origin: 'https://foo.com:443',
+            setting: settings.ContentSetting.ALLOW,
+            source: 'preference',
+          },
+        ],
+        notifications: [
+          {
+            embeddingOrigin: 'https://foo.com:443',
+            origin: 'https://foo.com:443',
+            setting: settings.ContentSetting.BLOCK,
+            source: 'policy',
+          },
+        ],
+        plugins: [
+          {
+            embeddingOrigin: 'https://foo.com:443',
+            origin: 'https://foo.com:443',
+            setting: settings.ContentSetting.ALLOW,
+            source: 'extension',
+          },
+        ],
+        popups: [
+          {
+            embeddingOrigin: 'https://foo.com:443',
+            origin: 'https://foo.com:443',
+            setting: settings.ContentSetting.BLOCK,
+            source: 'default',
+          },
+        ],
+        unsandboxed_plugins: [
+          {
+            embeddingOrigin: 'https://foo.com:443',
+            origin: 'https://foo.com:443',
+            setting: settings.ContentSetting.ALLOW,
+            source: 'preference',
+          },
+        ],
+      }
+    };
+
     browserProxy = new TestSiteSettingsPrefsBrowserProxy();
     settings.SiteSettingsPrefsBrowserProxyImpl.instance_ = browserProxy;
     PolymerTest.clearBody();
@@ -133,7 +171,7 @@
     Polymer.dom(parent).appendChild(api);
 
     browserProxy.setPrefs(prefs);
-    testElement.origin = 'https://foo-allow.com:443';
+    testElement.origin = 'https://foo.com:443';
 
     Polymer.dom.flush();
 
@@ -143,17 +181,40 @@
 
   test('correct pref settings are shown', function() {
     browserProxy.setPrefs(prefs);
-    testElement.origin = 'https://foo-allow.com:443';
+    testElement.origin = 'https://foo.com:443';
 
     return browserProxy.whenCalled('getOriginPermissions').then(function() {
       testElement.root.querySelectorAll('site-details-permission')
           .forEach(function(siteDetailsPermission) {
             // Verify settings match the values specified in |prefs|.
-            var setting = 'allow';
-            if (siteDetailsPermission.site.category == 'location')
-              setting = 'block';
-            assertEquals(setting, siteDetailsPermission.site.setting);
-            assertEquals(setting, siteDetailsPermission.$.permission.value);
+            var expectedSetting = settings.ContentSetting.ALLOW;
+            var expectedSource = 'preference';
+            var expectedMenuValue = settings.ContentSetting.ALLOW;
+
+            // For all the categories with non-user-set 'Allow' preferences,
+            // update expected values.
+            if (siteDetailsPermission.category ==
+                    settings.ContentSettingsTypes.NOTIFICATIONS ||
+                siteDetailsPermission.category ==
+                    settings.ContentSettingsTypes.PLUGINS ||
+                siteDetailsPermission.category ==
+                    settings.ContentSettingsTypes.JAVASCRIPT ||
+                siteDetailsPermission.category ==
+                    settings.ContentSettingsTypes.IMAGES ||
+                siteDetailsPermission.category ==
+                    settings.ContentSettingsTypes.POPUPS) {
+              expectedSetting =
+                  prefs.exceptions[siteDetailsPermission.category][0].setting;
+              expectedSource =
+                  prefs.exceptions[siteDetailsPermission.category][0].source;
+              expectedMenuValue = (expectedSource == 'default') ?
+                  settings.ContentSetting.DEFAULT :
+                  expectedSetting;
+            }
+            assertEquals(expectedSetting, siteDetailsPermission.site.setting);
+            assertEquals(expectedSource, siteDetailsPermission.site.source);
+            assertEquals(
+                expectedMenuValue, siteDetailsPermission.$.permission.value);
           });
     });
   });
diff --git a/chrome/test/data/webui/settings/site_list_tests.js b/chrome/test/data/webui/settings/site_list_tests.js
index 9b340576..810c1e5 100644
--- a/chrome/test/data/webui/settings/site_list_tests.js
+++ b/chrome/test/data/webui/settings/site_list_tests.js
@@ -546,7 +546,7 @@
             assertEquals(
                 kControlledByLookup[prefsMixedProvider.exceptions.geolocation[i]
                                         .source] ||
-                    '',
+                    chrome.settingsPrivate.ControlledBy.PRIMARY_USER,
                 testElement.sites[i].controlledBy);
           }
         });
diff --git a/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js b/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js
index 733ea20c3..d10e6e2d 100644
--- a/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js
+++ b/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js
@@ -3,53 +3,35 @@
 // found in the LICENSE file.
 
 /**
+ * In the real (non-test) code, this data comes from the C++ handler.
  * Only used for tests.
- * @typedef {{
- *   auto_downloads: !Array<!RawSiteException>},
- *   background_sync: !Array<!RawSiteException>},
- *   camera: !Array<!RawSiteException>},
- *   cookies: !Array<!RawSiteException>},
- *   geolocation: !Array<!RawSiteException>},
- *   javascript: !Array<!RawSiteException>},
- *   mic: !Array<!RawSiteException>},
- *   midiDevices: !Array<!RawSiteException>},
- *   notifications: !Array<!RawSiteException>},
- *   plugins: !Array<!RawSiteException>},
- *   images: !Array<!RawSiteException>},
- *   popups: !Array<!RawSiteException>},
- *   unsandboxed_plugins: !Array<!RawSiteException>},
- * }}
- */
-var ExceptionListPref;
-
-/**
- * In the real (non-test) code, these data come from the C++ handler.
- * Only used for tests.
- * @typedef {{defaults: CategoryDefaultsPref,
- *            exceptions: ExceptionListPref}}
+ * @typedef {{defaults: Map<string, !DefaultContentSetting>,
+ *            exceptions: !Map<string, !Array<!RawSiteException>>}}
  */
 var SiteSettingsPref;
 
 /**
  * An example empty pref.
+ * TODO(patricialor): Use the values from settings.ContentSettingsTypes (see
+ * site_settings/constants.js) as the keys for these instead.
  * @type {SiteSettingsPref}
  */
 var prefsEmpty = {
   defaults: {
-    ads: '',
-    auto_downloads: '',
-    background_sync: '',
-    camera: '',
-    cookies: '',
-    geolocation: '',
-    javascript: '',
-    mic: '',
-    midiDevices: '',
-    notifications: '',
-    plugins: '',
-    images: '',
-    popups: '',
-    unsandboxed_plugins: '',
+    ads: {},
+    auto_downloads: {},
+    background_sync: {},
+    camera: {},
+    cookies: {},
+    geolocation: {},
+    javascript: {},
+    mic: {},
+    midiDevices: {},
+    notifications: {},
+    plugins: {},
+    images: {},
+    popups: {},
+    unsandboxed_plugins: {},
   },
   exceptions: {
     ads: [],
@@ -203,10 +185,11 @@
     var pref = undefined;
     if (contentType == settings.ContentSettingsTypes.ADS) {
       pref = this.prefs_.defaults.ads;
-    } else if (contentType == settings.ContentSettingsTypes.AUTOMATIC_DOWNLOADS) {
+    } else if (
+        contentType == settings.ContentSettingsTypes.AUTOMATIC_DOWNLOADS) {
       pref = this.prefs_.defaults.auto_downloads;
     } else if (contentType == settings.ContentSettingsTypes.BACKGROUND_SYNC) {
-      pref = this.prefs_.background_sync;
+      pref = this.prefs_.defaults.background_sync;
     } else if (contentType == settings.ContentSettingsTypes.CAMERA) {
       pref = this.prefs_.defaults.camera;
     } else if (contentType == settings.ContentSettingsTypes.COOKIES) {
@@ -336,10 +319,12 @@
         contentType = 'unsandboxed_plugins';
       }
 
-      var setting = undefined;
+      var setting;
+      var source;
       this.prefs_.exceptions[contentType].some(function(originPrefs) {
         if (originPrefs.origin == origin) {
           setting = originPrefs.setting;
+          source = originPrefs.source;
           return true;
         }
       });
@@ -354,7 +339,7 @@
         origin: origin,
         displayName: '',
         setting: setting,
-        source: undefined
+        source: source,
       })
     }, this);
     return Promise.resolve(exceptionList);
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index 9330a21..a3b4353cc 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -536,8 +536,6 @@
     "cryptohome/mock_homedir_methods.h",
     "dbus/biod/test_utils.cc",
     "dbus/biod/test_utils.h",
-    "dbus/mock_cryptohome_client.cc",
-    "dbus/mock_cryptohome_client.h",
     "dbus/mock_lorgnette_manager_client.cc",
     "dbus/mock_lorgnette_manager_client.h",
     "dbus/mock_permission_broker_client.cc",
diff --git a/chromeos/dbus/mock_cryptohome_client.cc b/chromeos/dbus/mock_cryptohome_client.cc
deleted file mode 100644
index d0ed940..0000000
--- a/chromeos/dbus/mock_cryptohome_client.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/dbus/mock_cryptohome_client.h"
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-
-using ::testing::_;
-using ::testing::AnyNumber;
-using ::testing::Invoke;
-
-namespace chromeos {
-
-namespace {
-
-// Runs callback with true.
-void RunCallbackWithTrue(const BoolDBusMethodCallback& callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true));
-}
-
-}  // namespace
-
-MockCryptohomeClient::MockCryptohomeClient() {
-  EXPECT_CALL(*this, Init(_)).Times(AnyNumber());
-  ON_CALL(*this, IsMounted(_))
-      .WillByDefault(Invoke(&RunCallbackWithTrue));
-  ON_CALL(*this, InstallAttributesIsReady(_))
-      .WillByDefault(Invoke(&RunCallbackWithTrue));
-}
-
-MockCryptohomeClient::~MockCryptohomeClient() {}
-
-void MockCryptohomeClient::TpmCanAttemptOwnership(
-    VoidDBusMethodCallback callback) {
-  NOTREACHED() << "No mock for TmpCanAttemptOwnership.";
-}
-
-void MockCryptohomeClient::TpmClearStoredPassword(
-    VoidDBusMethodCallback callback) {
-  NOTREACHED() << "No mock for TmpClearStoredPassword.";
-}
-
-void MockCryptohomeClient::MigrateToDircrypto(
-    const cryptohome::Identification& cryptohome_id,
-    VoidDBusMethodCallback callback) {
-  NOTREACHED() << "No mock for MigrateToDircrypto.";
-}
-
-}  // namespace chromeos
diff --git a/chromeos/dbus/mock_cryptohome_client.h b/chromeos/dbus/mock_cryptohome_client.h
deleted file mode 100644
index 46acbe0e..0000000
--- a/chromeos/dbus/mock_cryptohome_client.h
+++ /dev/null
@@ -1,242 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_DBUS_MOCK_CRYPTOHOME_CLIENT_H_
-#define CHROMEOS_DBUS_MOCK_CRYPTOHOME_CLIENT_H_
-
-#include <stdint.h>
-
-#include <string>
-
-#include "chromeos/cryptohome/cryptohome_parameters.h"
-#include "chromeos/dbus/cryptohome/rpc.pb.h"
-#include "chromeos/dbus/cryptohome_client.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace chromeos {
-
-class MockCryptohomeClient : public CryptohomeClient {
- public:
-  MockCryptohomeClient();
-  virtual ~MockCryptohomeClient();
-
-  MOCK_METHOD1(Init, void(dbus::Bus* bus));
-  MOCK_METHOD2(SetAsyncCallStatusHandlers,
-               void(const AsyncCallStatusHandler& handler,
-                    const AsyncCallStatusWithDataHandler& data_handler));
-  MOCK_METHOD0(ResetAsyncCallStatusHandlers, void());
-  MOCK_METHOD1(SetLowDiskSpaceHandler,
-               void(const LowDiskSpaceHandler& handler));
-  MOCK_METHOD1(WaitForServiceToBeAvailable,
-               void(const WaitForServiceToBeAvailableCallback& callback));
-  MOCK_METHOD1(IsMounted, void(const BoolDBusMethodCallback& callback));
-  MOCK_METHOD1(Unmount, void(const BoolDBusMethodCallback& callback));
-  MOCK_METHOD3(AsyncCheckKey,
-               void(const cryptohome::Identification& cryptohome_id,
-                    const std::string& key,
-                    const AsyncMethodCallback& callback));
-  MOCK_METHOD4(AsyncMigrateKey,
-               void(const cryptohome::Identification& cryptohome_id,
-                    const std::string& from_key,
-                    const std::string& to_key,
-                    const AsyncMethodCallback& callback));
-  MOCK_METHOD2(AsyncRemove,
-               void(const cryptohome::Identification& cryptohome_id,
-                    const AsyncMethodCallback& callback));
-  MOCK_METHOD3(RenameCryptohome,
-               void(const cryptohome::Identification& id_from,
-                    const cryptohome::Identification& id_to,
-                    const ProtobufMethodCallback& callback));
-  MOCK_METHOD2(GetAccountDiskUsage,
-               void(const cryptohome::Identification& account_id,
-                    const ProtobufMethodCallback& callback));
-
-  MOCK_METHOD1(GetSystemSalt, void(const GetSystemSaltCallback& callback));
-  MOCK_METHOD2(GetSanitizedUsername,
-               void(const cryptohome::Identification& cryptohome_id,
-                    const StringDBusMethodCallback& callback));
-  MOCK_METHOD1(BlockingGetSanitizedUsername,
-               std::string(const cryptohome::Identification& cryptohome_id));
-  MOCK_METHOD4(AsyncMount,
-               void(const cryptohome::Identification& cryptohome_id,
-                    const std::string& key,
-                    int flags,
-                    const AsyncMethodCallback& callback));
-  MOCK_METHOD4(AsyncAddKey,
-               void(const cryptohome::Identification& cryptohome_id,
-                    const std::string& key,
-                    const std::string& new_key,
-                    const AsyncMethodCallback& callback));
-  MOCK_METHOD1(AsyncMountGuest,
-               void(const AsyncMethodCallback& callback));
-  MOCK_METHOD3(AsyncMountPublic,
-               void(const cryptohome::Identification& public_mount_id,
-                    int flags,
-                    const AsyncMethodCallback& callback));
-  MOCK_METHOD1(TpmIsReady, void(const BoolDBusMethodCallback& callback));
-  MOCK_METHOD1(TpmIsEnabled, void(const BoolDBusMethodCallback& callback));
-  MOCK_METHOD1(CallTpmIsEnabledAndBlock, bool(bool* enabled));
-  MOCK_METHOD1(TpmGetPassword, void(const StringDBusMethodCallback& callback));
-  MOCK_METHOD1(TpmIsOwned, void(const BoolDBusMethodCallback& callback));
-  MOCK_METHOD1(CallTpmIsOwnedAndBlock, bool(bool* owned));
-  MOCK_METHOD1(TpmIsBeingOwned, void(const BoolDBusMethodCallback& callback));
-  MOCK_METHOD1(CallTpmIsBeingOwnedAndBlock, bool(bool* owning));
-  void TpmCanAttemptOwnership(VoidDBusMethodCallback callback) override;
-  void TpmClearStoredPassword(VoidDBusMethodCallback callback) override;
-  MOCK_METHOD0(CallTpmClearStoredPasswordAndBlock, bool());
-  MOCK_METHOD1(Pkcs11IsTpmTokenReady,
-               void(const BoolDBusMethodCallback& callback));
-  MOCK_METHOD1(Pkcs11GetTpmTokenInfo,
-               void(const Pkcs11GetTpmTokenInfoCallback& callback));
-  MOCK_METHOD2(Pkcs11GetTpmTokenInfoForUser,
-               void(const cryptohome::Identification& cryptohome_id,
-                    const Pkcs11GetTpmTokenInfoCallback& callback));
-  MOCK_METHOD3(InstallAttributesGet,
-               bool(const std::string& name,
-                    std::vector<uint8_t>* value,
-                    bool* successful));
-  MOCK_METHOD3(InstallAttributesSet,
-               bool(const std::string& name,
-                    const std::vector<uint8_t>& value,
-                    bool* successful));
-  MOCK_METHOD1(InstallAttributesFinalize, bool(bool* successful));
-  MOCK_METHOD1(InstallAttributesIsReady,
-               void(const BoolDBusMethodCallback& callback));
-  MOCK_METHOD1(InstallAttributesIsInvalid, bool(bool* is_invalid));
-  MOCK_METHOD1(InstallAttributesIsFirstInstall, bool(bool* is_first_install));
-  MOCK_METHOD1(TpmAttestationIsPrepared,
-               void(const BoolDBusMethodCallback& callback));
-  MOCK_METHOD1(TpmAttestationIsEnrolled,
-               void(const BoolDBusMethodCallback& callback));
-  MOCK_METHOD2(AsyncTpmAttestationCreateEnrollRequest,
-               void(attestation::PrivacyCAType pca_type,
-                    const AsyncMethodCallback& callback));
-  MOCK_METHOD3(AsyncTpmAttestationEnroll,
-               void(attestation::PrivacyCAType pca_type,
-                    const std::string& pca_response,
-                    const AsyncMethodCallback& callback));
-  MOCK_METHOD5(
-      AsyncTpmAttestationCreateCertRequest,
-      void(attestation::PrivacyCAType pca_type,
-           attestation::AttestationCertificateProfile certificate_profile,
-           const cryptohome::Identification& cryptohome_id,
-           const std::string& request_origin,
-           const AsyncMethodCallback& callback));
-  MOCK_METHOD5(AsyncTpmAttestationFinishCertRequest,
-               void(const std::string& pca_response,
-                    attestation::AttestationKeyType key_type,
-                    const cryptohome::Identification& cryptohome_id,
-                    const std::string& key_name,
-                    const AsyncMethodCallback& callback));
-  MOCK_METHOD4(TpmAttestationDoesKeyExist,
-               void(attestation::AttestationKeyType key_type,
-                    const cryptohome::Identification& cryptohome_id,
-                    const std::string& key_name,
-                    const BoolDBusMethodCallback& callback));
-  MOCK_METHOD4(TpmAttestationGetCertificate,
-               void(attestation::AttestationKeyType key_type,
-                    const cryptohome::Identification& cryptohome_id,
-                    const std::string& key_name,
-                    const DataMethodCallback& callback));
-  MOCK_METHOD4(TpmAttestationGetPublicKey,
-               void(attestation::AttestationKeyType key_type,
-                    const cryptohome::Identification& cryptohome_id,
-                    const std::string& key_name,
-                    const DataMethodCallback& callback));
-  MOCK_METHOD4(TpmAttestationRegisterKey,
-               void(attestation::AttestationKeyType key_type,
-                    const cryptohome::Identification& cryptohome_id,
-                    const std::string& key_name,
-                    const AsyncMethodCallback& callback));
-  MOCK_METHOD8(TpmAttestationSignEnterpriseChallenge,
-               void(attestation::AttestationKeyType key_type,
-                    const cryptohome::Identification& cryptohome_id,
-                    const std::string& key_name,
-                    const std::string& domain,
-                    const std::string& device_id,
-                    attestation::AttestationChallengeOptions options,
-                    const std::string& challenge,
-                    const AsyncMethodCallback& callback));
-  MOCK_METHOD5(TpmAttestationSignSimpleChallenge,
-               void(attestation::AttestationKeyType key_type,
-                    const cryptohome::Identification& cryptohome_id,
-                    const std::string& key_name,
-                    const std::string& challenge,
-                    const AsyncMethodCallback& callback));
-  MOCK_METHOD4(TpmAttestationGetKeyPayload,
-               void(attestation::AttestationKeyType key_type,
-                    const cryptohome::Identification& cryptohome_id,
-                    const std::string& key_name,
-                    const DataMethodCallback& callback));
-  MOCK_METHOD5(TpmAttestationSetKeyPayload,
-               void(attestation::AttestationKeyType key_type,
-                    const cryptohome::Identification& cryptohome_id,
-                    const std::string& key_name,
-                    const std::string& payload,
-                    const BoolDBusMethodCallback& callback));
-  MOCK_METHOD4(TpmAttestationDeleteKeys,
-               void(attestation::AttestationKeyType key_type,
-                    const cryptohome::Identification& cryptohome_id,
-                    const std::string& key_prefix,
-                    const BoolDBusMethodCallback& callback));
-  MOCK_METHOD4(GetKeyDataEx,
-               void(const cryptohome::Identification& cryptohome_id,
-                    const cryptohome::AuthorizationRequest& auth,
-                    const cryptohome::GetKeyDataRequest& request,
-                    const ProtobufMethodCallback& callback));
-  MOCK_METHOD4(CheckKeyEx,
-               void(const cryptohome::Identification& cryptohome_id,
-                    const cryptohome::AuthorizationRequest& auth,
-                    const cryptohome::CheckKeyRequest& request,
-                    const ProtobufMethodCallback& callback));
-  MOCK_METHOD4(MountEx,
-               void(const cryptohome::Identification& cryptohome_id,
-                    const cryptohome::AuthorizationRequest& auth,
-                    const cryptohome::MountRequest& request,
-                    const ProtobufMethodCallback& callback));
-  MOCK_METHOD4(AddKeyEx,
-               void(const cryptohome::Identification& cryptohome_id,
-                    const cryptohome::AuthorizationRequest& auth,
-                    const cryptohome::AddKeyRequest& request,
-                    const ProtobufMethodCallback& callback));
-  MOCK_METHOD4(UpdateKeyEx,
-               void(const cryptohome::Identification& cryptohome_id,
-                    const cryptohome::AuthorizationRequest& auth,
-                    const cryptohome::UpdateKeyRequest& request,
-                    const ProtobufMethodCallback& callback));
-  MOCK_METHOD4(RemoveKeyEx,
-               void(const cryptohome::Identification& cryptohome_id,
-                    const cryptohome::AuthorizationRequest& auth,
-                    const cryptohome::RemoveKeyRequest& request,
-                    const ProtobufMethodCallback& callback));
-  MOCK_METHOD2(GetBootAttribute,
-               void(const cryptohome::GetBootAttributeRequest& request,
-                    const ProtobufMethodCallback& callback));
-  MOCK_METHOD2(SetBootAttribute,
-               void(const cryptohome::SetBootAttributeRequest& request,
-                    const ProtobufMethodCallback& callback));
-  MOCK_METHOD2(
-      FlushAndSignBootAttributes,
-      void(const cryptohome::FlushAndSignBootAttributesRequest& request,
-           const ProtobufMethodCallback& callback));
-  void MigrateToDircrypto(const cryptohome::Identification& cryptohome_id,
-                          VoidDBusMethodCallback callback) override;
-  MOCK_METHOD1(SetDircryptoMigrationProgressHandler,
-               void(const DircryptoMigrationProgessHandler& handler));
-  MOCK_METHOD2(
-      RemoveFirmwareManagementParametersFromTpm,
-      void(const cryptohome::RemoveFirmwareManagementParametersRequest& request,
-           const ProtobufMethodCallback& callback));
-  MOCK_METHOD2(
-      SetFirmwareManagementParametersInTpm,
-      void(const cryptohome::SetFirmwareManagementParametersRequest& request,
-           const ProtobufMethodCallback& callback));
-  MOCK_METHOD2(NeedsDircryptoMigration,
-               void(const cryptohome::Identification& cryptohome_id,
-                    const BoolDBusMethodCallback& callback));
-};
-
-}  // namespace chromeos
-
-#endif  // CHROMEOS_DBUS_MOCK_CRYPTOHOME_CLIENT_H_
diff --git a/components/component_updater/configurator_impl.cc b/components/component_updater/configurator_impl.cc
index 54f0bb69..efc46c51 100644
--- a/components/component_updater/configurator_impl.cc
+++ b/components/component_updater/configurator_impl.cc
@@ -198,10 +198,10 @@
 }
 
 std::vector<uint8_t> ConfiguratorImpl::GetRunActionKeyHash() const {
-  return std::vector<uint8_t>{0x97, 0xf0, 0xbe, 0xe4, 0x3f, 0x2b, 0x9e, 0xcf,
-                              0x2c, 0x50, 0x61, 0xdf, 0xc2, 0x6e, 0x0b, 0x4a,
-                              0x4f, 0x1e, 0xda, 0x71, 0x29, 0x64, 0x74, 0x70,
-                              0x15, 0x07, 0x18, 0xb7, 0x92, 0x04, 0xcd, 0x70};
+  return std::vector<uint8_t>{0x5f, 0x94, 0xe0, 0x3c, 0x64, 0x30, 0x9f, 0xbc,
+                              0xfe, 0x00, 0x9a, 0x27, 0x3e, 0x52, 0xbf, 0xa5,
+                              0x84, 0xb9, 0xb3, 0x75, 0x07, 0x29, 0xde, 0xfa,
+                              0x32, 0x76, 0xd9, 0x93, 0xb5, 0xa3, 0xce, 0x02};
 }
 
 }  // namespace component_updater
diff --git a/components/data_reduction_proxy/core/browser/data_store_impl.cc b/components/data_reduction_proxy/core/browser/data_store_impl.cc
index 3c7c180f..564b70b7 100644
--- a/components/data_reduction_proxy/core/browser/data_store_impl.cc
+++ b/components/data_reduction_proxy/core/browser/data_store_impl.cc
@@ -121,17 +121,15 @@
   // these log entries are deleted.
   options.reuse_logs = false;
   std::string db_name = profile_path_.Append(kDBName).AsUTF8Unsafe();
-  leveldb::DB* dbptr = nullptr;
+  db_.reset();
   Status status =
-      LevelDbToDRPStoreStatus(leveldb::DB::Open(options, db_name, &dbptr));
+      LevelDbToDRPStoreStatus(leveldb_env::OpenDB(options, db_name, &db_));
   UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.LevelDBOpenStatus", status,
                             STATUS_MAX);
 
   if (status != OK)
     LOG(ERROR) << "Failed to open Data Reduction Proxy DB: " << status;
 
-  db_.reset(dbptr);
-
   if (db_) {
     leveldb::Range range;
     uint64_t size;
@@ -139,7 +137,7 @@
     // lowest keys.
     range.start = "";
     range.limit = "z";  // Keys starting with 'z' will not be included.
-    dbptr->GetApproximateSizes(&range, 1, &size);
+    db_->GetApproximateSizes(&range, 1, &size);
     UMA_HISTOGRAM_MEMORY_KB("DataReductionProxy.LevelDBSize", size / 1024);
   }
 
diff --git a/components/download/internal/config.cc b/components/download/internal/config.cc
index b7ede40..02bcfdde 100644
--- a/components/download/internal/config.cc
+++ b/components/download/internal/config.cc
@@ -29,23 +29,29 @@
 
 // Default value for file keep alive time in minutes, keep the file alive for
 // 12 hours by default.
-const uint32_t kDefaultFileKeepAliveTimeMinutes = 12 * 60;
+const base::TimeDelta kDefaultFileKeepAliveTime =
+    base::TimeDelta::FromHours(12);
 
 // Default value for file cleanup window in minutes, the system will schedule a
 // cleanup task within this window.
-const uint32_t kDefaultFileCleanupWindowMinutes = 24 * 60;
+const base::TimeDelta kDefaultFileCleanupWindow =
+    base::TimeDelta::FromHours(24);
 
 // Default value for the start window time for OS to schedule background task.
-const uint32_t kDefaultWindowStartTimeSeconds = 300; /* 5 minutes. */
+const base::TimeDelta kDefaultWindowStartTime = base::TimeDelta::FromMinutes(5);
 
 // Default value for the end window time for OS to schedule background task.
-const uint32_t kDefaultWindowEndTimeSeconds = 3600 * 8; /* 8 hours. */
+const base::TimeDelta kDefaultWindowEndTime = base::TimeDelta::FromHours(8);
 
 // The default delay to notify the observer when network changes from
 // disconnected to connected.
 const base::TimeDelta kDefaultNetworkChangeDelay =
     base::TimeDelta::FromSeconds(5);
 
+// The default value of download retry delay when the download is failed.
+const base::TimeDelta kDefaultDownloadRetryDelay =
+    base::TimeDelta::FromSeconds(20);
+
 // Helper routine to get Finch experiment parameter. If no Finch seed was found,
 // use the |default_value|. The |name| should match an experiment
 // parameter in Finch server configuration.
@@ -70,20 +76,27 @@
   config->max_retry_count =
       GetFinchConfigUInt(kMaxRetryCountConfig, kDefaultMaxRetryCount);
   config->file_keep_alive_time =
-      base::TimeDelta::FromMinutes(base::saturated_cast<int>(GetFinchConfigUInt(
-          kFileKeepAliveTimeMinutesConfig, kDefaultFileKeepAliveTimeMinutes)));
+      base::TimeDelta::FromMinutes(base::saturated_cast<int>(
+          GetFinchConfigUInt(kFileKeepAliveTimeMinutesConfig,
+                             kDefaultFileKeepAliveTime.InMinutes())));
   config->file_cleanup_window =
-      base::TimeDelta::FromMinutes(base::saturated_cast<int>(GetFinchConfigUInt(
-          kFileCleanupWindowMinutesConfig, kDefaultFileCleanupWindowMinutes)));
-  config->window_start_time_seconds = GetFinchConfigUInt(
-      kWindowStartTimeConfig, kDefaultWindowStartTimeSeconds);
-  config->window_end_time_seconds =
-      GetFinchConfigUInt(kWindowEndTimeConfig, kDefaultWindowEndTimeSeconds);
+      base::TimeDelta::FromMinutes(base::saturated_cast<int>(
+          GetFinchConfigUInt(kFileCleanupWindowMinutesConfig,
+                             kDefaultFileCleanupWindow.InMinutes())));
+  config->window_start_time =
+      base::TimeDelta::FromSeconds(base::saturated_cast<int>(GetFinchConfigUInt(
+          kWindowStartTimeSecondsConfig, kDefaultWindowStartTime.InSeconds())));
+  config->window_end_time =
+      base::TimeDelta::FromSeconds(base::saturated_cast<int>(GetFinchConfigUInt(
+          kWindowEndTimeSecondsConfig, kDefaultWindowEndTime.InSeconds())));
   config->network_change_delay =
       base::TimeDelta::FromMilliseconds(base::saturated_cast<int>(
-          GetFinchConfigUInt(kNetworkChangeDelayConfig,
+          GetFinchConfigUInt(kNetworkChangeDelayMsConfig,
                              kDefaultNetworkChangeDelay.InMilliseconds())));
-
+  config->download_retry_delay =
+      base::TimeDelta::FromMilliseconds(base::saturated_cast<int>(
+          GetFinchConfigUInt(kDownloadRetryDelayMsConfig,
+                             kDefaultDownloadRetryDelay.InMilliseconds())));
   return config;
 }
 
@@ -92,12 +105,11 @@
       max_running_downloads(kDefaultMaxRunningDownloads),
       max_scheduled_downloads(kDefaultMaxScheduledDownloads),
       max_retry_count(kDefaultMaxRetryCount),
-      file_keep_alive_time(base::TimeDelta::FromMinutes(
-          base::saturated_cast<int>(kDefaultFileKeepAliveTimeMinutes))),
-      file_cleanup_window(base::TimeDelta::FromMinutes(
-          base::saturated_cast<int>(kDefaultFileCleanupWindowMinutes))),
-      window_start_time_seconds(kDefaultWindowStartTimeSeconds),
-      window_end_time_seconds(kDefaultWindowEndTimeSeconds),
-      network_change_delay(kDefaultNetworkChangeDelay) {}
+      file_keep_alive_time(kDefaultFileKeepAliveTime),
+      file_cleanup_window(kDefaultFileCleanupWindow),
+      window_start_time(kDefaultWindowStartTime),
+      window_end_time(kDefaultWindowEndTime),
+      network_change_delay(kDefaultNetworkChangeDelay),
+      download_retry_delay(kDefaultDownloadRetryDelay) {}
 
 }  // namespace download
diff --git a/components/download/internal/config.h b/components/download/internal/config.h
index 1b22a4f..073676fc 100644
--- a/components/download/internal/config.h
+++ b/components/download/internal/config.h
@@ -31,14 +31,18 @@
 constexpr char kFileCleanupWindowMinutesConfig[] = "file_cleanup_window";
 
 // Configuration name for window start time.
-constexpr char kWindowStartTimeConfig[] = "window_start_time_seconds";
+constexpr char kWindowStartTimeSecondsConfig[] = "window_start_time_seconds";
 
 // Configuration name for window end time.
-constexpr char kWindowEndTimeConfig[] = "window_end_time_seconds";
+constexpr char kWindowEndTimeSecondsConfig[] = "window_end_time_seconds";
 
 // Configuration name for the delay to notify network status change, measured in
 // milliseconds.
-constexpr char kNetworkChangeDelayConfig[] = "network_change_delay_ms";
+constexpr char kNetworkChangeDelayMsConfig[] = "network_change_delay_ms";
+
+// Configuration name for the retry delay when the download is failed, measured
+// in milliseconds.
+constexpr char kDownloadRetryDelayMsConfig[] = "retry_delay_ms";
 
 // Download service configuration.
 //
@@ -75,15 +79,18 @@
 
   // The start window time in seconds for OS to schedule background task.
   // The OS will trigger the background task in this window.
-  uint32_t window_start_time_seconds;
+  base::TimeDelta window_start_time;
 
   // The end window time in seconds for OS to schedule background task.
   // The OS will trigger the background task in this window.
-  uint32_t window_end_time_seconds;
+  base::TimeDelta window_end_time;
 
   // The delay to notify network status changes.
   base::TimeDelta network_change_delay;
 
+  // The delay to retry a download when the download is failed.
+  base::TimeDelta download_retry_delay;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Configuration);
 };
diff --git a/components/download/internal/controller_impl.cc b/components/download/internal/controller_impl.cc
index 9e9a583..03fa70c 100644
--- a/components/download/internal/controller_impl.cc
+++ b/components/download/internal/controller_impl.cc
@@ -363,7 +363,14 @@
   }
 
   if (failure_type == FailureType::RECOVERABLE) {
-    UpdateDriverState(entry);
+    // Because the network offline signal comes later than actual download
+    // failure, retry the download after a delay to avoid the retry to fail
+    // immediately again.
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&ControllerImpl::UpdateDriverStateWithGuid,
+                   weak_ptr_factory_.GetWeakPtr(), download.guid),
+        config_->download_retry_delay);
   } else {
     // TODO(dtrainor, xingliu): We probably have to prevent cancel calls from
     // coming through here as we remove downloads (especially through
@@ -720,6 +727,12 @@
     UpdateDriverState(entry);
 }
 
+void ControllerImpl::UpdateDriverStateWithGuid(const std::string& guid) {
+  Entry* entry = model_->Get(guid);
+  if (entry)
+    UpdateDriverState(entry);
+}
+
 void ControllerImpl::UpdateDriverState(Entry* entry) {
   DCHECK_EQ(controller_state_, State::READY);
 
diff --git a/components/download/internal/controller_impl.h b/components/download/internal/controller_impl.h
index 2b644de..911ada78 100644
--- a/components/download/internal/controller_impl.h
+++ b/components/download/internal/controller_impl.h
@@ -131,6 +131,9 @@
   // service.
   void UpdateDriverStates();
 
+  // See |UpdateDriverState|.
+  void UpdateDriverStateWithGuid(const std::string& guid);
+
   // Processes the download based on the state of |entry|. May start, pause
   // or resume a download accordingly.
   void UpdateDriverState(Entry* entry);
diff --git a/components/download/internal/controller_impl_unittest.cc b/components/download/internal/controller_impl_unittest.cc
index e047209..5a5a7a1 100644
--- a/components/download/internal/controller_impl_unittest.cc
+++ b/components/download/internal/controller_impl_unittest.cc
@@ -863,9 +863,12 @@
   driver_->NotifyDownloadFailed(dentry2, FailureType::RECOVERABLE);
   driver_->NotifyDownloadFailed(dentry2, FailureType::RECOVERABLE);
   driver_->NotifyDownloadFailed(dentry2, FailureType::RECOVERABLE);
-  EXPECT_EQ(nullptr, model_->Get(entry2.guid));
+  // Failed entry should exist because we retry after a delay.
+  EXPECT_NE(nullptr, model_->Get(entry2.guid));
 
   task_runner_->RunUntilIdle();
+  // Retry is done, and failed entry should be removed.
+  EXPECT_EQ(nullptr, model_->Get(entry2.guid));
 }
 
 TEST_F(DownloadServiceControllerImplTest, OnDownloadSucceeded) {
diff --git a/components/download/internal/scheduler/scheduler_impl.cc b/components/download/internal/scheduler/scheduler_impl.cc
index 9b5b34c..8ee8f73 100644
--- a/components/download/internal/scheduler/scheduler_impl.cc
+++ b/components/download/internal/scheduler/scheduler_impl.cc
@@ -59,8 +59,8 @@
   task_scheduler_->ScheduleTask(
       DownloadTaskType::DOWNLOAD_TASK, criteria.requires_unmetered_network,
       criteria.requires_battery_charging,
-      base::saturated_cast<long>(config_->window_start_time_seconds),
-      base::saturated_cast<long>(config_->window_end_time_seconds));
+      base::saturated_cast<long>(config_->window_start_time.InSeconds()),
+      base::saturated_cast<long>(config_->window_end_time.InSeconds()));
 }
 
 Entry* SchedulerImpl::Next(const Model::EntryList& entries,
diff --git a/components/drive/resource_metadata_storage.cc b/components/drive/resource_metadata_storage.cc
index 0c49407c..7d601a1 100644
--- a/components/drive/resource_metadata_storage.cc
+++ b/components/drive/resource_metadata_storage.cc
@@ -269,14 +269,15 @@
     return false;
 
   // Open DB.
-  leveldb::DB* db = NULL;
+  std::unique_ptr<leveldb::DB> resource_map;
   leveldb::Options options;
   options.max_open_files = 0;  // Use minimum.
   options.create_if_missing = false;
   options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
-  if (!leveldb::DB::Open(options, resource_map_path.AsUTF8Unsafe(), &db).ok())
+  leveldb::Status status = leveldb_env::OpenDB(
+      options, resource_map_path.AsUTF8Unsafe(), &resource_map);
+  if (!status.ok())
     return false;
-  std::unique_ptr<leveldb::DB> resource_map(db);
 
   // Check DB version.
   std::string serialized_header;
@@ -552,7 +553,6 @@
   }
 
   // Try to open the existing DB.
-  leveldb::DB* db = NULL;
   leveldb::Options options;
   options.max_open_files = 0;  // Use minimum.
   options.create_if_missing = false;
@@ -561,13 +561,12 @@
   DBInitStatus open_existing_result = DB_INIT_NOT_FOUND;
   leveldb::Status status;
   if (base::PathExists(resource_map_path)) {
-    status = leveldb::DB::Open(options, resource_map_path.AsUTF8Unsafe(), &db);
+    status = leveldb_env::OpenDB(options, resource_map_path.AsUTF8Unsafe(),
+                                 &resource_map_);
     open_existing_result = LevelDBStatusToDBInitStatus(status);
   }
 
   if (open_existing_result == DB_INIT_SUCCESS) {
-    resource_map_.reset(db);
-
     // Check the validity of existing DB.
     int db_version = -1;
     ResourceMetadataHeader header;
@@ -610,10 +609,9 @@
     options.error_if_exists = true;
     options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
 
-    status = leveldb::DB::Open(options, resource_map_path.AsUTF8Unsafe(), &db);
+    status = leveldb_env::OpenDB(options, resource_map_path.AsUTF8Unsafe(),
+                                 &resource_map_);
     if (status.ok()) {
-      resource_map_.reset(db);
-
       // Set up header and trash the old DB.
       if (PutHeader(GetDefaultHeaderEntry()) == FILE_ERROR_OK &&
           MoveIfPossible(preserved_resource_map_path,
@@ -676,14 +674,13 @@
   }
 
   // Open it.
-  leveldb::DB* db = NULL;
-  status = leveldb::DB::Open(options, trashed_resource_map_path.AsUTF8Unsafe(),
-                             &db);
+  std::unique_ptr<leveldb::DB> resource_map;
+  status = leveldb_env::OpenDB(
+      options, trashed_resource_map_path.AsUTF8Unsafe(), &resource_map);
   if (!status.ok()) {
     LOG(ERROR) << "Failed to open trashed DB: " << status.ToString();
     return;
   }
-  std::unique_ptr<leveldb::DB> resource_map(db);
 
   // Check DB version.
   std::string serialized_header;
diff --git a/components/leveldb/leveldb_database_impl.cc b/components/leveldb/leveldb_database_impl.cc
index d8ae4e2..f0f509a 100644
--- a/components/leveldb/leveldb_database_impl.cc
+++ b/components/leveldb/leveldb_database_impl.cc
@@ -16,6 +16,7 @@
 #include "base/trace_event/memory_dump_manager.h"
 #include "components/leveldb/env_mojo.h"
 #include "components/leveldb/public/cpp/util.h"
+#include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
 
@@ -310,11 +311,10 @@
                          cache_->TotalCharge());
   }
 
-  const char* system_allocator_name =
-      base::trace_event::MemoryDumpManager::GetInstance()
-          ->system_allocator_pool_name();
-  if (system_allocator_name)
-    pmd->AddSuballocation(mad->guid(), system_allocator_name);
+  // All leveldb databases are already dumped by leveldb_env::DBTracker. Add
+  // an edge to avoid double counting.
+  pmd->AddSuballocation(mad->guid(),
+                        leveldb_env::DBTracker::GetMemoryDumpName(db_.get()));
 
   if (memory_dump_id_) {
     auto* global_dump = pmd->CreateSharedGlobalAllocatorDump(*memory_dump_id_);
diff --git a/components/leveldb/leveldb_service_impl.cc b/components/leveldb/leveldb_service_impl.cc
index a26f0ba..a640616 100644
--- a/components/leveldb/leveldb_service_impl.cc
+++ b/components/leveldb/leveldb_service_impl.cc
@@ -68,15 +68,14 @@
       leveldb::NewLRUCache(open_options->block_cache_size));
   options.block_cache = cache.get();
 
-  leveldb::DB* db = nullptr;
-  leveldb::Status s = leveldb::DB::Open(options, dbname, &db);
+  std::unique_ptr<leveldb::DB> db;
+  leveldb::Status s = leveldb_env::OpenDB(options, dbname, &db);
 
   if (s.ok()) {
-    mojo::MakeStrongAssociatedBinding(
-        base::MakeUnique<LevelDBDatabaseImpl>(std::move(env_mojo),
-                                              base::WrapUnique(db),
-                                              std::move(cache), memory_dump_id),
-        std::move(database));
+    mojo::MakeStrongAssociatedBinding(base::MakeUnique<LevelDBDatabaseImpl>(
+                                          std::move(env_mojo), std::move(db),
+                                          std::move(cache), memory_dump_id),
+                                      std::move(database));
   }
 
   std::move(callback).Run(LeveldbStatusToError(s));
@@ -95,13 +94,13 @@
       leveldb::NewMemEnv(leveldb::Env::Default()));
   options.env = env.get();
 
-  leveldb::DB* db = nullptr;
-  leveldb::Status s = leveldb::DB::Open(options, "", &db);
+  std::unique_ptr<leveldb::DB> db;
+  leveldb::Status s = leveldb_env::OpenDB(options, "", &db);
 
   if (s.ok()) {
     mojo::MakeStrongAssociatedBinding(
-        base::MakeUnique<LevelDBDatabaseImpl>(
-            std::move(env), base::WrapUnique(db), nullptr, memory_dump_id),
+        base::MakeUnique<LevelDBDatabaseImpl>(std::move(env), std::move(db),
+                                              nullptr, memory_dump_id),
         std::move(database));
   }
 
diff --git a/components/leveldb_proto/leveldb_database.cc b/components/leveldb_proto/leveldb_database.cc
index e3903f6..073dbec 100644
--- a/components/leveldb_proto/leveldb_database.cc
+++ b/components/leveldb_proto/leveldb_database.cc
@@ -62,19 +62,15 @@
 
   std::string path = database_dir.AsUTF8Unsafe();
 
-  leveldb::DB* db = NULL;
-  leveldb::Status status = leveldb::DB::Open(options, path, &db);
+  leveldb::Status status = leveldb_env::OpenDB(options, path, &db_);
   if (open_histogram_)
     open_histogram_->Add(leveldb_env::GetLevelDBStatusUMAValue(status));
   if (status.IsCorruption()) {
     base::DeleteFile(database_dir, true);
-    status = leveldb::DB::Open(options, path, &db);
+    status = leveldb_env::OpenDB(options, path, &db_);
   }
 
   if (status.ok()) {
-    CHECK(db);
-    db_.reset(db);
-
     base::trace_event::MemoryDumpManager::GetInstance()
         ->RegisterDumpProviderWithSequencedTaskRunner(
             this, "LevelDB", base::SequencedTaskRunnerHandle::Get(),
@@ -223,12 +219,10 @@
     dump->AddString("client_name", "", client_name_);
   }
 
-  // Memory is allocated from system allocator (malloc).
-  const char* system_allocator_pool_name =
-      base::trace_event::MemoryDumpManager::GetInstance()
-          ->system_allocator_pool_name();
-  if (system_allocator_pool_name)
-    pmd->AddSuballocation(dump->guid(), system_allocator_pool_name);
+  // All leveldb databases are already dumped by leveldb_env::DBTracker. Add
+  // an edge to avoid double counting.
+  pmd->AddSuballocation(dump->guid(),
+                        leveldb_env::DBTracker::GetMemoryDumpName(db_.get()));
 
   return true;
 }
diff --git a/components/leveldb_proto/proto_database_impl_unittest.cc b/components/leveldb_proto/proto_database_impl_unittest.cc
index c198b50c..691d774 100644
--- a/components/leveldb_proto/proto_database_impl_unittest.cc
+++ b/components/leveldb_proto/proto_database_impl_unittest.cc
@@ -647,16 +647,13 @@
       new base::trace_event::ProcessMemoryDump(nullptr, dump_args));
   db->OnMemoryDump(dump_args, process_memory_dump.get());
 
-  const auto& allocator_dumps = process_memory_dump->allocator_dumps();
-  const char* system_allocator_pool_name =
-      base::trace_event::MemoryDumpManager::GetInstance()
-          ->system_allocator_pool_name();
-  size_t expected_dump_count = system_allocator_pool_name ? 2 : 1;
-  EXPECT_EQ(expected_dump_count, allocator_dumps.size());
-  for (const auto& dump : allocator_dumps) {
-    ASSERT_TRUE(dump.first.find("leveldb/leveldb_proto/") == 0 ||
-                dump.first.find(system_allocator_pool_name) == 0);
+  size_t leveldb_dump_count = 0;
+  for (const auto& dump : process_memory_dump->allocator_dumps()) {
+    if (dump.first.find("leveldb/leveldb_proto/") == 0) {
+      leveldb_dump_count++;
+    }
   }
+  ASSERT_EQ(1u, leveldb_dump_count);
 }
 
 }  // namespace leveldb_proto
diff --git a/components/metrics/field_trials_provider.cc b/components/metrics/field_trials_provider.cc
index 90e13e62..25287d56 100644
--- a/components/metrics/field_trials_provider.cc
+++ b/components/metrics/field_trials_provider.cc
@@ -4,6 +4,7 @@
 
 #include "components/metrics/field_trials_provider.h"
 
+#include "base/strings/string_piece.h"
 #include "components/metrics/proto/system_profile.pb.h"
 #include "components/variations/active_field_trials.h"
 #include "components/variations/synthetic_trial_registry.h"
@@ -24,35 +25,41 @@
 
 }  // namespace
 
-FieldTrialsProvider::FieldTrialsProvider(SyntheticTrialRegistry* registry)
-    : registry_(registry) {}
+FieldTrialsProvider::FieldTrialsProvider(SyntheticTrialRegistry* registry,
+                                         base::StringPiece suffix)
+    : registry_(registry), suffix_(suffix) {}
 FieldTrialsProvider::~FieldTrialsProvider() = default;
 
 void FieldTrialsProvider::GetFieldTrialIds(
     std::vector<ActiveGroupId>* field_trial_ids) const {
   // We use the default field trial suffixing (no suffix).
-  variations::GetFieldTrialActiveGroupIds(base::StringPiece(), field_trial_ids);
+  variations::GetFieldTrialActiveGroupIds(suffix_, field_trial_ids);
 }
 
 void FieldTrialsProvider::OnDidCreateMetricsLog() {
-  creation_times_.push_back(base::TimeTicks::Now());
+  if (registry_) {
+    creation_times_.push_back(base::TimeTicks::Now());
+  }
 }
 
 void FieldTrialsProvider::ProvideSystemProfileMetrics(
     metrics::SystemProfileProto* system_profile_proto) {
-  base::TimeTicks creation_time;
-  // Should always be true, but don't crash even if there is a bug.
-  if (!creation_times_.empty()) {
-    creation_time = creation_times_.back();
-    creation_times_.pop_back();
-  }
-  std::vector<ActiveGroupId> synthetic_trials;
-  registry_->GetSyntheticFieldTrialsOlderThan(creation_time, &synthetic_trials);
-
   std::vector<ActiveGroupId> field_trial_ids;
   GetFieldTrialIds(&field_trial_ids);
   WriteFieldTrials(field_trial_ids, system_profile_proto);
-  WriteFieldTrials(synthetic_trials, system_profile_proto);
+
+  if (registry_) {
+    base::TimeTicks creation_time;
+    // Should always be true, but don't crash even if there is a bug.
+    if (!creation_times_.empty()) {
+      creation_time = creation_times_.back();
+      creation_times_.pop_back();
+    }
+    std::vector<ActiveGroupId> synthetic_trials;
+    registry_->GetSyntheticFieldTrialsOlderThan(creation_time,
+                                                &synthetic_trials);
+    WriteFieldTrials(synthetic_trials, system_profile_proto);
+  }
 }
 
 }  // namespace variations
diff --git a/components/metrics/field_trials_provider.h b/components/metrics/field_trials_provider.h
index 6242a20d..d93988e 100644
--- a/components/metrics/field_trials_provider.h
+++ b/components/metrics/field_trials_provider.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "base/strings/string_piece.h"
 #include "base/time/time.h"
 #include "components/metrics/metrics_provider.h"
 
@@ -21,7 +22,8 @@
 class FieldTrialsProvider : public metrics::MetricsProvider {
  public:
   // |registry| must outlive this metrics provider.
-  FieldTrialsProvider(SyntheticTrialRegistry* registry);
+  FieldTrialsProvider(SyntheticTrialRegistry* registry,
+                      base::StringPiece suffix);
   ~FieldTrialsProvider() override;
 
   // metrics::MetricsProvider:
@@ -36,6 +38,9 @@
 
   SyntheticTrialRegistry* registry_;
 
+  // Suffix used for the field trial names before they are hashed for uploads.
+  std::string suffix_;
+
   // A stack of log creation times.
   // While the initial metrics log exists, there will be two logs open.
   // Use a stack so that we use the right creation time for the first ongoing
diff --git a/components/metrics/field_trials_provider_unittest.cc b/components/metrics/field_trials_provider_unittest.cc
index 25c31c5d8..c8b04fe 100644
--- a/components/metrics/field_trials_provider_unittest.cc
+++ b/components/metrics/field_trials_provider_unittest.cc
@@ -18,8 +18,8 @@
 
 class TestProvider : public FieldTrialsProvider {
  public:
-  TestProvider(SyntheticTrialRegistry* registry)
-      : FieldTrialsProvider(registry) {}
+  TestProvider(SyntheticTrialRegistry* registry, base::StringPiece suffix)
+      : FieldTrialsProvider(registry, suffix) {}
   ~TestProvider() override {}
 
   void GetFieldTrialIds(
@@ -83,7 +83,7 @@
 };
 
 TEST_F(FieldTrialsProviderTest, ProvideSyntheticTrials) {
-  TestProvider provider(&registry_);
+  TestProvider provider(&registry_, base::StringPiece());
 
   RegisterExpectedSyntheticTrials();
   // Make sure these trials are older than the log.
diff --git a/components/metrics/metrics_service.cc b/components/metrics/metrics_service.cc
index ef1d389..fae8af3 100644
--- a/components/metrics/metrics_service.cc
+++ b/components/metrics/metrics_service.cc
@@ -140,6 +140,7 @@
 #include "base/metrics/sparse_histogram.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/single_thread_task_runner.h"
+#include "base/strings/string_piece.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/tracked_objects.h"
@@ -236,7 +237,7 @@
       base::MakeUnique<StabilityMetricsProvider>(local_state_));
 
   RegisterMetricsProvider(base::MakeUnique<variations::FieldTrialsProvider>(
-      &synthetic_trial_registry_));
+      &synthetic_trial_registry_, base::StringPiece()));
 }
 
 MetricsService::~MetricsService() {
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index 18b68d8..72382870 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -76,7 +76,13 @@
 // in memory allows the suggest server to respond more quickly with
 // personalized suggestions as the user types.
 const base::Feature kSearchProviderWarmUpOnFocus{
-    "OmniboxWarmUpSearchProviderOnFocus", base::FEATURE_DISABLED_BY_DEFAULT};
+  "OmniboxWarmUpSearchProviderOnFocus",
+#if defined(OS_IOS)
+      base::FEATURE_DISABLED_BY_DEFAULT
+#else
+      base::FEATURE_ENABLED_BY_DEFAULT
+#endif
+};
 
 // Feature used to enable the transmission of HTTPS URLs as part of the
 // context to the suggest server (assuming SearchProvider is permitted to
diff --git a/components/prefs/pref_service_factory.cc b/components/prefs/pref_service_factory.cc
index 7b21ae0..8e5d807 100644
--- a/components/prefs/pref_service_factory.cc
+++ b/components/prefs/pref_service_factory.cc
@@ -41,14 +41,16 @@
 }
 
 std::unique_ptr<PrefService> PrefServiceFactory::Create(
-    PrefRegistry* pref_registry) {
+    PrefRegistry* pref_registry,
+    std::unique_ptr<PrefValueStore::Delegate> delegate) {
   PrefNotifierImpl* pref_notifier = new PrefNotifierImpl();
   std::unique_ptr<PrefService> pref_service(new PrefService(
       pref_notifier,
       new PrefValueStore(managed_prefs_.get(), supervised_user_prefs_.get(),
                          extension_prefs_.get(), command_line_prefs_.get(),
                          user_prefs_.get(), recommended_prefs_.get(),
-                         pref_registry->defaults().get(), pref_notifier),
+                         pref_registry->defaults().get(), pref_notifier,
+                         std::move(delegate)),
       user_prefs_.get(), pref_registry, read_error_callback_, async_));
   return pref_service;
 }
diff --git a/components/prefs/pref_service_factory.h b/components/prefs/pref_service_factory.h
index 0427543..c9781c8 100644
--- a/components/prefs/pref_service_factory.h
+++ b/components/prefs/pref_service_factory.h
@@ -12,6 +12,7 @@
 #include "components/prefs/persistent_pref_store.h"
 #include "components/prefs/pref_registry.h"
 #include "components/prefs/pref_store.h"
+#include "components/prefs/pref_value_store.h"
 
 class PrefService;
 
@@ -67,7 +68,9 @@
 
   // Creates a PrefService object initialized with the parameters from
   // this factory.
-  std::unique_ptr<PrefService> Create(PrefRegistry* registry);
+  std::unique_ptr<PrefService> Create(
+      PrefRegistry* registry,
+      std::unique_ptr<PrefValueStore::Delegate> delegate = nullptr);
 
  protected:
   scoped_refptr<PrefStore> managed_prefs_;
diff --git a/components/proximity_auth/remote_device_life_cycle_impl.cc b/components/proximity_auth/remote_device_life_cycle_impl.cc
index 011786f..4940c15b 100644
--- a/components/proximity_auth/remote_device_life_cycle_impl.cc
+++ b/components/proximity_auth/remote_device_life_cycle_impl.cc
@@ -88,8 +88,8 @@
 
 std::unique_ptr<cryptauth::ConnectionFinder>
 RemoteDeviceLifeCycleImpl::CreateConnectionFinder() {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)) {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)) {
     return base::MakeUnique<BluetoothLowEnergyConnectionFinder>(
         remote_device_, bluetooth_throttler_);
   } else {
diff --git a/components/proximity_auth/switches.cc b/components/proximity_auth/switches.cc
index 44f6b3d..668fcc5b 100644
--- a/components/proximity_auth/switches.cc
+++ b/components/proximity_auth/switches.cc
@@ -7,9 +7,9 @@
 namespace proximity_auth {
 namespace switches {
 
-// Enables discovery of the phone over Bluetooth Low Energy.
-const char kEnableBluetoothLowEnergyDiscovery[] =
-    "enable-proximity-auth-bluetooth-low-energy-discovery";
+// Disables discovery of the phone over Bluetooth Low Energy.
+const char kDisableBluetoothLowEnergyDiscovery[] =
+    "disable-proximity-auth-bluetooth-low-energy-discovery";
 
 // Enables the use of EasyUnlock to log into the Chromebook.
 extern const char kEnableChromeOSLogin[] =
diff --git a/components/proximity_auth/switches.h b/components/proximity_auth/switches.h
index 0ec6d182..55854515 100644
--- a/components/proximity_auth/switches.h
+++ b/components/proximity_auth/switches.h
@@ -8,7 +8,7 @@
 namespace proximity_auth {
 namespace switches {
 
-extern const char kEnableBluetoothLowEnergyDiscovery[];
+extern const char kDisableBluetoothLowEnergyDiscovery[];
 extern const char kEnableChromeOSLogin[];
 extern const char kEnableForcePasswordReauth[];
 extern const char kForceLoadEasyUnlockAppInTests[];
diff --git a/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc b/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc
index b3628a3..7e7bfefc 100644
--- a/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc
+++ b/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/strings/stringprintf.h"
 #include "content/public/common/resource_type.h"
 #include "content/public/renderer/render_frame.h"
@@ -20,9 +21,25 @@
 
 WebSocketSBHandshakeThrottle::WebSocketSBHandshakeThrottle(
     mojom::SafeBrowsing* safe_browsing)
-    : callbacks_(nullptr), safe_browsing_(safe_browsing), weak_factory_(this) {}
+    : callbacks_(nullptr),
+      safe_browsing_(safe_browsing),
+      result_(Result::UNKNOWN),
+      weak_factory_(this) {}
 
-WebSocketSBHandshakeThrottle::~WebSocketSBHandshakeThrottle() {}
+WebSocketSBHandshakeThrottle::~WebSocketSBHandshakeThrottle() {
+  // ThrottleHandshake() should always be called, but since that is done all the
+  // way over in Blink, just avoid logging if it is not called rather than
+  // DCHECK()ing.
+  if (start_time_.is_null())
+    return;
+  if (result_ == Result::UNKNOWN) {
+    result_ = Result::ABANDONED;
+    UMA_HISTOGRAM_TIMES("SafeBrowsing.WebSocket.Elapsed.Abandoned",
+                        base::TimeTicks::Now() - start_time_);
+  }
+  UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.WebSocket.Result", result_,
+                            Result::RESULT_COUNT);
+}
 
 void WebSocketSBHandshakeThrottle::ThrottleHandshake(
     const blink::WebURL& url,
@@ -38,6 +55,7 @@
         content::RenderFrame::FromWebFrame(web_local_frame)->GetRoutingID();
   }
   int load_flags = 0;
+  start_time_ = base::TimeTicks::Now();
   safe_browsing_->CreateCheckerAndCheck(
       render_frame_id, mojo::MakeRequest(&url_checker_), url, load_flags,
       content::RESOURCE_TYPE_SUB_RESOURCE,
@@ -46,9 +64,17 @@
 }
 
 void WebSocketSBHandshakeThrottle::OnCheckResult(bool safe) {
+  DCHECK(!start_time_.is_null());
+  base::TimeDelta elapsed = base::TimeTicks::Now() - start_time_;
   if (safe) {
+    result_ = Result::SAFE;
+    UMA_HISTOGRAM_TIMES("SafeBrowsing.WebSocket.Elapsed.Safe", elapsed);
     callbacks_->OnSuccess();
   } else {
+    // When the insterstitial is dismissed the page is navigated and this object
+    // is destroyed before reaching here.
+    result_ = Result::BLOCKED;
+    UMA_HISTOGRAM_TIMES("SafeBrowsing.WebSocket.Elapsed.Blocked", elapsed);
     callbacks_->OnError(blink::WebString::FromUTF8(base::StringPrintf(
         "WebSocket connection to %s failed safe browsing check",
         url_.spec().c_str())));
diff --git a/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h b/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h
index 8bb27f9..71a2c73 100644
--- a/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h
+++ b/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h
@@ -12,6 +12,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/time/time.h"
 #include "components/safe_browsing/common/safe_browsing.mojom.h"
 #include "third_party/WebKit/public/platform/WebCallbacks.h"
 #include "third_party/WebKit/public/platform/WebSocketHandshakeThrottle.h"
@@ -30,12 +31,22 @@
       blink::WebCallbacks<void, const blink::WebString&>* callbacks) override;
 
  private:
+  // These values are logged to UMA so do not renumber or reuse.
+  enum class Result {
+    UNKNOWN = 0,
+    SAFE = 1,
+    BLOCKED = 2,
+    ABANDONED = 3,
+    RESULT_COUNT
+  };
   void OnCheckResult(bool safe);
 
   GURL url_;
   blink::WebCallbacks<void, const blink::WebString&>* callbacks_;
   mojom::SafeBrowsingUrlCheckerPtr url_checker_;
   mojom::SafeBrowsing* safe_browsing_;
+  base::TimeTicks start_time_;
+  Result result_;
 
   base::WeakPtrFactory<WebSocketSBHandshakeThrottle> weak_factory_;
 
diff --git a/components/sync/engine/attachments/on_disk_attachment_store.cc b/components/sync/engine/attachments/on_disk_attachment_store.cc
index e4f083b..15a83a25 100644
--- a/components/sync/engine/attachments/on_disk_attachment_store.cc
+++ b/components/sync/engine/attachments/on_disk_attachment_store.cc
@@ -359,7 +359,6 @@
   DCHECK(!db_);
   base::FilePath leveldb_path = path.Append(kLeveldbDirectory);
 
-  leveldb::DB* db_raw;
   std::unique_ptr<leveldb::DB> db;
   leveldb::Options options;
   options.create_if_missing = true;
@@ -367,15 +366,13 @@
   // TODO(pavely): crbug/424287 Consider adding info_log, block_cache and
   // filter_policy to options.
   leveldb::Status status =
-      leveldb::DB::Open(options, leveldb_path.AsUTF8Unsafe(), &db_raw);
+      leveldb_env::OpenDB(options, leveldb_path.AsUTF8Unsafe(), &db);
   if (!status.ok()) {
-    DVLOG(1) << "DB::Open failed: status=" << status.ToString()
+    DVLOG(1) << "OpenDB failed: status=" << status.ToString()
              << ", path=" << path.AsUTF8Unsafe();
     return AttachmentStore::UNSPECIFIED_ERROR;
   }
 
-  db.reset(db_raw);
-
   attachment_store_pb::StoreMetadata metadata;
   status = ReadStoreMetadata(db.get(), &metadata);
   if (!status.ok() && !status.IsNotFound()) {
diff --git a/components/sync/engine/attachments/on_disk_attachment_store_unittest.cc b/components/sync/engine/attachments/on_disk_attachment_store_unittest.cc
index 640a1a8..3554c4e 100644
--- a/components/sync/engine/attachments/on_disk_attachment_store_unittest.cc
+++ b/components/sync/engine/attachments/on_disk_attachment_store_unittest.cc
@@ -19,6 +19,7 @@
 #include "components/sync/engine_impl/attachments/proto/attachment_store.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/options.h"
 #include "third_party/leveldatabase/src/include/leveldb/slice.h"
@@ -103,13 +104,13 @@
   }
 
   std::unique_ptr<leveldb::DB> OpenLevelDB() {
-    leveldb::DB* db;
+    std::unique_ptr<leveldb::DB> db;
     leveldb::Options options;
     options.create_if_missing = true;
     leveldb::Status s =
-        leveldb::DB::Open(options, db_path_.AsUTF8Unsafe(), &db);
+        leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db);
     EXPECT_TRUE(s.ok());
-    return base::WrapUnique(db);
+    return db;
   }
 
   void UpdateRecord(const std::string& key, const std::string& content) {
diff --git a/components/sync/model_impl/model_type_store_backend.cc b/components/sync/model_impl/model_type_store_backend.cc
index a1745312..45ff1bc 100644
--- a/components/sync/model_impl/model_type_store_backend.cc
+++ b/components/sync/model_impl/model_type_store_backend.cc
@@ -178,7 +178,6 @@
 
 leveldb::Status ModelTypeStoreBackend::OpenDatabase(const std::string& path,
                                                     leveldb::Env* env) {
-  leveldb::DB* db_raw = nullptr;
   leveldb::Options options;
   options.create_if_missing = true;
   options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
@@ -186,11 +185,7 @@
   if (env)
     options.env = env;
 
-  leveldb::Status status = leveldb::DB::Open(options, path, &db_raw);
-  DCHECK(status.ok() != (db_raw == nullptr));
-  if (status.ok())
-    db_.reset(db_raw);
-  return status;
+  return leveldb_env::OpenDB(options, path, &db_);
 }
 
 leveldb::Status ModelTypeStoreBackend::DestroyDatabase(const std::string& path,
diff --git a/components/update_client/crx_downloader.cc b/components/update_client/crx_downloader.cc
index de4a774..afdfdbf6 100644
--- a/components/update_client/crx_downloader.cc
+++ b/components/update_client/crx_downloader.cc
@@ -124,7 +124,6 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 
   if (!result.error)
-
     base::PostTaskWithTraits(
         FROM_HERE,
         {base::MayBlock(), base::TaskPriority::BACKGROUND,
diff --git a/components/update_client/crx_downloader_unittest.cc b/components/update_client/crx_downloader_unittest.cc
index 7a97aef..40440085 100644
--- a/components/update_client/crx_downloader_unittest.cc
+++ b/components/update_client/crx_downloader_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "components/update_client/update_client_errors.h"
+#include "components/update_client/utils.h"
 #include "net/base/net_errors.h"
 #include "net/url_request/test_url_request_interceptor.h"
 #include "net/url_request/url_request_test_util.h"
@@ -165,6 +166,7 @@
 }
 
 void CrxDownloaderTest::RunThreadsUntilIdle() {
+  scoped_task_environment_.RunUntilIdle();
   base::RunLoop().RunUntilIdle();
 }
 
@@ -222,7 +224,8 @@
   EXPECT_EQ(1843, download_complete_result_.total_bytes);
   EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file));
 
-  EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false));
+  EXPECT_TRUE(
+      DeleteFileAndEmptyParentDirectory(download_complete_result_.response));
 
   EXPECT_LE(1, num_progress_calls_);
   EXPECT_EQ(1843, download_progress_result_.downloaded_bytes);
@@ -291,7 +294,8 @@
   EXPECT_EQ(1843, download_complete_result_.total_bytes);
   EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file));
 
-  EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false));
+  EXPECT_TRUE(
+      DeleteFileAndEmptyParentDirectory(download_complete_result_.response));
 
   EXPECT_LE(1, num_progress_calls_);
   EXPECT_EQ(1843, download_progress_result_.downloaded_bytes);
@@ -370,7 +374,8 @@
   EXPECT_EQ(1843, download_complete_result_.total_bytes);
   EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file));
 
-  EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false));
+  EXPECT_TRUE(
+      DeleteFileAndEmptyParentDirectory(download_complete_result_.response));
 
   EXPECT_LE(1, num_progress_calls_);
   EXPECT_EQ(1843, download_progress_result_.downloaded_bytes);
@@ -402,7 +407,8 @@
   EXPECT_EQ(1843, download_complete_result_.total_bytes);
   EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file));
 
-  EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false));
+  EXPECT_TRUE(
+      DeleteFileAndEmptyParentDirectory(download_complete_result_.response));
 
   EXPECT_LE(1, num_progress_calls_);
   EXPECT_EQ(1843, download_progress_result_.downloaded_bytes);
diff --git a/components/update_client/url_fetcher_downloader.cc b/components/update_client/url_fetcher_downloader.cc
index 33214c1..03e6190 100644
--- a/components/update_client/url_fetcher_downloader.cc
+++ b/components/update_client/url_fetcher_downloader.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/files/file_util.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/sequenced_task_runner.h"
@@ -21,22 +22,43 @@
 #include "net/url_request/url_fetcher.h"
 #include "url/gurl.h"
 
+namespace {
+
+constexpr base::TaskTraits kTaskTraits = {
+    base::MayBlock(), base::TaskPriority::BACKGROUND,
+    base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN};
+
+}  // namespace
+
 namespace update_client {
 
 UrlFetcherDownloader::UrlFetcherDownloader(
     std::unique_ptr<CrxDownloader> successor,
     net::URLRequestContextGetter* context_getter)
-    : CrxDownloader(std::move(successor)),
-      context_getter_(context_getter),
-      downloaded_bytes_(-1),
-      total_bytes_(-1) {}
+    : CrxDownloader(std::move(successor)), context_getter_(context_getter) {}
 
 UrlFetcherDownloader::~UrlFetcherDownloader() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 }
 
 void UrlFetcherDownloader::DoStartDownload(const GURL& url) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  base::PostTaskWithTraitsAndReply(
+      FROM_HERE, kTaskTraits,
+      base::BindOnce(&UrlFetcherDownloader::CreateDownloadDir,
+                     base::Unretained(this)),
+      base::BindOnce(&UrlFetcherDownloader::StartURLFetch,
+                     base::Unretained(this), url));
+}
+
+void UrlFetcherDownloader::CreateDownloadDir() {
+  base::CreateNewTempDirectory(FILE_PATH_LITERAL("chrome_url_fetcher_"),
+                               &download_dir_);
+}
+
+void UrlFetcherDownloader::StartURLFetch(const GURL& url) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   net::NetworkTrafficAnnotationTag traffic_annotation =
       net::DefineNetworkTrafficAnnotation("url_fetcher_downloader", R"(
@@ -67,6 +89,30 @@
           }
         })");
 
+  if (download_dir_.empty()) {
+    Result result;
+    result.error = -1;
+    result.downloaded_bytes = downloaded_bytes_;
+    result.total_bytes = total_bytes_;
+
+    DownloadMetrics download_metrics;
+    download_metrics.url = url;
+    download_metrics.downloader = DownloadMetrics::kUrlFetcher;
+    download_metrics.error = -1;
+    download_metrics.downloaded_bytes = downloaded_bytes_;
+    download_metrics.total_bytes = total_bytes_;
+    download_metrics.download_time_ms = 0;
+
+    main_task_runner()->PostTask(
+        FROM_HERE, base::BindOnce(&UrlFetcherDownloader::OnDownloadComplete,
+                                  base::Unretained(this), false, result,
+                                  download_metrics));
+    return;
+  }
+
+  const base::FilePath response =
+      download_dir_.AppendASCII(url.ExtractFileName());
+
   url_fetcher_ = net::URLFetcher::Create(0, url, net::URLFetcher::GET, this,
                                          traffic_annotation);
   url_fetcher_->SetRequestContext(context_getter_);
@@ -74,10 +120,8 @@
                              net::LOAD_DO_NOT_SAVE_COOKIES |
                              net::LOAD_DISABLE_CACHE);
   url_fetcher_->SetAutomaticallyRetryOn5xx(false);
-  url_fetcher_->SaveResponseToTemporaryFile(
-      base::CreateSequencedTaskRunnerWithTraits(
-          {base::MayBlock(), base::TaskPriority::BACKGROUND,
-           base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
+  url_fetcher_->SaveResponseToFileAtPath(
+      response, base::CreateSequencedTaskRunnerWithTraits(kTaskTraits));
   data_use_measurement::DataUseUserData::AttachToFetcher(
       url_fetcher_.get(), data_use_measurement::DataUseUserData::UPDATE_CLIENT);
 
@@ -85,13 +129,10 @@
   url_fetcher_->Start();
 
   download_start_time_ = base::TimeTicks::Now();
-
-  downloaded_bytes_ = -1;
-  total_bytes_ = -1;
 }
 
 void UrlFetcherDownloader::OnURLFetchComplete(const net::URLFetcher* source) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   const base::TimeTicks download_end_time(base::TimeTicks::Now());
   const base::TimeDelta download_time =
@@ -121,16 +162,20 @@
   download_metrics.total_bytes = total_bytes_;
   download_metrics.download_time_ms = download_time.InMilliseconds();
 
-  base::FilePath local_path_;
-  source->GetResponseAsFilePath(false, &local_path_);
   VLOG(1) << "Downloaded " << downloaded_bytes_ << " bytes in "
           << download_time.InMilliseconds() << "ms from "
-          << source->GetURL().spec() << " to " << local_path_.value();
+          << source->GetURL().spec() << " to " << result.response.value();
+
+  // Delete the download directory in the error cases.
+  if (fetch_error && !download_dir_.empty())
+    base::PostTaskWithTraits(
+        FROM_HERE, kTaskTraits,
+        base::BindOnce(IgnoreResult(&base::DeleteFile), download_dir_, true));
 
   main_task_runner()->PostTask(
-      FROM_HERE,
-      base::Bind(&UrlFetcherDownloader::OnDownloadComplete,
-                 base::Unretained(this), is_handled, result, download_metrics));
+      FROM_HERE, base::BindOnce(&UrlFetcherDownloader::OnDownloadComplete,
+                                base::Unretained(this), is_handled, result,
+                                download_metrics));
 }
 
 void UrlFetcherDownloader::OnURLFetchDownloadProgress(
@@ -138,7 +183,7 @@
     int64_t current,
     int64_t total,
     int64_t current_network_bytes) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   downloaded_bytes_ = current;
   total_bytes_ = total;
diff --git a/components/update_client/url_fetcher_downloader.h b/components/update_client/url_fetcher_downloader.h
index 46d2e66..cb81fbc 100644
--- a/components/update_client/url_fetcher_downloader.h
+++ b/components/update_client/url_fetcher_downloader.h
@@ -9,6 +9,7 @@
 
 #include <memory>
 
+#include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread_checker.h"
@@ -42,15 +43,22 @@
                                   int64_t current,
                                   int64_t total,
                                   int64_t current_network_bytes) override;
+
+  void CreateDownloadDir();
+  void StartURLFetch(const GURL& url);
+
+  THREAD_CHECKER(thread_checker_);
+
   std::unique_ptr<net::URLFetcher> url_fetcher_;
-  net::URLRequestContextGetter* context_getter_;
+  net::URLRequestContextGetter* context_getter_ = nullptr;
+
+  // Contains a temporary download directory for the downloaded file.
+  base::FilePath download_dir_;
 
   base::TimeTicks download_start_time_;
 
-  int64_t downloaded_bytes_;
-  int64_t total_bytes_;
-
-  base::ThreadChecker thread_checker_;
+  int64_t downloaded_bytes_ = -1;
+  int64_t total_bytes_ = -1;
 
   DISALLOW_COPY_AND_ASSIGN(UrlFetcherDownloader);
 };
diff --git a/components/viz/DEPS b/components/viz/DEPS
index 565ba60..c4d836f 100644
--- a/components/viz/DEPS
+++ b/components/viz/DEPS
@@ -1,4 +1,4 @@
 include_rules = [
-  "+mojo/edk/embedder",
-  "+ui/gl",
+  "-components/viz",
+  "+components/viz/common",
 ]
diff --git a/components/viz/client/DEPS b/components/viz/client/DEPS
index 3450aad8..78b21a84 100644
--- a/components/viz/client/DEPS
+++ b/components/viz/client/DEPS
@@ -3,6 +3,7 @@
   "-cc/blink",
   "-cc/test",
 
+  "+components/viz/client",
   "+mojo/public/cpp/bindings",
   "+mojo/public/cpp/system",
   "+ui/gfx/geometry",
diff --git a/components/viz/host/DEPS b/components/viz/host/DEPS
index 18cdf15..b6198f4b 100644
--- a/components/viz/host/DEPS
+++ b/components/viz/host/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+cc/ipc",
   "+cc/surfaces",
+  "+components/viz/host",
   "+gpu/command_buffer/client",
   "+gpu/command_buffer/common",
   "+gpu/ipc/client",
@@ -10,3 +11,13 @@
   "+services/ui/gpu/interfaces",
   "+ui/gfx",
 ]
+
+specific_include_rules = {
+  "host_frame_sink_manager.*": [
+    "+components/viz/service/frame_sinks/compositor_frame_sink_support.h",
+    "+components/viz/service/frame_sinks/compositor_frame_sink_support_client.h",
+    "+components/viz/service/frame_sinks/frame_sink_manager.h",
+    "+components/viz/service/frame_sinks/frame_sink_manager_impl.h",
+    "+components/viz/service/frame_sinks/compositor_frame_sink_support_manager.h",
+  ]
+}
diff --git a/components/viz/service/DEPS b/components/viz/service/DEPS
index 878bb265..19ccf893 100644
--- a/components/viz/service/DEPS
+++ b/components/viz/service/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+cc",
+  "+components/viz/service",
   "+third_party/skia",
   "+ui/gfx",
   "+ui/gfx/geometry",
diff --git a/components/viz/service/frame_sinks/DEPS b/components/viz/service/frame_sinks/DEPS
index 8e8b659..af562e2 100644
--- a/components/viz/service/frame_sinks/DEPS
+++ b/components/viz/service/frame_sinks/DEPS
@@ -3,7 +3,6 @@
   "+cc/ipc",
   "+cc/surfaces",
   "+cc/scheduler",
-  "+components/viz/display_embedder",
   "+gpu/ipc/common",
   "+mojo/public/cpp/bindings",
 ]
diff --git a/components/viz/test/DEPS b/components/viz/test/DEPS
index 549a9a59..01edd97 100644
--- a/components/viz/test/DEPS
+++ b/components/viz/test/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+cc",
+  "+components/viz",
   "+ui/gfx/geometry",
 ]
 
diff --git a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
index 16720977..9bd47a3 100644
--- a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
+++ b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
@@ -976,13 +976,12 @@
   {
     // Mess up version number in database.
     leveldb_env::ChromiumEnv env;
-    leveldb::DB* db = nullptr;
+    std::unique_ptr<leveldb::DB> db;
     leveldb::Options options;
     options.env = &env;
     base::FilePath db_path =
         temp_path().Append(test_path).Append(FILE_PATH_LITERAL("leveldb"));
-    ASSERT_TRUE(leveldb::DB::Open(options, db_path.AsUTF8Unsafe(), &db).ok());
-    std::unique_ptr<leveldb::DB> db_owner(db);
+    ASSERT_TRUE(leveldb_env::OpenDB(options, db_path.AsUTF8Unsafe(), &db).ok());
     ASSERT_TRUE(db->Put(leveldb::WriteOptions(), "VERSION", "argh").ok());
   }
 
diff --git a/content/browser/dom_storage/session_storage_database.cc b/content/browser/dom_storage/session_storage_database.cc
index 0bf1caa..2e3d8f7 100644
--- a/content/browser/dom_storage/session_storage_database.cc
+++ b/content/browser/dom_storage/session_storage_database.cc
@@ -357,12 +357,10 @@
   mad->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
                  base::trace_event::MemoryAllocatorDump::kUnitsBytes, size);
 
-  // Memory is allocated from system allocator (malloc).
-  const char* system_allocator_name =
-      base::trace_event::MemoryDumpManager::GetInstance()
-          ->system_allocator_pool_name();
-  if (system_allocator_name)
-    pmd->AddSuballocation(mad->guid(), system_allocator_name);
+  // All leveldb databases are already dumped by leveldb_env::DBTracker. Add
+  // an edge to avoid double counting.
+  pmd->AddSuballocation(mad->guid(),
+                        leveldb_env::DBTracker::GetMemoryDumpName(db_.get()));
 }
 
 bool SessionStorageDatabase::LazyOpen(bool create_if_needed) {
@@ -383,16 +381,14 @@
     return false;
   }
 
-  leveldb::DB* db;
-  leveldb::Status s = TryToOpen(&db);
+  leveldb::Status s = TryToOpen(&db_);
   if (!s.ok()) {
     LOG(WARNING) << "Failed to open leveldb in " << file_path_.value()
                  << ", error: " << s.ToString();
-    DCHECK(db == NULL);
 
     // Clear the directory and try again.
     base::DeleteFile(file_path_, true);
-    s = TryToOpen(&db);
+    s = TryToOpen(&db_);
     if (!s.ok()) {
       LOG(WARNING) << "Failed to open leveldb in " << file_path_.value()
                    << ", error: " << s.ToString();
@@ -420,7 +416,6 @@
         NOTREACHED();
       }
 
-      DCHECK(db == NULL);
       db_error_ = true;
       return false;
     }
@@ -432,11 +427,11 @@
                               SESSION_STORAGE_UMA_SUCCESS,
                               SESSION_STORAGE_UMA_MAX);
   }
-  db_.reset(db);
   return true;
 }
 
-leveldb::Status SessionStorageDatabase::TryToOpen(leveldb::DB** db) {
+leveldb::Status SessionStorageDatabase::TryToOpen(
+    std::unique_ptr<leveldb::DB>* db) {
   leveldb::Options options;
   // The directory exists but a valid leveldb database might not exist inside it
   // (e.g., a subset of the needed files might be missing). Handle this
@@ -447,7 +442,7 @@
   // Default write_buffer_size is 4 MB but that might leave a 3.999
   // memory allocation in RAM from a log file recovery.
   options.write_buffer_size = 64 * 1024;
-  return leveldb::DB::Open(options, file_path_.AsUTF8Unsafe(), db);
+  return leveldb_env::OpenDB(options, file_path_.AsUTF8Unsafe(), db);
 }
 
 bool SessionStorageDatabase::IsOpen() const {
diff --git a/content/browser/dom_storage/session_storage_database.h b/content/browser/dom_storage/session_storage_database.h
index 81c6313..2c48aec2 100644
--- a/content/browser/dom_storage/session_storage_database.h
+++ b/content/browser/dom_storage/session_storage_database.h
@@ -102,7 +102,7 @@
 
   // Tries to open the database at file_path_, assigns |db| to point to the
   // opened leveldb::DB instance.
-  leveldb::Status TryToOpen(leveldb::DB** db);
+  leveldb::Status TryToOpen(std::unique_ptr<leveldb::DB>* db);
 
   // Returns true if the database is already open, false otherwise.
   bool IsOpen() const;
diff --git a/content/browser/indexed_db/leveldb/leveldb_database.cc b/content/browser/indexed_db/leveldb/leveldb_database.cc
index 541cf3b..2e61cfd2 100644
--- a/content/browser/indexed_db/leveldb/leveldb_database.cc
+++ b/content/browser/indexed_db/leveldb/leveldb_database.cc
@@ -155,11 +155,7 @@
   options.block_cache = default_block_cache;
 
   // ChromiumEnv assumes UTF8, converts back to FilePath before using.
-  leveldb::DB* db_ptr = nullptr;
-  leveldb::Status s = leveldb::DB::Open(options, path.AsUTF8Unsafe(), &db_ptr);
-  db->reset(db_ptr);
-
-  return s;
+  return leveldb_env::OpenDB(options, path.AsUTF8Unsafe(), db);
 }
 
 leveldb::Status LevelDBDatabase::Destroy(const base::FilePath& file_name) {
@@ -506,10 +502,11 @@
 
   dump->AddString("file_name", "", file_name_for_tracing);
 
-  // Memory is allocated from system allocator (malloc).
+  // All leveldb databases are already dumped by leveldb_env::DBTracker. Add
+  // an edge to avoid double counting.
   pmd->AddSuballocation(dump->guid(),
-                        base::trace_event::MemoryDumpManager::GetInstance()
-                            ->system_allocator_pool_name());
+                        leveldb_env::DBTracker::GetMemoryDumpName(db_.get()));
+
   return true;
 }
 
diff --git a/content/browser/notifications/notification_database.cc b/content/browser/notifications/notification_database.cc
index 677a327..9b00a53 100644
--- a/content/browser/notifications/notification_database.cc
+++ b/content/browser/notifications/notification_database.cc
@@ -132,14 +132,12 @@
     options.env = env_.get();
   }
 
-  leveldb::DB* db = nullptr;
   Status status = LevelDBStatusToStatus(
-      leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db));
+      leveldb_env::OpenDB(options, path_.AsUTF8Unsafe(), &db_));
   if (status != STATUS_OK)
     return status;
 
   state_ = STATE_INITIALIZED;
-  db_.reset(db);
 
   return ReadNextPersistentNotificationId();
 }
diff --git a/content/browser/service_worker/service_worker_database.cc b/content/browser/service_worker/service_worker_database.cc
index 21c002e..93480c4 100644
--- a/content/browser/service_worker/service_worker_database.cc
+++ b/content/browser/service_worker/service_worker_database.cc
@@ -1230,16 +1230,13 @@
     options.env = g_service_worker_env.Pointer();
   }
 
-  leveldb::DB* db = NULL;
   Status status = LevelDBStatusToStatus(
-      leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db));
+      leveldb_env::OpenDB(options, path_.AsUTF8Unsafe(), &db_));
   HandleOpenResult(FROM_HERE, status);
   if (status != STATUS_OK) {
-    DCHECK(!db);
     // TODO(nhiroki): Should we retry to open the database?
     return status;
   }
-  db_.reset(db);
 
   int64_t db_version;
   status = ReadDatabaseVersion(&db_version);
diff --git a/device/vr/features/features.gni b/device/vr/features/features.gni
index f4c3102..9b30fe1 100644
--- a/device/vr/features/features.gni
+++ b/device/vr/features/features.gni
@@ -12,4 +12,7 @@
   enable_vr = is_android && (current_cpu == "arm" || current_cpu == "arm64") &&
               !is_chromecast
   enable_openvr = false
+
+  # Whether to include VR extras like test APKs in non-VR-specific targets
+  include_vr_data = false
 }
diff --git a/docs/code_reviews.md b/docs/code_reviews.md
index ae6bfd0f1..af8e91e2 100644
--- a/docs/code_reviews.md
+++ b/docs/code_reviews.md
@@ -14,9 +14,10 @@
 for each directory you are touching. If you have doubts, look at the git blame
 for the file and the `OWNERS` files (see below).
 
-To indicate a positive review, the reviewer types "LGTM" (case insensitive)
-into a comment on the code review. This stands for "Looks Good To Me." The text
-"not LGTM" will cancel out a previous positive review.
+To indicate a positive review, the reviewer chooses "+1" in Code-Review field
+on Gerrit, or types "LGTM" (case insensitive) into a comment on Rietveld. This
+stands for "Looks Good To Me." "-1" in Code-Review field on Gerrit or the text
+"not LGTM" on Rietveld will cancel out a previous positive review.
 
 If you have multiple reviewers, make it clear in the message you send
 requesting review what you expect from each reviewer. Otherwise people might
@@ -68,7 +69,7 @@
 #### Expectations of owners
 
 The existing owners of a directory approve additions to the list. It is
-preferrable to have many directories, each with a smaller number of specific
+preferable to have many directories, each with a smaller number of specific
 owners rather than large directories with many owners. Owners must:
 
   * Demonstrate excellent judgment, teamwork and ability to uphold Chrome
@@ -101,8 +102,8 @@
 common use of TBR is to revert patches that broke the build.
 
 TBR does not mean "no review." A reviewer TBR-ed on a change should still
-review the change. If there comments after landing the author is obligated to
-address them in a followup patch.
+review the change. If there are comments after landing, the author is obligated
+to address them in a followup patch.
 
 Do not use TBR just because a change is urgent or the reviewer is being slow.
 Contact the reviewer directly or find somebody.
@@ -200,7 +201,7 @@
 ```
 
 The `per-file` directive allows owners to be added that apply only to files
-matching a pattern. In this example, owners from the parent directiory
+matching a pattern. In this example, owners from the parent directory
 apply, plus one person for some classes of files, and all committers are
 owners for the readme:
 ```
diff --git a/docs/origin_trials_integration.md b/docs/origin_trials_integration.md
index d56431a..90e7ee9 100644
--- a/docs/origin_trials_integration.md
+++ b/docs/origin_trials_integration.md
@@ -62,8 +62,8 @@
 1. A native C++ method that you can call in Blink code at runtime to expose your
     feature: `bool OriginTrials::myFeatureEnabled()`
 2. An IDL attribute \[[OriginTrialEnabled]\] that you can use to automatically
-    expose and hide JavaScript methods/attributes/objects. This attribute works
-    very similar to \[RuntimeEnabled\].
+    generate code to expose and hide JavaScript methods/attributes/objects. This
+    attribute works very similarly to \[RuntimeEnabled\].
 ```
 [OriginTrialEnabled=MyFeature]
 partial interface Navigator {
@@ -75,36 +75,6 @@
 check. Your code should simply call `OriginTrials::myFeatureEnabled()` as often
 as necessary to gate access to your feature.
 
-### IDL Bindings
-
-When using the \[OriginTrialEnabled\] IDL attribute, you'll need to manually
-install the appropriate methods in the V8 bindings code. Based on the
-\[OriginTrialEnabled\] attribute, there will be one or more `installMyFeature`
-methods generated in the bindings code. These methods must be manually
-installed:
-
-- Find the relevant methods by doing a code search for `installMyFeature`:
-    - Search within the generated bindings code, e.g. 'f:gen/blink/bindings'
-    - Example search results: `V8WindowPartial::installMyFeature`,
-      `V8NavigatorPartial::installMyFeature`, `V8<type>::installMyFeature`
-- Determine which bindings code needs to be updated:
-    - [ConditionalFeatures.cpp]: Your feature lives in `core` (i.e. generated
-      methods are found under .../bindings/core/...)
-    - [ConditionalFeaturesForModules.cpp]: Your feature lives under `modules`
-      (i.e. generated methods are found under .../bindings/modules/...)
-- Update `installConditionalFeatures[Core|ForModules]()`:
-    - These methods are broken down by type.
-    - Add/update the logic for each type to call the corresponding
-      `V8<type>::installMyFeature()` methods.
-- Update `installPendingConditionalFeature[Core|ForModules]()`:
-    - These methods are broken down by trial/feature.
-    - Add/update the logic for each feature to call all of the
-     `installMyFeature()` methods.
-
-Eventually, the V8 bindings code will be generated automatically (See
-[crbug.com/615060]).
-
-
 ## Limitations
 
 What you can't do, because of the nature of these Origin Trials, is know at
@@ -155,26 +125,16 @@
 
 ### Layout Tests
 When using the \[OriginTrialEnabled\] IDL attribute, you should add layout tests
-to verify that you've correctly updated the V8 bindings code. Depending on how
+to verify that the V8 bindings code is working as expected. Depending on how
 your feature is exposed, you'll want tests for the exposed interfaces, as well
 as tests for script-added tokens. For examples, refer to the existing tests in
 [origin_trials/webexposed].
 
-In addition, you'll need to update the command line for the
-`origin-trials-runtimeflags-disabled` virtual suite, in [VirtualTestSuites].
-Add your feature name to the list of explicitly disabled features. This test
-suite ensures that features are actually enabled by origin trial, not overridden
-by the runtime flag.
-
 [build_config.h]: /build/build_config.h
 [chrome_origin_trial_policy.cc]: /chrome/common/origin_trials/chrome_origin_trial_policy.cc
-[crbug.com/615060]: https://bugs.chromium.org/p/chromium/issues/detail?id=615060
-[ConditionalFeatures.cpp]: /third_party/WebKit/Source/bindings/core/v8/ConditionalFeatures.cpp
-[ConditionalFeaturesForModules.cpp]: /third_party/WebKit/Source/bindings/modules/v8/ConditionalFeaturesForModules.cpp
 [generate_token.py]: /tools/origin_trials/generate_token.py
 [Developer Guide]: https://github.com/jpchase/OriginTrials/blob/gh-pages/developer-guide.md
 [OriginTrialEnabled]: /third_party/WebKit/Source/bindings/IDLExtendedAttributes.md#_OriginTrialEnabled_i_m_a_c_
 [origin_trials/webexposed]: /third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/
 [RuntimeEnabledFeatures.json5]: /third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
 [trial_token_unittest.cc]: /content/common/origin_trials/trial_token_unittest.cc
-[VirtualTestSuites]: /third_party/WebKit/LayoutTests/VirtualTestSuites
diff --git a/docs/testing/layout_tests.md b/docs/testing/layout_tests.md
index 23c104dd..f89bcd7 100644
--- a/docs/testing/layout_tests.md
+++ b/docs/testing/layout_tests.md
@@ -426,6 +426,42 @@
 * In the loaded devtools, set any required breakpoints and execute `test()` in
   the console to actually start the test.
 
+## Bisecting Regressions
+
+You can use [`git bisect`](https://git-scm.com/docs/git-bisect) to find which
+commit broke (or fixed!) a layout test in a fully automated way.  Unlike
+[bisect-builds.py](http://dev.chromium.org/developers/bisect-builds-py), which
+downloads pre-built Chromium binaries, `git bisect` operates on your local
+checkout, so it can run tests with `content_shell`.
+
+Bisecting can take several hours, but since it is fully automated you can leave
+it running overnight and view the results the next day.
+
+To set up an automated bisect of a layout test regression, create a script like
+this:
+
+```
+#!/bin/bash
+
+# Exit code 125 tells git bisect to skip the revision.
+gclient sync || exit 125
+ninja -C out/Debug -j100 blink_tests || exit 125
+
+blink/tools/run_layout_tests.sh -t Debug \
+  --no-show-results --no-retry-failures \
+  path/to/layout/test.html
+```
+
+Modify the `out` directory, ninja args, and test name as appropriate, and save
+the script in `~/checkrev.sh`.  Then run:
+
+```
+chmod u+x ~/checkrev.sh  # mark script as executable
+git bisect start <badrev> <goodrev>
+git bisect run ~/checkrev.sh
+git bisect reset  # quit the bisect session
+```
+
 ## Rebaselining Layout Tests
 
 *** promo
diff --git a/extensions/browser/value_store/lazy_leveldb.cc b/extensions/browser/value_store/lazy_leveldb.cc
index 1d972f8..3eed60b 100644
--- a/extensions/browser/value_store/lazy_leveldb.cc
+++ b/extensions/browser/value_store/lazy_leveldb.cc
@@ -182,24 +182,21 @@
   // RepairDB can drop an unbounded number of leveldb tables (key/value sets).
   s = leveldb::RepairDB(db_path_.AsUTF8Unsafe(), repair_options);
 
-  leveldb::DB* db = nullptr;
   if (s.ok()) {
     restore_status = ValueStore::DB_RESTORE_REPAIR_SUCCESS;
-    s = leveldb::DB::Open(open_options_, db_path_.AsUTF8Unsafe(), &db);
+    s = leveldb_env::OpenDB(open_options_, db_path_.AsUTF8Unsafe(), &db_);
   }
 
   if (!s.ok()) {
     if (DeleteDbFile()) {
       restore_status = ValueStore::DB_RESTORE_DELETE_SUCCESS;
-      s = leveldb::DB::Open(open_options_, db_path_.AsUTF8Unsafe(), &db);
+      s = leveldb_env::OpenDB(open_options_, db_path_.AsUTF8Unsafe(), &db_);
     } else {
       restore_status = ValueStore::DB_RESTORE_DELETE_FAILURE;
     }
   }
 
-  if (s.ok())
-    db_.reset(db);
-  else
+  if (!s.ok())
     db_unrecoverable_ = true;
 
   if (s.ok() && key) {
@@ -209,7 +206,7 @@
     } else if (s.IsIOError()) {
       restore_status = ValueStore::VALUE_RESTORE_DELETE_FAILURE;
     } else {
-      db_.reset(db);
+      db_.reset();
       if (!DeleteDbFile())
         db_unrecoverable_ = true;
       restore_status = ValueStore::DB_RESTORE_DELETE_FAILURE;
@@ -234,14 +231,11 @@
                               "Database corrupted");
   }
 
-  leveldb::DB* db = nullptr;
   leveldb::Status ldb_status =
-      leveldb::DB::Open(open_options_, db_path_.AsUTF8Unsafe(), &db);
+      leveldb_env::OpenDB(open_options_, db_path_.AsUTF8Unsafe(), &db_);
   open_histogram_->Add(leveldb_env::GetLevelDBStatusUMAValue(ldb_status));
   ValueStore::Status status = ToValueStoreError(ldb_status);
-  if (ldb_status.ok()) {
-    db_.reset(db);
-  } else if (ldb_status.IsCorruption()) {
+  if (ldb_status.IsCorruption()) {
     status.restore_status = FixCorruption(nullptr);
     if (status.restore_status != ValueStore::DB_RESTORE_DELETE_FAILURE) {
       status.code = ValueStore::OK;
diff --git a/extensions/browser/value_store/leveldb_value_store.cc b/extensions/browser/value_store/leveldb_value_store.cc
index 657e593..c0e133bf 100644
--- a/extensions/browser/value_store/leveldb_value_store.cc
+++ b/extensions/browser/value_store/leveldb_value_store.cc
@@ -259,12 +259,10 @@
   dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
                   base::trace_event::MemoryAllocatorDump::kUnitsBytes, size);
 
-  // Memory is allocated from system allocator (malloc).
-  const char* system_allocator_name =
-      base::trace_event::MemoryDumpManager::GetInstance()
-          ->system_allocator_pool_name();
-  if (system_allocator_name)
-    pmd->AddSuballocation(dump->guid(), system_allocator_name);
+  // All leveldb databases are already dumped by leveldb_env::DBTracker. Add
+  // an edge to avoid double counting.
+  pmd->AddSuballocation(dump->guid(),
+                        leveldb_env::DBTracker::GetMemoryDumpName(db()));
 
   return true;
 }
diff --git a/extensions/renderer/api_test_base.cc b/extensions/renderer/api_test_base.cc
index 9f87585b..2d1de991 100644
--- a/extensions/renderer/api_test_base.cc
+++ b/extensions/renderer/api_test_base.cc
@@ -13,6 +13,7 @@
 #include "base/strings/string_piece.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "extensions/common/extension_urls.h"
+#include "extensions/common/feature_switch.h"
 #include "extensions/renderer/dispatcher.h"
 #include "extensions/renderer/process_info_native_handler.h"
 #include "gin/converter.h"
@@ -176,6 +177,11 @@
 }
 
 void ApiTestEnvironment::InitializeEnvironment() {
+  // With native bindings, we use the actual bindings system to set up the
+  // context, so there's no need to provide these stubs.
+  if (FeatureSwitch::native_crx_bindings()->IsEnabled())
+    return;
+
   gin::Dictionary global(env()->isolate(),
                          env()->context()->v8_context()->Global());
   gin::Dictionary navigator(gin::Dictionary::CreateEmpty(env()->isolate()));
@@ -183,8 +189,6 @@
   global.Set("navigator", navigator);
   gin::Dictionary chrome(gin::Dictionary::CreateEmpty(env()->isolate()));
   global.Set("chrome", chrome);
-  gin::Dictionary extension(gin::Dictionary::CreateEmpty(env()->isolate()));
-  chrome.Set("extension", extension);
   gin::Dictionary runtime(gin::Dictionary::CreateEmpty(env()->isolate()));
   chrome.Set("runtime", runtime);
 }
@@ -233,9 +237,6 @@
 
 void ApiTestEnvironment::RunPromisesAgain() {
   v8::MicrotasksScope::PerformCheckpoint(env()->isolate());
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&ApiTestEnvironment::RunPromisesAgain,
-                            base::Unretained(this)));
 }
 
 ApiTestBase::ApiTestBase() {
diff --git a/extensions/renderer/module_system_test.cc b/extensions/renderer/module_system_test.cc
index 96f834e..c267e46 100644
--- a/extensions/renderer/module_system_test.cc
+++ b/extensions/renderer/module_system_test.cc
@@ -20,12 +20,17 @@
 #include "base/path_service.h"
 #include "base/strings/string_piece.h"
 #include "extensions/common/extension_paths.h"
+#include "extensions/common/feature_switch.h"
+#include "extensions/renderer/ipc_message_sender.h"
 #include "extensions/renderer/logging_native_handler.h"
+#include "extensions/renderer/native_extension_bindings_system.h"
 #include "extensions/renderer/object_backed_native_handler.h"
 #include "extensions/renderer/safe_builtins.h"
+#include "extensions/renderer/script_context_set.h"
 #include "extensions/renderer/string_source_map.h"
 #include "extensions/renderer/test_v8_extension_configuration.h"
 #include "extensions/renderer/utils_native_handler.h"
+#include "gin/converter.h"
 #include "ui/base/resource/resource_bundle.h"
 
 namespace extensions {
@@ -39,6 +44,44 @@
   }
 };
 
+class GetAPINatives : public ObjectBackedNativeHandler {
+ public:
+  GetAPINatives(ScriptContext* context,
+                NativeExtensionBindingsSystem* bindings_system)
+      : ObjectBackedNativeHandler(context) {
+    DCHECK_EQ(FeatureSwitch::native_crx_bindings()->IsEnabled(),
+              !!bindings_system);
+
+    auto get_api = [](ScriptContext* context,
+                      NativeExtensionBindingsSystem* bindings_system,
+                      const v8::FunctionCallbackInfo<v8::Value>& args) {
+      CHECK_EQ(1, args.Length());
+      CHECK(args[0]->IsString());
+      std::string api_name = gin::V8ToString(args[0]);
+      v8::Local<v8::Object> api;
+      if (bindings_system) {
+        api = bindings_system->GetAPIObjectForTesting(context, api_name);
+      } else {
+        v8::Local<v8::Object> full_binding;
+        CHECK(
+            context->module_system()->Require(api_name).ToLocal(&full_binding))
+            << "Failed to get: " << api_name;
+        v8::Local<v8::Value> api_value;
+        CHECK(full_binding
+                  ->Get(context->v8_context(),
+                        gin::StringToSymbol(context->isolate(), "binding"))
+                  .ToLocal(&api_value))
+            << "Failed to get: " << api_name;
+        CHECK(api_value->IsObject()) << "Failed to get: " << api_name;
+        api = api_value.As<v8::Object>();
+      }
+      args.GetReturnValue().Set(api);
+    };
+
+    RouteFunction("get", base::Bind(get_api, context, bindings_system));
+  }
+};
+
 }  // namespace
 
 // Native JS functions for doing asserts.
@@ -77,25 +120,38 @@
   bool failed_;
 };
 
-ModuleSystemTestEnvironment::ModuleSystemTestEnvironment(v8::Isolate* isolate)
+ModuleSystemTestEnvironment::ModuleSystemTestEnvironment(
+    v8::Isolate* isolate,
+    ScriptContextSet* context_set)
     : isolate_(isolate),
       context_holder_(new gin::ContextHolder(isolate_)),
       handle_scope_(isolate_),
+      context_set_(context_set),
       source_map_(new StringSourceMap()) {
   context_holder_->SetContext(v8::Context::New(
       isolate, TestV8ExtensionConfiguration::GetConfiguration()));
-  context_.reset(new ScriptContext(context_holder_->context(),
-                                   nullptr,  // WebFrame
-                                   nullptr,  // Extension
-                                   Feature::BLESSED_EXTENSION_CONTEXT,
-                                   nullptr,  // Effective Extension
-                                   Feature::BLESSED_EXTENSION_CONTEXT));
+
+  {
+    auto context =
+        base::MakeUnique<ScriptContext>(context_holder_->context(),
+                                        nullptr,  // WebFrame
+                                        nullptr,  // Extension
+                                        Feature::BLESSED_EXTENSION_CONTEXT,
+                                        nullptr,  // Effective Extension
+                                        Feature::BLESSED_EXTENSION_CONTEXT);
+    context_ = context.get();
+    context_set_->AddForTesting(std::move(context));
+  }
+
   context_->v8_context()->Enter();
-  assert_natives_ = new AssertNatives(context_.get());
+  assert_natives_ = new AssertNatives(context_);
+
+  if (FeatureSwitch::native_crx_bindings()->IsEnabled())
+    bindings_system_ = base::MakeUnique<NativeExtensionBindingsSystem>(nullptr);
 
   {
     std::unique_ptr<ModuleSystem> module_system(
-        new ModuleSystem(context_.get(), source_map_.get()));
+        new ModuleSystem(context_, source_map_.get()));
     context_->set_module_system(std::move(module_system));
   }
   ModuleSystem* module_system = context_->module_system();
@@ -103,16 +159,24 @@
       "assert", std::unique_ptr<NativeHandler>(assert_natives_));
   module_system->RegisterNativeHandler(
       "logging",
-      std::unique_ptr<NativeHandler>(new LoggingNativeHandler(context_.get())));
+      std::unique_ptr<NativeHandler>(new LoggingNativeHandler(context_)));
   module_system->RegisterNativeHandler(
       "utils",
-      std::unique_ptr<NativeHandler>(new UtilsNativeHandler(context_.get())));
+      std::unique_ptr<NativeHandler>(new UtilsNativeHandler(context_)));
+  module_system->RegisterNativeHandler(
+      "apiGetter",
+      base::MakeUnique<GetAPINatives>(context_, bindings_system_.get()));
   module_system->SetExceptionHandlerForTest(
       std::unique_ptr<ModuleSystem::ExceptionHandler>(new FailsOnException));
+
+  if (bindings_system_) {
+    bindings_system_->DidCreateScriptContext(context_);
+    bindings_system_->UpdateBindingsForContext(context_);
+  }
 }
 
 ModuleSystemTestEnvironment::~ModuleSystemTestEnvironment() {
-  if (context_->is_valid())
+  if (context_)
     ShutdownModuleSystem();
 }
 
@@ -154,7 +218,10 @@
 void ModuleSystemTestEnvironment::ShutdownModuleSystem() {
   CHECK(context_->is_valid());
   context_->v8_context()->Exit();
-  context_->Invalidate();
+  context_set_->Remove(context_);
+  base::RunLoop().RunUntilIdle();
+  context_ = nullptr;
+  assert_natives_ = nullptr;
 }
 
 v8::Local<v8::Object> ModuleSystemTestEnvironment::CreateGlobal(
@@ -168,8 +235,8 @@
 
 ModuleSystemTest::ModuleSystemTest()
     : isolate_(v8::Isolate::GetCurrent()),
-      should_assertions_be_made_(true) {
-}
+      context_set_(&extension_ids_),
+      should_assertions_be_made_(true) {}
 
 ModuleSystemTest::~ModuleSystemTest() {
 }
@@ -181,9 +248,13 @@
 
 void ModuleSystemTest::TearDown() {
   // All tests must assert at least once unless otherwise specified.
-  EXPECT_EQ(should_assertions_be_made_,
-            env_->assert_natives()->assertion_made());
-  EXPECT_FALSE(env_->assert_natives()->failed());
+  if (env_->assert_natives()) {  // The context may have already been shutdown.
+    EXPECT_EQ(should_assertions_be_made_,
+              env_->assert_natives()->assertion_made());
+    EXPECT_FALSE(env_->assert_natives()->failed());
+  } else {
+    EXPECT_FALSE(should_assertions_be_made_);
+  }
   env_.reset();
   v8::HeapStatistics stats;
   isolate_->GetHeapStatistics(&stats);
@@ -200,7 +271,7 @@
 
 std::unique_ptr<ModuleSystemTestEnvironment>
 ModuleSystemTest::CreateEnvironment() {
-  return base::WrapUnique(new ModuleSystemTestEnvironment(isolate_));
+  return base::MakeUnique<ModuleSystemTestEnvironment>(isolate_, &context_set_);
 }
 
 void ModuleSystemTest::ExpectNoAssertionsMade() {
diff --git a/extensions/renderer/module_system_test.h b/extensions/renderer/module_system_test.h
index df58fe2..b0a2bf21a 100644
--- a/extensions/renderer/module_system_test.h
+++ b/extensions/renderer/module_system_test.h
@@ -5,22 +5,28 @@
 #ifndef EXTENSIONS_RENDERER_MODULE_SYSTEM_TEST_H_
 #define EXTENSIONS_RENDERER_MODULE_SYSTEM_TEST_H_
 
+#include <set>
+
 #include "base/macros.h"
 #include "base/test/scoped_task_environment.h"
 #include "extensions/renderer/module_system.h"
 #include "extensions/renderer/script_context.h"
+#include "extensions/renderer/script_context_set.h"
+#include "extensions/renderer/test_extensions_renderer_client.h"
 #include "gin/public/context_holder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "v8/include/v8.h"
 
 namespace extensions {
+class NativeExtensionBindingsSystem;
 class StringSourceMap;
 
 class ModuleSystemTestEnvironment {
  public:
   class AssertNatives;
 
-  explicit ModuleSystemTestEnvironment(v8::Isolate* isolate);
+  ModuleSystemTestEnvironment(v8::Isolate* isolate,
+                              ScriptContextSet* context_set);
   ~ModuleSystemTestEnvironment();
 
   // Register a named JS module in the module system.
@@ -48,20 +54,26 @@
 
   ModuleSystem* module_system() { return context_->module_system(); }
 
-  ScriptContext* context() { return context_.get(); }
+  ScriptContext* context() { return context_; }
 
   v8::Isolate* isolate() { return isolate_; }
 
+  StringSourceMap* source_map() { return source_map_.get(); }
+
   AssertNatives* assert_natives() { return assert_natives_; }
 
  private:
   v8::Isolate* isolate_;
   std::unique_ptr<gin::ContextHolder> context_holder_;
   v8::HandleScope handle_scope_;
-  std::unique_ptr<ScriptContext> context_;
+
+  ScriptContextSet* context_set_;
+  ScriptContext* context_;
   AssertNatives* assert_natives_;
   std::unique_ptr<StringSourceMap> source_map_;
 
+  std::unique_ptr<NativeExtensionBindingsSystem> bindings_system_;
+
   DISALLOW_COPY_AND_ASSIGN(ModuleSystemTestEnvironment);
 };
 
@@ -100,7 +112,13 @@
 
  private:
   base::test::ScopedTaskEnvironment scoped_task_environment_;
+
   v8::Isolate* isolate_;
+
+  std::set<std::string> extension_ids_;
+  ScriptContextSet context_set_;
+  TestExtensionsRendererClient renderer_client_;
+
   std::unique_ptr<ModuleSystemTestEnvironment> env_;
   bool should_assertions_be_made_;
 
diff --git a/extensions/renderer/mojo/keep_alive_client_unittest.cc b/extensions/renderer/mojo/keep_alive_client_unittest.cc
index 37bc9b4..87d38203d 100644
--- a/extensions/renderer/mojo/keep_alive_client_unittest.cc
+++ b/extensions/renderer/mojo/keep_alive_client_unittest.cc
@@ -9,6 +9,7 @@
 #include "extensions/common/mojo/keep_alive.mojom.h"
 #include "extensions/grit/extensions_renderer_resources.h"
 #include "extensions/renderer/api_test_base.h"
+#include "extensions/renderer/string_source_map.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 
 // A test launcher for tests for the stash client defined in
@@ -38,6 +39,26 @@
   const base::Closure on_destruction_;
 };
 
+const char kFakeSerialBindings[] =
+    R"(
+      var binding = apiBridge || require('binding').Binding.create('serial');
+      var utils = require('utils');
+      binding.registerCustomHook(function(bindingsAPI) {
+        utils.handleRequestWithPromiseDoNotUse(bindingsAPI.apiFunctions,
+                                               'serial', 'getDevices',
+                                               function() {
+          if (bindingsAPI.compiledApi.shouldSucceed) {
+            return Promise.resolve([]);
+          } else {
+            return Promise.reject();
+          }
+        });
+      });
+
+      if (!apiBridge)
+        exports.$set('binding', binding.generate());
+    )";
+
 }  // namespace
 
 class KeepAliveClientTest : public ApiTestBase {
@@ -52,8 +73,10 @@
                               base::Unretained(this)),
                    base::Bind(&KeepAliveClientTest::KeepAliveDestroyed,
                               base::Unretained(this))));
-    created_keep_alive_ = false;
-    destroyed_keep_alive_ = false;
+
+    // We register fake custom bindings for the serial API to use
+    // handleRequestWithPromiseDoNotUse().
+    env()->source_map()->RegisterModule("serial", kFakeSerialBindings);
   }
 
   void WaitForKeepAlive() {
@@ -79,8 +102,8 @@
       stop_run_loop_.Run();
   }
 
-  bool created_keep_alive_;
-  bool destroyed_keep_alive_;
+  bool created_keep_alive_ = false;
+  bool destroyed_keep_alive_ = false;
   base::Closure stop_run_loop_;
 
   DISALLOW_COPY_AND_ASSIGN(KeepAliveClientTest);
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc
index 4746763..8a04ef1 100644
--- a/extensions/renderer/native_extension_bindings_system.cc
+++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -583,6 +583,13 @@
   return ipc_message_sender_.get();
 }
 
+v8::Local<v8::Object> NativeExtensionBindingsSystem::GetAPIObjectForTesting(
+    ScriptContext* context,
+    const std::string& api_name) {
+  return GetAPIHelper(context->v8_context(),
+                      gin::StringToSymbol(context->isolate(), api_name));
+}
+
 void NativeExtensionBindingsSystem::BindingAccessor(
     v8::Local<v8::Name> name,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
diff --git a/extensions/renderer/native_extension_bindings_system.h b/extensions/renderer/native_extension_bindings_system.h
index 51dd126..bac4e85 100644
--- a/extensions/renderer/native_extension_bindings_system.h
+++ b/extensions/renderer/native_extension_bindings_system.h
@@ -50,6 +50,11 @@
 
   APIBindingsSystem* api_system() { return &api_system_; }
 
+  // Returns the API with the given |name| for the given |context|. Used for
+  // testing purposes.
+  v8::Local<v8::Object> GetAPIObjectForTesting(ScriptContext* context,
+                                               const std::string& api_name);
+
  private:
   // Handles sending a given |request|, forwarding it on to the send_ipc_ after
   // adding additional info.
diff --git a/extensions/renderer/resources/file_entry_binding_util.js b/extensions/renderer/resources/file_entry_binding_util.js
index cdef7222..e4460c8 100644
--- a/extensions/renderer/resources/file_entry_binding_util.js
+++ b/extensions/renderer/resources/file_entry_binding_util.js
@@ -36,7 +36,10 @@
 //   previously saved file entries.
 function getFileBindingsForApi(apiName) {
   // Fallback to using the current window if no background page is running.
-  var backgroundPage = GetExtensionViews(-1, -1, 'BACKGROUND')[0] || WINDOW;
+  var views = GetExtensionViews(-1, -1, 'BACKGROUND');
+  // GetExtensionViews() can return null if called from a context without an
+  // associated extension.
+  var backgroundPage = views && views[0] ? views[0] : WINDOW;
   var backgroundPageModuleSystem = GetModuleSystem(backgroundPage);
 
   // All windows use the bindFileEntryCallback from the background page so their
@@ -138,7 +141,10 @@
 function getBindDirectoryEntryCallback() {
   // Get the background page if one exists. Otherwise, default to the current
   // window.
-  var backgroundPage = GetExtensionViews(-1, -1, 'BACKGROUND')[0] || WINDOW;
+  var views = GetExtensionViews(-1, -1, 'BACKGROUND');
+  // GetExtensionViews() can return null if called from a context without an
+  // associated extension.
+  var backgroundPage = views && views[0] ? views[0] : WINDOW;
 
   // For packaged apps, all windows use the bindFileEntryCallback from the
   // background page so their FileEntry objects have the background page's
diff --git a/extensions/renderer/resources/mojo_private_custom_bindings.js b/extensions/renderer/resources/mojo_private_custom_bindings.js
index 18d6016b..397f7d8 100644
--- a/extensions/renderer/resources/mojo_private_custom_bindings.js
+++ b/extensions/renderer/resources/mojo_private_custom_bindings.js
@@ -6,7 +6,7 @@
  * Custom bindings for the mojoPrivate API.
  */
 
-let binding = require('binding').Binding.create('mojoPrivate');
+let binding = apiBridge || require('binding').Binding.create('mojoPrivate');
 
 binding.registerCustomHook(function(bindingsAPI) {
   let apiFunctions = bindingsAPI.apiFunctions;
@@ -20,4 +20,5 @@
   });
 });
 
-exports.$set('binding', binding.generate());
+if (!apiBridge)
+  exports.$set('binding', binding.generate());
diff --git a/extensions/renderer/utils_unittest.cc b/extensions/renderer/utils_unittest.cc
index 07a237a..303b7fb2 100644
--- a/extensions/renderer/utils_unittest.cc
+++ b/extensions/renderer/utils_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/strings/stringprintf.h"
+#include "extensions/common/feature_switch.h"
 #include "extensions/grit/extensions_renderer_resources.h"
 #include "extensions/renderer/module_system_test.h"
 #include "gin/dictionary.h"
@@ -24,6 +25,12 @@
                                  "exports.$set('DCHECK', function() {});\n"
                                  "exports.$set('WARNING', function() {});");
     env()->OverrideNativeHandler("v8_context", "");
+
+    // Native bindings set up the chrome.runtime accessor, so we don't need to
+    // stub it out.
+    if (FeatureSwitch::native_crx_bindings()->IsEnabled())
+      return;
+
     gin::Dictionary chrome(env()->isolate(), env()->CreateGlobal("chrome"));
     gin::Dictionary chrome_runtime(
         gin::Dictionary::CreateEmpty(env()->isolate()));
diff --git a/extensions/test/data/api_test_base_unittest.js b/extensions/test/data/api_test_base_unittest.js
index 094a623..334b938 100644
--- a/extensions/test/data/api_test_base_unittest.js
+++ b/extensions/test/data/api_test_base_unittest.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-var test = require('test').binding;
+var test = requireNative('apiGetter').get('test');
 var unittestBindings = require('test_environment_specific_bindings');
 
 unittestBindings.exportTests([
@@ -19,16 +19,20 @@
     test.assertTrue(!!requireNative);
     test.assertTrue(!!requireAsync);
     test.assertEq(undefined, chrome.runtime.lastError);
-    test.assertEq(undefined, chrome.extension.lastError);
+    // chrome.extension is defined at the //chrome layer, and so won't be
+    // available.
+    test.assertEq(undefined, chrome.extension);
     test.succeed();
   },
   function testPromisesRun() {
     Promise.resolve().then(test.callbackPass());
   },
   function testCommonModulesAreAvailable() {
-    var binding = require('binding');
-    var sendRequest = require('sendRequest');
-    var lastError = require('lastError');
+    var binding = bindingUtil || require('binding');
+    var sendRequest =
+        bindingUtil ? bindingUtil.sendRequest : require('sendRequest');
+    var lastError =
+        bindingUtil ? bindingUtil.setLastError : require('lastError');
     test.assertTrue(!!binding);
     test.assertTrue(!!sendRequest);
     test.assertTrue(!!lastError);
diff --git a/extensions/test/data/keep_alive_client_unittest.js b/extensions/test/data/keep_alive_client_unittest.js
index 2997d5a..3a59137 100644
--- a/extensions/test/data/keep_alive_client_unittest.js
+++ b/extensions/test/data/keep_alive_client_unittest.js
@@ -8,29 +8,19 @@
  * They are launched by extensions/renderer/mojo/keep_alive_client_unittest.cc.
  */
 
-var test = require('test').binding;
+var getApi = requireNative('apiGetter').get;
+var test = getApi('test');
 var unittestBindings = require('test_environment_specific_bindings');
 var utils = require('utils');
 
-var shouldSucceed;
-
 // We need to set custom bindings for a real API and serial.getDevices has a
 // simple signature.
-var binding = require('binding').Binding.create('serial');
-binding.registerCustomHook(function(bindingsAPI) {
-  utils.handleRequestWithPromiseDoNotUse(bindingsAPI.apiFunctions,
-                                         'serial', 'getDevices', function() {
-    if (shouldSucceed)
-      return Promise.resolve([]);
-    else
-      return Promise.reject();
-  });
-});
-var apiFunction = binding.generate().getDevices;
+var serial = getApi('serial');
+var apiFunction = serial.getDevices;
 
 function runFunction() {
   apiFunction(function() {
-    if (shouldSucceed)
+    if (serial.shouldSucceed)
       test.assertNoLastError();
     else
       test.assertTrue(!!chrome.runtime.lastError);
@@ -41,14 +31,16 @@
 unittestBindings.exportTests([
   // Test that a keep alive is created and destroyed for a successful API call.
   function testKeepAliveWithSuccessfulCall() {
-    shouldSucceed = true;
+    // We cheat and put a property on the API object as a way of passing it to
+    // the custom hooks.
+    serial.shouldSucceed = true;
     runFunction();
   },
 
   // Test that a keep alive is created and destroyed for an unsuccessful API
   // call.
   function testKeepAliveWithError() {
-    shouldSucceed = false;
+    serial.shouldSucceed = true;
     runFunction();
   },
 ], test.runTests, exports);
diff --git a/extensions/test/data/mojo_private_unittest.js b/extensions/test/data/mojo_private_unittest.js
index f66b997..ddeb077 100644
--- a/extensions/test/data/mojo_private_unittest.js
+++ b/extensions/test/data/mojo_private_unittest.js
@@ -4,8 +4,9 @@
 
 'use strict';
 
-let mojoPrivate = require('mojoPrivate').binding;
-let test = require('test').binding;
+let getApi = requireNative('apiGetter').get;
+let mojoPrivate = getApi('mojoPrivate');
+let test = getApi('test');
 let unittestBindings = require('test_environment_specific_bindings');
 
 unittestBindings.exportTests([
diff --git a/google_apis/gcm/engine/gcm_store_impl.cc b/google_apis/gcm/engine/gcm_store_impl.cc
index 59600a11..cb5e9d6 100644
--- a/google_apis/gcm/engine/gcm_store_impl.cc
+++ b/google_apis/gcm/engine/gcm_store_impl.cc
@@ -292,7 +292,7 @@
     return RELOADING_OPEN_STORE;
   }
 
-  // Checks if the store exists or not. Calling DB::Open with create_if_missing
+  // Checks if the store exists or not. Opening a db with create_if_missing
   // not set will still create a new directory if the store does not exist.
   if (open_mode == DO_NOT_CREATE && !DatabaseExists(path_)) {
     DVLOG(2) << "Database " << path_.value() << " does not exist";
@@ -303,9 +303,8 @@
   options.create_if_missing = open_mode == CREATE_IF_MISSING;
   options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   options.paranoid_checks = true;
-  leveldb::DB* db;
   leveldb::Status status =
-      leveldb::DB::Open(options, path_.AsUTF8Unsafe(), &db);
+      leveldb_env::OpenDB(options, path_.AsUTF8Unsafe(), &db_);
   UMA_HISTOGRAM_ENUMERATION("GCM.Database.Open",
                             leveldb_env::GetLevelDBStatusUMAValue(status),
                             leveldb_env::LEVELDB_STATUS_MAX);
@@ -315,7 +314,6 @@
     return OPENING_STORE_FAILED;
   }
 
-  db_.reset(db);
   if (!LoadDeviceCredentials(&result->device_android_id,
                              &result->device_security_token)) {
     return LOADING_DEVICE_CREDENTIALS_FAILED;
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
index 5937cc1c..0bd05f8 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
@@ -69,6 +69,8 @@
     "org.chromium.externalclearkey.crash";
 const char kExternalClearKeyVerifyCdmHostTestKeySystem[] =
     "org.chromium.externalclearkey.verifycdmhosttest";
+const char kExternalClearKeyStorageIdTestKeySystem[] =
+    "org.chromium.externalclearkey.storageidtest";
 
 const int64_t kSecondsPerMinute = 60;
 const int64_t kMsPerSecond = 1000;
@@ -235,7 +237,8 @@
       key_system_string != kExternalClearKeyOutputProtectionTestKeySystem &&
       key_system_string != kExternalClearKeyPlatformVerificationTestKeySystem &&
       key_system_string != kExternalClearKeyCrashKeySystem &&
-      key_system_string != kExternalClearKeyVerifyCdmHostTestKeySystem) {
+      key_system_string != kExternalClearKeyVerifyCdmHostTestKeySystem &&
+      key_system_string != kExternalClearKeyStorageIdTestKeySystem) {
     DVLOG(1) << "Unsupported key system:" << key_system_string;
     return NULL;
   }
@@ -330,7 +333,8 @@
       timer_delay_ms_(kInitialTimerDelayMs),
       renewal_timer_set_(false),
       is_running_output_protection_test_(false),
-      is_running_platform_verification_test_(false) {
+      is_running_platform_verification_test_(false),
+      is_running_storage_id_test_(false) {
 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
   channel_count_ = 0;
   bits_per_channel_ = 0;
@@ -390,6 +394,8 @@
     StartPlatformVerificationTest();
   } else if (key_system_ == kExternalClearKeyVerifyCdmHostTestKeySystem) {
     VerifyCdmHostTest();
+  } else if (key_system_ == kExternalClearKeyStorageIdTestKeySystem) {
+    StartStorageIdTest();
   }
 }
 
@@ -793,7 +799,21 @@
 
 void ClearKeyCdm::OnStorageId(const uint8_t* storage_id,
                               uint32_t storage_id_size) {
-  NOTREACHED() << "OnStorageId() called unexpectedly.";
+  if (!is_running_storage_id_test_) {
+    NOTREACHED() << "OnStorageId() called unexpectedly.";
+    return;
+  }
+
+  is_running_storage_id_test_ = false;
+
+  // TODO(jrummell): Needs to be updated when Storage ID is actually returned.
+  // See http://crbug.com/478960
+  if (storage_id_size != 0) {
+    OnUnitTestComplete(false);
+    return;
+  }
+
+  OnUnitTestComplete(true);
 }
 
 void ClearKeyCdm::OnSessionMessage(const std::string& session_id,
@@ -958,4 +978,10 @@
   OnUnitTestComplete(g_verify_host_files_result);
 }
 
+void ClearKeyCdm::StartStorageIdTest() {
+  DVLOG(1) << __func__;
+  is_running_storage_id_test_ = true;
+  host_->RequestStorageId();
+}
+
 }  // namespace media
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
index d1d15be..4059d68 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
@@ -152,11 +152,8 @@
 
   void StartOutputProtectionTest();
   void StartPlatformVerificationTest();
-
-  // Keep track of the last session created.
-  void SetSessionId(const std::string& session_id);
-
   void VerifyCdmHostTest();
+  void StartStorageIdTest();
 
   scoped_refptr<ContentDecryptionModule> cdm_;
 
@@ -193,6 +190,7 @@
 
   bool is_running_output_protection_test_;
   bool is_running_platform_verification_test_;
+  bool is_running_storage_id_test_;
 
   DISALLOW_COPY_AND_ASSIGN(ClearKeyCdm);
 };
diff --git a/media/cdm/ppapi/ppapi_cdm_adapter.cc b/media/cdm/ppapi/ppapi_cdm_adapter.cc
index 4698653..b75a326 100644
--- a/media/cdm/ppapi/ppapi_cdm_adapter.cc
+++ b/media/cdm/ppapi/ppapi_cdm_adapter.cc
@@ -1158,8 +1158,21 @@
 }
 
 void PpapiCdmAdapter::RequestStorageId() {
-  // TODO(jrummell): Implement Storage Id. https://crbug.com/478960.
-  PP_NOTREACHED();
+  CDM_DLOG() << __func__;
+
+  // If persistent storage is not allowed, no need to get the Storage ID.
+  if (allow_persistent_state_) {
+    linked_ptr<pp::Var> response(new pp::Var());
+    int32_t result = platform_verification_.GetStorageId(
+        response.get(), callback_factory_.NewCallback(
+                            &PpapiCdmAdapter::RequestStorageIdDone, response));
+    if (result == PP_OK_COMPLETIONPENDING)
+      return;
+
+    // Fall through on error and provide an empty storage_id.
+    PP_DCHECK(result != PP_OK);
+  }
+
   cdm_->OnStorageId(nullptr, 0);
 }
 
@@ -1277,6 +1290,21 @@
                                       output_protection_mask_);
 }
 
+void PpapiCdmAdapter::RequestStorageIdDone(
+    int32_t result,
+    const linked_ptr<pp::Var>& response) {
+  std::string storage_id;
+
+  if (result == PP_OK)
+    storage_id = response->AsString();
+
+  CDM_DLOG() << __func__ << ": result = " << result
+             << ", storage_id = " << storage_id;
+
+  cdm_->OnStorageId(reinterpret_cast<const uint8_t*>(storage_id.data()),
+                    static_cast<uint32_t>(storage_id.length()));
+}
+
 PpapiCdmAdapter::SessionError::SessionError(
     cdm::Exception exception,
     uint32_t system_code,
diff --git a/media/cdm/ppapi/ppapi_cdm_adapter.h b/media/cdm/ppapi/ppapi_cdm_adapter.h
index 91ddf97..e1bc7bc6 100644
--- a/media/cdm/ppapi/ppapi_cdm_adapter.h
+++ b/media/cdm/ppapi/ppapi_cdm_adapter.h
@@ -264,6 +264,9 @@
       const linked_ptr<PepperPlatformChallengeResponse>& response);
 #endif
 
+  void RequestStorageIdDone(int32_t result,
+                            const linked_ptr<pp::Var>& response);
+
   pp::OutputProtection_Private output_protection_;
 
   // Same as above, these are only read by QueryOutputProtectionStatusDone().
@@ -276,7 +279,7 @@
   bool uma_for_output_protection_query_reported_;
   bool uma_for_output_protection_positive_result_reported_;
 
-  // TODO(jrummell): Use this to implement host challenging.
+  // Used to implement platform challenge (ChromeOS only) and access Storage ID.
   pp::PlatformVerification platform_verification_;
 
   PpbBufferAllocator allocator_;
diff --git a/media/test/data/eme_player_js/globals.js b/media/test/data/eme_player_js/globals.js
index bdc7d25..6fc8e240 100644
--- a/media/test/data/eme_player_js/globals.js
+++ b/media/test/data/eme_player_js/globals.js
@@ -47,6 +47,7 @@
 var CRASH_TEST_KEYSYSTEM = 'org.chromium.externalclearkey.crash';
 var VERIFY_HOST_FILES_TEST_KEYSYSTEM =
     'org.chromium.externalclearkey.verifycdmhosttest';
+var STORAGE_ID_TEST_KEYSYSTEM = 'org.chromium.externalclearkey.storageidtest';
 
 // Key system name:value map to show on the document page.
 var KEY_SYSTEMS = {
diff --git a/media/test/data/eme_player_js/player_utils.js b/media/test/data/eme_player_js/player_utils.js
index 7defd7a..6b9baca 100644
--- a/media/test/data/eme_player_js/player_utils.js
+++ b/media/test/data/eme_player_js/player_utils.js
@@ -238,6 +238,7 @@
       case OUTPUT_PROTECTION_TEST_KEYSYSTEM:
       case PLATFORM_VERIFICATION_TEST_KEYSYSTEM:
       case VERIFY_HOST_FILES_TEST_KEYSYSTEM:
+      case STORAGE_ID_TEST_KEYSYSTEM:
         return UnitTestPlayer;
       default:
         Utils.timeLog(keySystem + ' is not a known key system');
diff --git a/remoting/client/BUILD.gn b/remoting/client/BUILD.gn
index b6f0f78..2a283c0 100644
--- a/remoting/client/BUILD.gn
+++ b/remoting/client/BUILD.gn
@@ -29,8 +29,6 @@
     "host_experiment_sender.h",
     "queued_task_poster.cc",
     "queued_task_poster.h",
-    "server_log_entry_client.cc",
-    "server_log_entry_client.h",
     "software_video_renderer.cc",
     "software_video_renderer.h",
   ]
@@ -53,10 +51,7 @@
   libs = []
 
   if (is_nacl) {
-    sources -= [
-      "client_telemetry_logger.cc",
-      "server_log_entry_client.cc",
-    ]
+    sources -= [ "client_telemetry_logger.cc" ]
   } else {
     sources += [
       "chromoting_client_runtime.cc",
@@ -90,7 +85,6 @@
     "dual_buffer_frame_consumer_unittest.cc",
     "empty_cursor_filter_unittest.cc",
     "queued_task_poster_unittest.cc",
-    "server_log_entry_client_unittest.cc",
     "software_video_renderer_unittest.cc",
   ]
 
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index a0df02f..e8f0da79 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -139,9 +139,9 @@
     case protocol::SIGNALING_TIMEOUT:
     case protocol::UNKNOWN_ERROR:
       return "NETWORK_FAILURE";
+    default:
+      return "UNKNOWN";
   }
-  DLOG(FATAL) << "Unknown error code" << error;
-  return std::string();
 }
 
 PP_Instance g_logging_instance = 0;
diff --git a/remoting/client/server_log_entry_client.cc b/remoting/client/server_log_entry_client.cc
deleted file mode 100644
index fc1ba2a..0000000
--- a/remoting/client/server_log_entry_client.cc
+++ /dev/null
@@ -1,171 +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 "remoting/client/server_log_entry_client.h"
-
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringize_macros.h"
-#include "base/strings/stringprintf.h"
-#include "base/sys_info.h"
-#include "remoting/protocol/performance_tracker.h"
-#include "remoting/signaling/server_log_entry.h"
-
-using base::StringPrintf;
-using base::SysInfo;
-using remoting::protocol::ConnectionToHost;
-using remoting::protocol::ErrorCode;
-
-namespace remoting {
-
-namespace {
-const char kValueRoleClient[] = "client";
-
-const char kValueEventNameSessionState[] = "session-state";
-const char kValueEventNameStatistics[] = "connection-statistics";
-const char kValueEventNameSessionIdOld[] = "session-id-old";
-const char kValueEventNameSessionIdNew[] = "session-id-new";
-
-const char kKeySessionId[] = "session-id";
-const char kKeySessionDuration[] = "session-duration";
-
-const char kKeySessionState[] = "session-state";
-const char kKeyConnectionError[] = "connection-error";
-const char kValueSessionStateConnected[] = "connected";
-const char kValueSessionStateClosed[] = "closed";
-
-const char kKeyOsName[] = "os-name";
-const char kKeyOsVersion[] = "os-version";
-const char kKeyAppVersion[] = "app-version";
-
-const char* GetValueSessionState(ConnectionToHost::State state) {
-  switch (state) {
-    // Where possible, these are the same strings that the webapp sends for the
-    // corresponding state - see remoting/webapp/server_log_entry.js.
-    case ConnectionToHost::INITIALIZING:
-      return "initializing";
-    case ConnectionToHost::CONNECTING:
-      return "connecting";
-    case ConnectionToHost::AUTHENTICATED:
-      return "authenticated";
-    case ConnectionToHost::CONNECTED:
-      return kValueSessionStateConnected;
-    case ConnectionToHost::FAILED:
-      return "connection-failed";
-    case ConnectionToHost::CLOSED:
-      return kValueSessionStateClosed;
-  }
-  NOTREACHED();
-  return nullptr;
-}
-
-const char* GetValueError(ErrorCode error) {
-  switch (error) {
-    // Where possible, these are the same strings that the webapp sends for the
-    // corresponding error - see remoting/webapp/crd/js/server_log_entry.js.
-    case protocol::OK:
-      return "none";
-    case protocol::PEER_IS_OFFLINE:
-      return "host-is-offline";
-    case protocol::SESSION_REJECTED:
-      return "session-rejected";
-    case protocol::INCOMPATIBLE_PROTOCOL:
-      return "incompatible-protocol";
-    case protocol::AUTHENTICATION_FAILED:
-      return "authentication-failed";
-    case protocol::CHANNEL_CONNECTION_ERROR:
-      return "p2p-failure";
-    case protocol::SIGNALING_ERROR:
-      return "network-failure";
-    case protocol::SIGNALING_TIMEOUT:
-      return "network-failure";
-    case protocol::HOST_OVERLOAD:
-      return "host-overload";
-    case protocol::MAX_SESSION_LENGTH:
-      return "max-session-length";
-    case protocol::HOST_CONFIGURATION_ERROR:
-      return "host-configuration-error";
-    case protocol::UNKNOWN_ERROR:
-      return "unknown-error";
-    case protocol::INVALID_ACCOUNT:
-      return "invalid-account";
-  }
-  NOTREACHED();
-  return nullptr;
-}
-
-}  // namespace
-
-std::unique_ptr<ServerLogEntry> MakeLogEntryForSessionStateChange(
-    ConnectionToHost::State state,
-    ErrorCode error) {
-  std::unique_ptr<ServerLogEntry> entry(new ServerLogEntry());
-  entry->AddRoleField(kValueRoleClient);
-  entry->AddEventNameField(kValueEventNameSessionState);
-
-  entry->Set(kKeySessionState, GetValueSessionState(state));
-  if (error != protocol::OK) {
-    entry->Set(kKeyConnectionError, GetValueError(error));
-  }
-
-  return entry;
-}
-
-std::unique_ptr<ServerLogEntry> MakeLogEntryForStatistics(
-    protocol::PerformanceTracker* perf_tracker) {
-  std::unique_ptr<ServerLogEntry> entry(new ServerLogEntry());
-  entry->AddRoleField(kValueRoleClient);
-  entry->AddEventNameField(kValueEventNameStatistics);
-
-  entry->Set("video-bandwidth",
-             StringPrintf("%.2f", perf_tracker->video_bandwidth()));
-  entry->Set("capture-latency",
-             StringPrintf("%.2f", perf_tracker->video_capture_ms().Average()));
-  entry->Set("encode-latency",
-             StringPrintf("%.2f", perf_tracker->video_encode_ms().Average()));
-  entry->Set("decode-latency",
-             StringPrintf("%.2f", perf_tracker->video_decode_ms().Average()));
-  entry->Set("render-latency",
-             StringPrintf("%.2f", perf_tracker->video_paint_ms().Average()));
-  entry->Set("roundtrip-latency",
-             StringPrintf("%.2f", perf_tracker->round_trip_ms().Average()));
-
-  return entry;
-}
-
-std::unique_ptr<ServerLogEntry> MakeLogEntryForSessionIdOld(
-    const std::string& session_id) {
-  std::unique_ptr<ServerLogEntry> entry(new ServerLogEntry());
-  entry->AddRoleField(kValueRoleClient);
-  entry->AddEventNameField(kValueEventNameSessionIdOld);
-  AddSessionIdToLogEntry(entry.get(), session_id);
-  return entry;
-}
-
-std::unique_ptr<ServerLogEntry> MakeLogEntryForSessionIdNew(
-    const std::string& session_id) {
-  std::unique_ptr<ServerLogEntry> entry(new ServerLogEntry());
-  entry->AddRoleField(kValueRoleClient);
-  entry->AddEventNameField(kValueEventNameSessionIdNew);
-  AddSessionIdToLogEntry(entry.get(), session_id);
-  return entry;
-}
-
-void AddClientFieldsToLogEntry(ServerLogEntry* entry) {
-  entry->Set(kKeyOsName, SysInfo::OperatingSystemName());
-  entry->Set(kKeyOsVersion, SysInfo::OperatingSystemVersion());
-  entry->Set(kKeyAppVersion, STRINGIZE(VERSION));
-  entry->AddCpuField();
-}
-
-void AddSessionIdToLogEntry(ServerLogEntry* entry, const std::string& id) {
-  entry->Set(kKeySessionId, id);
-}
-
-void AddSessionDurationToLogEntry(ServerLogEntry* entry,
-                                  base::TimeDelta duration) {
-  entry->Set(kKeySessionDuration, base::Int64ToString(duration.InSeconds()));
-}
-
-}  // namespace remoting
diff --git a/remoting/client/server_log_entry_client.h b/remoting/client/server_log_entry_client.h
deleted file mode 100644
index 238c9e21..0000000
--- a/remoting/client/server_log_entry_client.h
+++ /dev/null
@@ -1,44 +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 REMOTING_CLIENT_SERVER_LOG_ENTRY_CLIENT_H_
-#define REMOTING_CLIENT_SERVER_LOG_ENTRY_CLIENT_H_
-
-#include "base/time/time.h"
-#include "remoting/protocol/connection_to_host.h"
-#include "remoting/protocol/errors.h"
-
-namespace remoting {
-
-class ServerLogEntry;
-
-namespace protocol {
-class PerformanceTracker;
-}  // namespace protocol
-
-// Constructs a log entry for a session state change.
-std::unique_ptr<ServerLogEntry> MakeLogEntryForSessionStateChange(
-    protocol::ConnectionToHost::State state,
-    protocol::ErrorCode error);
-
-// Constructs a log entry for reporting statistics.
-std::unique_ptr<ServerLogEntry> MakeLogEntryForStatistics(
-    protocol::PerformanceTracker* statistics);
-
-// Constructs a log entry for reporting session ID is old.
-std::unique_ptr<ServerLogEntry> MakeLogEntryForSessionIdOld(
-    const std::string& session_id);
-
-// Constructs a log entry for reporting session ID is old.
-std::unique_ptr<ServerLogEntry> MakeLogEntryForSessionIdNew(
-    const std::string& session_id);
-
-void AddClientFieldsToLogEntry(ServerLogEntry* entry);
-void AddSessionIdToLogEntry(ServerLogEntry* entry, const std::string& id);
-void AddSessionDurationToLogEntry(ServerLogEntry* entry,
-                                  base::TimeDelta duration);
-
-}  // namespace remoting
-
-#endif  // REMOTING_CLIENT_SERVER_LOG_ENTRY_CLIENT_H_
diff --git a/remoting/client/server_log_entry_client_unittest.cc b/remoting/client/server_log_entry_client_unittest.cc
deleted file mode 100644
index b9b1bfa..0000000
--- a/remoting/client/server_log_entry_client_unittest.cc
+++ /dev/null
@@ -1,128 +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 "remoting/client/server_log_entry_client.h"
-
-#include <memory>
-
-#include "base/strings/stringize_macros.h"
-#include "base/sys_info.h"
-#include "remoting/protocol/performance_tracker.h"
-#include "remoting/signaling/server_log_entry.h"
-#include "remoting/signaling/server_log_entry_unittest.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
-
-using base::SysInfo;
-using buzz::XmlAttr;
-using buzz::XmlElement;
-using remoting::protocol::ConnectionToHost;
-
-namespace remoting {
-
-TEST(ServerLogEntryClientTest, SessionStateChange) {
-  std::unique_ptr<ServerLogEntry> entry(MakeLogEntryForSessionStateChange(
-      ConnectionToHost::CONNECTED, remoting::protocol::OK));
-  std::unique_ptr<XmlElement> stanza = entry->ToStanza();
-  std::string error;
-  std::map<std::string, std::string> key_value_pairs;
-  key_value_pairs["role"] = "client";
-  key_value_pairs["event-name"] = "session-state";
-  key_value_pairs["session-state"] = "connected";
-  std::set<std::string> keys;
-  ASSERT_TRUE(VerifyStanza(key_value_pairs, keys, stanza.get(), &error))
-      << error;
-}
-
-TEST(ServerLogEntryClientTest, SessionStateChangeWithError) {
-  std::unique_ptr<ServerLogEntry> entry(MakeLogEntryForSessionStateChange(
-      ConnectionToHost::FAILED, remoting::protocol::PEER_IS_OFFLINE));
-  std::unique_ptr<XmlElement> stanza = entry->ToStanza();
-  std::string error;
-  std::map<std::string, std::string> key_value_pairs;
-  key_value_pairs["role"] = "client";
-  key_value_pairs["event-name"] = "session-state";
-  key_value_pairs["session-state"] = "connection-failed";
-  key_value_pairs["connection-error"] = "host-is-offline";
-  std::set<std::string> keys;
-  ASSERT_TRUE(VerifyStanza(key_value_pairs, keys, stanza.get(), &error))
-      << error;
-}
-
-TEST(ServerLogEntryClientTest, Statistics) {
-  protocol::PerformanceTracker perf_tracker;
-  std::unique_ptr<ServerLogEntry> entry(
-      MakeLogEntryForStatistics(&perf_tracker));
-  std::unique_ptr<XmlElement> stanza = entry->ToStanza();
-  std::string error;
-  std::map<std::string, std::string> key_value_pairs;
-  key_value_pairs["role"] = "client";
-  key_value_pairs["event-name"] = "connection-statistics";
-  std::set<std::string> keys;
-  keys.insert("video-bandwidth");
-  keys.insert("capture-latency");
-  keys.insert("encode-latency");
-  keys.insert("decode-latency");
-  keys.insert("render-latency");
-  keys.insert("roundtrip-latency");
-  ASSERT_TRUE(VerifyStanza(key_value_pairs, keys, stanza.get(), &error))
-      << error;
-}
-
-TEST(ServerLogEntryClientTest, SessionIdChanged) {
-  std::unique_ptr<ServerLogEntry> entry(MakeLogEntryForSessionIdOld("abc"));
-  std::unique_ptr<XmlElement> stanza = entry->ToStanza();
-  std::string error;
-  std::map<std::string, std::string> key_value_pairs;
-  key_value_pairs["role"] = "client";
-  key_value_pairs["event-name"] = "session-id-old";
-  key_value_pairs["session-id"] = "abc";
-  std::set<std::string> keys;
-  ASSERT_TRUE(VerifyStanza(key_value_pairs, keys, stanza.get(), &error))
-      << error;
-
-  entry = MakeLogEntryForSessionIdNew("def");
-  stanza = entry->ToStanza();
-  key_value_pairs["event-name"] = "session-id-new";
-  key_value_pairs["session-id"] = "def";
-  ASSERT_TRUE(VerifyStanza(key_value_pairs, keys, stanza.get(), &error))
-      << error;
-}
-
-TEST(ServerLogEntryClientTest, AddClientFields) {
-  std::unique_ptr<ServerLogEntry> entry(MakeLogEntryForSessionStateChange(
-      ConnectionToHost::CONNECTED, remoting::protocol::OK));
-  AddClientFieldsToLogEntry(entry.get());
-  std::unique_ptr<XmlElement> stanza = entry->ToStanza();
-  std::string error;
-  std::map<std::string, std::string> key_value_pairs;
-  key_value_pairs["role"] = "client";
-  key_value_pairs["event-name"] = "session-state";
-  key_value_pairs["session-state"] = "connected";
-  key_value_pairs["os-name"] = SysInfo::OperatingSystemName();
-  key_value_pairs["os-version"] = SysInfo::OperatingSystemVersion();
-  key_value_pairs["app-version"] = STRINGIZE(VERSION);
-  key_value_pairs["cpu"] = SysInfo::OperatingSystemArchitecture();
-  std::set<std::string> keys;
-  ASSERT_TRUE(VerifyStanza(key_value_pairs, keys, stanza.get(), &error)) <<
-      error;
-}
-
-TEST(ServerLogEntryClientTest, AddSessionDuration) {
-  std::unique_ptr<ServerLogEntry> entry(MakeLogEntryForSessionStateChange(
-      ConnectionToHost::CONNECTED, remoting::protocol::OK));
-  AddSessionDurationToLogEntry(entry.get(), base::TimeDelta::FromSeconds(123));
-  std::unique_ptr<XmlElement> stanza = entry->ToStanza();
-  std::string error;
-  std::map<std::string, std::string> key_value_pairs;
-  key_value_pairs["role"] = "client";
-  key_value_pairs["event-name"] = "session-state";
-  key_value_pairs["session-state"] = "connected";
-  key_value_pairs["session-duration"] = "123";
-  std::set<std::string> keys;
-  ASSERT_TRUE(VerifyStanza(key_value_pairs, keys, stanza.get(), &error))
-      << error;
-}
-
-}  // namespace remoting
diff --git a/remoting/host/it2me/it2me_host.cc b/remoting/host/it2me/it2me_host.cc
index 7f49098..f593753 100644
--- a/remoting/host/it2me/it2me_host.cc
+++ b/remoting/host/it2me/it2me_host.cc
@@ -42,6 +42,8 @@
 
 namespace remoting {
 
+using protocol::ErrorCode;
+
 namespace {
 
 // This is used for tagging system event logs.
@@ -103,7 +105,7 @@
   DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
   DCHECK_EQ(kDisconnected, state_);
 
-  SetState(kStarting, std::string());
+  SetState(kStarting, ErrorCode::OK);
 
   // Check the host domain policy.
   if (!required_host_domain_list_.empty()) {
@@ -116,7 +118,7 @@
       }
     }
     if (!matched) {
-      SetState(kInvalidDomainError, std::string());
+      SetState(kInvalidDomainError, ErrorCode::OK);
       return;
     }
   }
@@ -192,7 +194,7 @@
   signal_strategy_->Connect();
   host_->Start(username);
 
-  SetState(kRequestedAccessCode, std::string());
+  SetState(kRequestedAccessCode, ErrorCode::OK);
   return;
 }
 
@@ -206,7 +208,7 @@
     DCHECK_EQ(state_, kConnecting);
     connecting_jid_.clear();
     confirmation_dialog_proxy_.reset();
-    SetState(kReceivedAccessCode, std::string());
+    SetState(kReceivedAccessCode, ErrorCode::OK);
   }
 }
 
@@ -230,7 +232,7 @@
       FROM_HERE, base::Bind(&It2MeHost::Observer::OnClientAuthenticated,
                             observer_, client_username));
 
-  SetState(kConnected, std::string());
+  SetState(kConnected, ErrorCode::OK);
 }
 
 void It2MeHost::OnClientDisconnected(const std::string& jid) {
@@ -350,8 +352,7 @@
   }
 }
 
-void It2MeHost::SetState(It2MeHostState state,
-                         const std::string& error_message) {
+void It2MeHost::SetState(It2MeHostState state, ErrorCode error_code) {
   DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
 
   switch (state_) {
@@ -397,7 +398,7 @@
   // Post a state-change notification to the web-app.
   host_context_->ui_task_runner()->PostTask(
       FROM_HERE, base::Bind(&It2MeHost::Observer::OnStateChanged, observer_,
-                            state, error_message));
+                            state, error_code));
 }
 
 bool It2MeHost::IsRunning() const {
@@ -405,14 +406,13 @@
          state_ == kConnected || state_ == kConnecting;
 }
 
-void It2MeHost::OnReceivedSupportID(
-    const std::string& support_id,
-    const base::TimeDelta& lifetime,
-    const std::string& error_message) {
+void It2MeHost::OnReceivedSupportID(const std::string& support_id,
+                                    const base::TimeDelta& lifetime,
+                                    const ErrorCode error_code) {
   DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
 
-  if (!error_message.empty()) {
-    SetState(kError, error_message);
+  if (error_code != ErrorCode::OK) {
+    SetState(kError, error_code);
     DisconnectOnNetworkThread();
     return;
   }
@@ -424,9 +424,8 @@
 
   std::string local_certificate = host_key_pair_->GenerateCertificate();
   if (local_certificate.empty()) {
-    std::string error_message = "Failed to generate host certificate.";
-    LOG(ERROR) << error_message;
-    SetState(kError, error_message);
+    LOG(ERROR) << "Failed to generate host certificate.";
+    SetState(kError, ErrorCode::HOST_CERTIFICATE_ERROR);
     DisconnectOnNetworkThread();
     return;
   }
@@ -443,7 +442,7 @@
       FROM_HERE, base::Bind(&It2MeHost::Observer::OnStoreAccessCode, observer_,
                             access_code, lifetime));
 
-  SetState(kReceivedAccessCode, std::string());
+  SetState(kReceivedAccessCode, ErrorCode::OK);
 }
 
 void It2MeHost::DisconnectOnNetworkThread() {
@@ -471,7 +470,7 @@
   host_context_->ui_task_runner()->DeleteSoon(
       FROM_HERE, desktop_environment_factory_.release());
 
-  SetState(kDisconnected, std::string());
+  SetState(kDisconnected, ErrorCode::OK);
 }
 
 void It2MeHost::ValidateConnectionDetails(
@@ -529,7 +528,7 @@
 
   HOST_LOG << "Client " << client_username << " connecting.";
   connecting_jid_ = remote_jid;
-  SetState(kConnecting, std::string());
+  SetState(kConnecting, ErrorCode::OK);
 
   // Show a confirmation dialog to the user to allow them to confirm/reject it.
   confirmation_dialog_proxy_.reset(new It2MeConfirmationDialogProxy(
diff --git a/remoting/host/it2me/it2me_host.h b/remoting/host/it2me/it2me_host.h
index ca39912..f76a967 100644
--- a/remoting/host/it2me/it2me_host.h
+++ b/remoting/host/it2me/it2me_host.h
@@ -16,6 +16,7 @@
 #include "remoting/host/host_status_observer.h"
 #include "remoting/host/it2me/it2me_confirmation_dialog.h"
 #include "remoting/host/it2me/it2me_confirmation_dialog_proxy.h"
+#include "remoting/protocol/errors.h"
 #include "remoting/protocol/port_range.h"
 #include "remoting/protocol/validating_authenticator.h"
 #include "remoting/signaling/xmpp_signal_strategy.h"
@@ -62,7 +63,7 @@
                                    base::TimeDelta access_code_lifetime) = 0;
     virtual void OnNatPolicyChanged(bool nat_traversal_enabled) = 0;
     virtual void OnStateChanged(It2MeHostState state,
-                                const std::string& error_message) = 0;
+                                protocol::ErrorCode error_code) = 0;
   };
 
   It2MeHost();
@@ -89,8 +90,8 @@
   void OnClientDisconnected(const std::string& jid) override;
 
   void SetStateForTesting(It2MeHostState state,
-                          const std::string& error_message) {
-    SetState(state, error_message);
+                          protocol::ErrorCode error_code) {
+    SetState(state, error_code);
   }
 
   // Returns the callback used for validating the connection.  Do not run the
@@ -114,7 +115,7 @@
   friend class It2MeHostTest;
 
   // Updates state of the host. Can be called only on the network thread.
-  void SetState(It2MeHostState state, const std::string& error_message);
+  void SetState(It2MeHostState state, protocol::ErrorCode error_code);
 
   // Returns true if the host is in a post-starting, non-error state.
   bool IsRunning() const;
@@ -132,7 +133,7 @@
   // Called when the support host registration completes.
   void OnReceivedSupportID(const std::string& support_id,
                            const base::TimeDelta& lifetime,
-                           const std::string& error_message);
+                           protocol::ErrorCode error_code);
 
   // Handlers for NAT traversal and domain policies.
   void UpdateNatPolicy(bool nat_traversal_enabled);
diff --git a/remoting/host/it2me/it2me_host_unittest.cc b/remoting/host/it2me/it2me_host_unittest.cc
index 8732597..8d3ff79 100644
--- a/remoting/host/it2me/it2me_host_unittest.cc
+++ b/remoting/host/it2me/it2me_host_unittest.cc
@@ -25,6 +25,7 @@
 #include "remoting/host/chromoting_host_context.h"
 #include "remoting/host/it2me/it2me_confirmation_dialog.h"
 #include "remoting/host/policy_watcher.h"
+#include "remoting/protocol/errors.h"
 #include "remoting/protocol/transport_context.h"
 #include "remoting/signaling/fake_signal_strategy.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -35,6 +36,8 @@
 
 namespace remoting {
 
+using protocol::ErrorCode;
+
 namespace {
 
 // Shortening some type names for readability.
@@ -145,8 +148,7 @@
   void OnStoreAccessCode(const std::string& access_code,
                          base::TimeDelta access_code_lifetime) override;
   void OnNatPolicyChanged(bool nat_traversal_enabled) override;
-  void OnStateChanged(It2MeHostState state,
-                      const std::string& error_message) override;
+  void OnStateChanged(It2MeHostState state, ErrorCode error_code) override;
 
   void SetPolicies(
       std::initializer_list<std::pair<base::StringPiece, const base::Value&>>
@@ -248,7 +250,7 @@
     network_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(&It2MeHost::SetStateForTesting, it2me_host_.get(),
-                   It2MeHostState::kReceivedAccessCode, std::string()));
+                   It2MeHostState::kReceivedAccessCode, ErrorCode::OK));
   } else if (last_host_state_ != It2MeHostState::kStarting) {
     quit_closure.Run();
     return;
@@ -319,8 +321,7 @@
 
 void It2MeHostTest::OnNatPolicyChanged(bool nat_traversal_enabled) {}
 
-void It2MeHostTest::OnStateChanged(It2MeHostState state,
-                                   const std::string& error_message) {
+void It2MeHostTest::OnStateChanged(It2MeHostState state, ErrorCode error_code) {
   last_host_state_ = state;
 
   if (state_change_callback_) {
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc
index 6212deb1..6be01ea 100644
--- a/remoting/host/it2me/it2me_native_messaging_host.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -45,6 +45,8 @@
 
 namespace remoting {
 
+using protocol::ErrorCode;
+
 namespace {
 
 const NameMapElement<It2MeHostState> kIt2MeHostStates[] = {
@@ -139,7 +141,8 @@
 
   std::string type;
   if (!message_dict->GetString("type", &type)) {
-    SendErrorAndExit(std::move(response), "'type' not found in request.");
+    LOG(ERROR) << "'type' not found in request.";
+    SendErrorAndExit(std::move(response), ErrorCode::INCOMPATIBLE_PROTOCOL);
     return;
   }
 
@@ -154,7 +157,8 @@
   } else if (type == "incomingIq") {
     ProcessIncomingIq(std::move(message_dict), std::move(response));
   } else {
-    SendErrorAndExit(std::move(response), "Unsupported request type: " + type);
+    LOG(ERROR) << "Unsupported request type: " << type;
+    SendErrorAndExit(std::move(response), ErrorCode::INCOMPATIBLE_PROTOCOL);
   }
 }
 
@@ -210,21 +214,22 @@
     // If the process cannot be started or message passing fails, then return an
     // error to the message sender.
     if (!DelegateToElevatedHost(std::move(message))) {
-      SendErrorAndExit(std::move(response),
-                       "Failed to send message to elevated host.");
+      LOG(ERROR) << "Failed to send message to elevated host.";
+      SendErrorAndExit(std::move(response), ErrorCode::ELEVATION_ERROR);
     }
     return;
   }
 
   if (it2me_host_.get()) {
-    SendErrorAndExit(std::move(response),
-                     "Connect can be called only when disconnected.");
+    LOG(ERROR) << "Connect can be called only when disconnected.";
+    SendErrorAndExit(std::move(response), ErrorCode::UNKNOWN_ERROR);
     return;
   }
 
   std::string username;
   if (!message->GetString("userName", &username)) {
-    SendErrorAndExit(std::move(response), "'userName' not found in request.");
+    LOG(ERROR) << "'userName' not found in request.";
+    SendErrorAndExit(std::move(response), ErrorCode::INCOMPATIBLE_PROTOCOL);
     return;
   }
 
@@ -246,8 +251,8 @@
 
     std::string auth_service_with_token;
     if (!message->GetString("authServiceWithToken", &auth_service_with_token)) {
-      SendErrorAndExit(std::move(response),
-                       "'authServiceWithToken' not found in request.");
+      LOG(ERROR) << "'authServiceWithToken' not found in request.";
+      SendErrorAndExit(std::move(response), ErrorCode::INCOMPATIBLE_PROTOCOL);
       return;
     }
 
@@ -257,8 +262,9 @@
     const char kOAuth2ServicePrefix[] = "oauth2:";
     if (!base::StartsWith(auth_service_with_token, kOAuth2ServicePrefix,
                           base::CompareCase::SENSITIVE)) {
-      SendErrorAndExit(std::move(response), "Invalid 'authServiceWithToken': " +
-                                                auth_service_with_token);
+      LOG(ERROR) << "Invalid 'authServiceWithToken': "
+                 << auth_service_with_token;
+      SendErrorAndExit(std::move(response), ErrorCode::INCOMPATIBLE_PROTOCOL);
       return;
     }
 
@@ -268,20 +274,20 @@
 #if !defined(NDEBUG)
     std::string address;
     if (!message->GetString("xmppServerAddress", &address)) {
-      SendErrorAndExit(std::move(response),
-                       "'xmppServerAddress' not found in request.");
+      LOG(ERROR) << "'xmppServerAddress' not found in request.";
+      SendErrorAndExit(std::move(response), ErrorCode::INCOMPATIBLE_PROTOCOL);
       return;
     }
 
     if (!net::ParseHostAndPort(address, &xmpp_config.host, &xmpp_config.port)) {
-      SendErrorAndExit(std::move(response),
-                       "Invalid 'xmppServerAddress': " + address);
+      LOG(ERROR) << "Invalid 'xmppServerAddress': " << address;
+      SendErrorAndExit(std::move(response), ErrorCode::INCOMPATIBLE_PROTOCOL);
       return;
     }
 
     if (!message->GetBoolean("xmppServerUseTls", &xmpp_config.use_tls)) {
-      SendErrorAndExit(std::move(response),
-                       "'xmppServerUseTls' not found in request.");
+      LOG(ERROR) << "'xmppServerUseTls' not found in request.";
+      SendErrorAndExit(std::move(response), ErrorCode::INCOMPATIBLE_PROTOCOL);
       return;
     }
 #endif  // !defined(NDEBUG)
@@ -293,7 +299,8 @@
     std::string local_jid;
 
     if (!message->GetString("localJid", &local_jid)) {
-      SendErrorAndExit(std::move(response), "'localJid' not found in request.");
+      LOG(ERROR) << "'localJid' not found in request.";
+      SendErrorAndExit(std::move(response), ErrorCode::INCOMPATIBLE_PROTOCOL);
       return;
     }
 
@@ -311,8 +318,8 @@
 
 #if !defined(NDEBUG)
   if (!message->GetString("directoryBotJid", &directory_bot_jid)) {
-    SendErrorAndExit(std::move(response),
-                     "'directoryBotJid' not found in request.");
+    LOG(ERROR) << "'directoryBotJid' not found in request.";
+    SendErrorAndExit(std::move(response), ErrorCode::INCOMPATIBLE_PROTOCOL);
     return;
   }
 #endif  // !defined(NDEBUG)
@@ -357,8 +364,8 @@
     // If the process cannot be started or message passing fails, then return an
     // error to the message sender.
     if (!DelegateToElevatedHost(std::move(message))) {
-      SendErrorAndExit(std::move(response),
-                       "Failed to send message to elevated host.");
+      LOG(ERROR) << "Failed to send message to elevated host.";
+      SendErrorAndExit(std::move(response), ErrorCode::ELEVATION_ERROR);
     }
     return;
   }
@@ -392,13 +399,12 @@
 
 void It2MeNativeMessagingHost::SendErrorAndExit(
     std::unique_ptr<base::DictionaryValue> response,
-    const std::string& description) const {
+    protocol::ErrorCode error_code) const {
   DCHECK(task_runner()->BelongsToCurrentThread());
-
-  LOG(ERROR) << description;
-
   response->SetString("type", "error");
-  response->SetString("description", description);
+  response->SetString("error_code", ErrorCodeToString(error_code));
+  // TODO(kelvinp): Remove this after M61 Webapp is pushed to 100%.
+  response->SetString("description", ErrorCodeToString(error_code));
   SendMessageToClient(std::move(response));
 
   // Trigger a host shutdown by sending an empty message.
@@ -414,9 +420,8 @@
   client_->CloseChannel(std::string());
 }
 
-void It2MeNativeMessagingHost::OnStateChanged(
-    It2MeHostState state,
-    const std::string& error_message) {
+void It2MeNativeMessagingHost::OnStateChanged(It2MeHostState state,
+                                              protocol::ErrorCode error_code) {
   DCHECK(task_runner()->BelongsToCurrentThread());
 
   state_ = state;
@@ -446,7 +451,9 @@
       // "error" message so that errors that occur before the "connect" message
       // is sent can be communicated.
       message->SetString("type", "error");
-      message->SetString("description", error_message);
+      message->SetString("error_code", ErrorCodeToString(error_code));
+      // TODO(kelvinp): Remove this after M61 Webapp is pushed to 100%.
+      message->SetString("description", ErrorCodeToString(error_code));
       break;
 
     default:
diff --git a/remoting/host/it2me/it2me_native_messaging_host.h b/remoting/host/it2me/it2me_native_messaging_host.h
index 28ca6cdc..4aed6ad1 100644
--- a/remoting/host/it2me/it2me_native_messaging_host.h
+++ b/remoting/host/it2me/it2me_native_messaging_host.h
@@ -14,6 +14,7 @@
 #include "build/build_config.h"
 #include "extensions/browser/api/messaging/native_message_host.h"
 #include "remoting/host/it2me/it2me_host.h"
+#include "remoting/protocol/errors.h"
 #include "remoting/signaling/delegating_signal_strategy.h"
 
 #if !defined(OS_CHROMEOS)
@@ -54,7 +55,7 @@
                                  base::TimeDelta access_code_lifetime) override;
   void OnNatPolicyChanged(bool nat_traversal_enabled) override;
   void OnStateChanged(It2MeHostState state,
-                      const std::string& error_message) override;
+                      protocol::ErrorCode error_code) override;
 
   // Set a callback to be called when a policy error notification has been
   // processed.
@@ -75,7 +76,7 @@
   void ProcessIncomingIq(std::unique_ptr<base::DictionaryValue> message,
                          std::unique_ptr<base::DictionaryValue> response);
   void SendErrorAndExit(std::unique_ptr<base::DictionaryValue> response,
-                        const std::string& description) const;
+                        const protocol::ErrorCode error_code) const;
   void SendPolicyErrorAndExit() const;
   void SendMessageToClient(std::unique_ptr<base::Value> message) const;
 
diff --git a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
index 30d6dbc8..1ce9429 100644
--- a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
@@ -33,11 +33,14 @@
 #include "remoting/host/native_messaging/pipe_messaging_channel.h"
 #include "remoting/host/policy_watcher.h"
 #include "remoting/host/setup/test_util.h"
+#include "remoting/protocol/errors.h"
 #include "remoting/protocol/ice_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace remoting {
 
+using protocol::ErrorCode;
+
 namespace {
 
 const char kTestAccessCode[] = "888888";
@@ -159,9 +162,10 @@
 void MockIt2MeHost::RunSetState(It2MeHostState state) {
   if (!host_context()->network_task_runner()->BelongsToCurrentThread()) {
     host_context()->network_task_runner()->PostTask(
-        FROM_HERE, base::Bind(&It2MeHost::SetStateForTesting, this, state, ""));
+        FROM_HERE,
+        base::Bind(&It2MeHost::SetStateForTesting, this, state, ErrorCode::OK));
   } else {
-    SetStateForTesting(state, "");
+    SetStateForTesting(state, ErrorCode::OK);
   }
 }
 
diff --git a/remoting/host/register_support_host_request.cc b/remoting/host/register_support_host_request.cc
index d4617d5..ab62c24 100644
--- a/remoting/host/register_support_host_request.cc
+++ b/remoting/host/register_support_host_request.cc
@@ -29,6 +29,8 @@
 
 namespace remoting {
 
+using protocol::ErrorCode;
+
 namespace {
 // Strings used in the request message we send to the bot.
 const char kRegisterQueryTag[] = "register-support-host";
@@ -78,10 +80,9 @@
         base::Bind(&RegisterSupportHostRequest::ProcessResponse,
                    base::Unretained(this)));
     if (!request_) {
-      std::string error_message =
-          "Error sending the register-support-host request.";
-      LOG(ERROR) << error_message;
-      CallCallback(std::string(), base::TimeDelta(), error_message);
+      LOG(ERROR) << "Error sending the register-support-host request.";
+      CallCallback(std::string(), base::TimeDelta(),
+                   ErrorCode::SIGNALING_ERROR);
       return;
     }
 
@@ -90,9 +91,8 @@
 
   } else if (state == SignalStrategy::DISCONNECTED) {
     // We will reach here if signaling fails to connect.
-    std::string error_message = "Signal strategy disconnected.";
-    LOG(ERROR) << error_message;
-    CallCallback(std::string(), base::TimeDelta(), error_message);
+    LOG(ERROR) << "Signal strategy disconnected.";
+    CallCallback(std::string(), base::TimeDelta(), ErrorCode::SIGNALING_ERROR);
   }
 }
 
@@ -154,45 +154,45 @@
 void RegisterSupportHostRequest::ParseResponse(const XmlElement* response,
                                                std::string* support_id,
                                                base::TimeDelta* lifetime,
-                                               std::string* error_message) {
-  std::ostringstream error;
-
+                                               ErrorCode* error_code) {
   if (!response) {
-    *error_message = "register-support-host request timed out.";
+    LOG(ERROR) << "register-support-host request timed out.";
+    *error_code = ErrorCode::SIGNALING_TIMEOUT;
     return;
   }
 
   std::string type = response->Attr(buzz::QN_TYPE);
   if (type == buzz::STR_ERROR) {
-    error << "Received error in response to heartbeat: " << response->Str();
-    *error_message = error.str();
+    LOG(ERROR) << "Received error in response to heartbeat: "
+               << response->Str();
+    *error_code = ErrorCode::HOST_REGISTRATION_ERROR;
     return;
   }
 
   // This method must only be called for error or result stanzas.
   if (type != buzz::STR_RESULT) {
-    error << "Received unexpect stanza of type \"" << type << "\"";
-    *error_message = error.str();
+    LOG(ERROR) << "Received unexpect stanza of type \"" << type << "\"";
+    *error_code = ErrorCode::HOST_REGISTRATION_ERROR;
     return;
   }
 
   const XmlElement* result_element = response->FirstNamed(QName(
       kChromotingXmlNamespace, kRegisterQueryResultTag));
   if (!result_element) {
-    error << "<" << kRegisterQueryResultTag
-          << "> is missing in the host registration response: "
-          << response->Str();
-    *error_message = error.str();
+    LOG(ERROR) << "<" << kRegisterQueryResultTag
+               << "> is missing in the host registration response: "
+               << response->Str();
+    *error_code = ErrorCode::HOST_REGISTRATION_ERROR;
     return;
   }
 
   const XmlElement* support_id_element =
       result_element->FirstNamed(QName(kChromotingXmlNamespace, kSupportIdTag));
   if (!support_id_element) {
-    error << "<" << kSupportIdTag
-          << "> is missing in the host registration response: "
-          << response->Str();
-    *error_message = error.str();
+    LOG(ERROR) << "<" << kSupportIdTag
+               << "> is missing in the host registration response: "
+               << response->Str();
+    *error_code = ErrorCode::HOST_REGISTRATION_ERROR;
     return;
   }
 
@@ -200,20 +200,20 @@
       result_element->FirstNamed(QName(kChromotingXmlNamespace,
                                        kSupportIdLifetimeTag));
   if (!lifetime_element) {
-    error << "<" << kSupportIdLifetimeTag
-          << "> is missing in the host registration response: "
-          << response->Str();
-    *error_message = error.str();
+    LOG(ERROR) << "<" << kSupportIdLifetimeTag
+               << "> is missing in the host registration response: "
+               << response->Str();
+    *error_code = ErrorCode::HOST_REGISTRATION_ERROR;
     return;
   }
 
   int lifetime_int;
   if (!base::StringToInt(lifetime_element->BodyText(), &lifetime_int) ||
       lifetime_int <= 0) {
-    error << "<" << kSupportIdLifetimeTag
-          << "> is malformed in the host registration response: "
-          << response->Str();
-    *error_message = error.str();
+    LOG(ERROR) << "<" << kSupportIdLifetimeTag
+               << "> is malformed in the host registration response: "
+               << response->Str();
+    *error_code = ErrorCode::HOST_REGISTRATION_ERROR;
     return;
   }
 
@@ -226,25 +226,21 @@
                                                  const XmlElement* response) {
   std::string support_id;
   base::TimeDelta lifetime;
-  std::string error_message;
-  ParseResponse(response, &support_id, &lifetime, &error_message);
-  if (!error_message.empty()) {
-    LOG(ERROR) << error_message;
-  }
-  CallCallback(support_id, lifetime, error_message);
+  ErrorCode error_code = ErrorCode::OK;
+  ParseResponse(response, &support_id, &lifetime, &error_code);
+  CallCallback(support_id, lifetime, error_code);
 }
 
-void RegisterSupportHostRequest::CallCallback(
-    const std::string& support_id,
-    base::TimeDelta lifetime,
-    const std::string& error_message) {
+void RegisterSupportHostRequest::CallCallback(const std::string& support_id,
+                                              base::TimeDelta lifetime,
+                                              ErrorCode error_code) {
   // Cleanup state before calling the callback.
   request_.reset();
   iq_sender_.reset();
   signal_strategy_->RemoveListener(this);
   signal_strategy_ = nullptr;
 
-  base::ResetAndReturn(&callback_).Run(support_id, lifetime, error_message);
+  base::ResetAndReturn(&callback_).Run(support_id, lifetime, error_code);
 }
 
 }  // namespace remoting
diff --git a/remoting/host/register_support_host_request.h b/remoting/host/register_support_host_request.h
index 63f155f..2173c2a 100644
--- a/remoting/host/register_support_host_request.h
+++ b/remoting/host/register_support_host_request.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "remoting/base/rsa_key_pair.h"
+#include "remoting/protocol/errors.h"
 #include "remoting/signaling/signal_strategy.h"
 #include "testing/gtest/include/gtest/gtest_prod.h"
 
@@ -39,7 +40,8 @@
   // is an error message if the request failed, or null if it succeeded.
   typedef base::Callback<void(const std::string&,
                               const base::TimeDelta&,
-                              const std::string&)> RegisterCallback;
+                              protocol::ErrorCode error_code)>
+      RegisterCallback;
 
   // |signal_strategy| and |key_pair| must outlive this
   // object. |callback| is called when registration response is
@@ -67,12 +69,13 @@
 
   void ProcessResponse(IqRequest* request, const buzz::XmlElement* response);
   void ParseResponse(const buzz::XmlElement* response,
-                     std::string* support_id, base::TimeDelta* lifetime,
-                     std::string* error_message);
+                     std::string* support_id,
+                     base::TimeDelta* lifetime,
+                     protocol::ErrorCode* error_code);
 
-  void CallCallback(
-      const std::string& support_id, base::TimeDelta lifetime,
-      const std::string& error_message);
+  void CallCallback(const std::string& support_id,
+                    base::TimeDelta lifetime,
+                    protocol::ErrorCode error_code);
 
   SignalStrategy* signal_strategy_;
   scoped_refptr<RsaKeyPair> key_pair_;
diff --git a/remoting/host/register_support_host_request_unittest.cc b/remoting/host/register_support_host_request_unittest.cc
index 3c39e2e..c9e3d103 100644
--- a/remoting/host/register_support_host_request_unittest.cc
+++ b/remoting/host/register_support_host_request_unittest.cc
@@ -18,6 +18,7 @@
 #include "remoting/base/rsa_key_pair.h"
 #include "remoting/base/test_rsa_key_pair.h"
 #include "remoting/host/host_details.h"
+#include "remoting/protocol/errors.h"
 #include "remoting/signaling/iq_sender.h"
 #include "remoting/signaling/mock_signal_strategy.h"
 #include "remoting/signaling/signaling_address.h"
@@ -38,6 +39,8 @@
 
 namespace remoting {
 
+using protocol::ErrorCode;
+
 namespace {
 const char kTestBotJid[] = "remotingunittest@bot.talk.google.com";
 const char kTestJid[] = "User@gmail.com/chromotingABC123";
@@ -91,7 +94,7 @@
 
   // Generate response and verify that callback is called.
   EXPECT_CALL(callback_, Run("", base::TimeDelta::FromSeconds(0),
-                             "register-support-host request timed out."));
+                             ErrorCode::SIGNALING_TIMEOUT));
 
   mock_time_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(15));
 }
@@ -157,8 +160,8 @@
   EXPECT_EQ(expected_signature, signature->BodyText());
 
   // Generate response and verify that callback is called.
-  EXPECT_CALL(callback_,
-              Run(kSupportId, base::TimeDelta::FromSeconds(300), ""));
+  EXPECT_CALL(callback_, Run(kSupportId, base::TimeDelta::FromSeconds(300),
+                             ErrorCode::OK));
 
   std::unique_ptr<XmlElement> response(new XmlElement(buzz::QN_IQ));
   response->AddAttr(QName(std::string(), "from"), kTestBotJid);
diff --git a/remoting/ios/app/BUILD.gn b/remoting/ios/app/BUILD.gn
index 2f85879..56e87cb0 100644
--- a/remoting/ios/app/BUILD.gn
+++ b/remoting/ios/app/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//remoting/build/config/remoting_build.gni")
 import("//remoting/ios/app/remoting_ios_tmpl.gni")
 
 group("all") {
@@ -12,6 +13,20 @@
   ]
 }
 
+foreach(locale, remoting_locales_with_underscores) {
+  bundle_data("locale_${locale}_bundle_data") {
+    sources = [
+      "$root_out_dir/remoting/resources/$locale.lproj/locale.pak",
+    ]
+    outputs = [
+      "{{bundle_resources_dir}}/$locale.lproj/{{source_file_part}}",
+    ]
+    public_deps = [
+      "//remoting/resources:copy_locales",
+    ]
+  }
+}
+
 # source set to be used by both external and internal app.
 source_set("common_source_set") {
   sources = [
@@ -78,11 +93,16 @@
     "//remoting/ios/mdc",
     "//remoting/ios/persistence",
     "//remoting/protocol",
+    "//remoting/resources",
     "//ui/base",
     "//ui/gfx",
     "//ui/resources",
   ]
 
+  foreach(locale, remoting_locales_with_underscores) {
+    deps += [ ":locale_${locale}_bundle_data" ]
+  }
+
   public_deps = [
     "//ios/third_party/material_components_ios",
   ]
diff --git a/remoting/ios/app/first_launch_view_controller.mm b/remoting/ios/app/first_launch_view_controller.mm
index 4e318fd..59a1b67f 100644
--- a/remoting/ios/app/first_launch_view_controller.mm
+++ b/remoting/ios/app/first_launch_view_controller.mm
@@ -11,6 +11,9 @@
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
 #import "remoting/ios/app/remoting_theme.h"
 
+#include "remoting/base/string_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
 static const float kLogoSizeMultiplier = 0.381966f;
 static const float kLogoYOffset = -10.f;
 static const float kButtonHeight = 80.f;
@@ -34,7 +37,8 @@
   [self.view addSubview:imageView];
 
   MDCFlatButton* signInButton = [[MDCFlatButton alloc] init];
-  [signInButton setTitle:@"Sign in" forState:UIControlStateNormal];
+  [signInButton setTitle:l10n_util::GetNSString(IDS_SIGN_IN_BUTTON)
+                forState:UIControlStateNormal];
   [signInButton sizeToFit];
   [signInButton addTarget:self
                    action:@selector(didTapSignIn:)
diff --git a/remoting/ios/app/help_view_controller.mm b/remoting/ios/app/help_view_controller.mm
index fbd8027..d154532 100644
--- a/remoting/ios/app/help_view_controller.mm
+++ b/remoting/ios/app/help_view_controller.mm
@@ -8,6 +8,9 @@
 
 #import "remoting/ios/app/help_view_controller.h"
 
+#include "remoting/base/string_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
 // TODO(nicholss): These urls should come from a global config.
 static NSString* const kHelpCenterUrl =
     @"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DiOS";
@@ -20,11 +23,11 @@
 
 - (instancetype)init {
   if (self = [super initWithUrl:kHelpCenterUrl title:@"Help Center"]) {
-    self.navigationItem.rightBarButtonItem =
-        [[UIBarButtonItem alloc] initWithTitle:@"Credits"
-                                         style:UIBarButtonItemStylePlain
-                                        target:self
-                                        action:@selector(onTapCredits:)];
+    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
+        initWithTitle:l10n_util::GetNSString(IDS_CREDITS)
+                style:UIBarButtonItemStylePlain
+               target:self
+               action:@selector(onTapCredits:)];
   }
   return self;
 }
@@ -32,9 +35,9 @@
 #pragma mark - Private
 
 - (void)onTapCredits:(id)button {
-  WebViewController* creditsVC =
-      [[WebViewController alloc] initWithUrl:kCreditsUrlString
-                                       title:@"Credits"];
+  WebViewController* creditsVC = [[WebViewController alloc]
+      initWithUrl:kCreditsUrlString
+            title:l10n_util::GetNSString(IDS_CREDITS)];
   [self.navigationController pushViewController:creditsVC animated:YES];
 }
 
diff --git a/remoting/ios/app/main.mm b/remoting/ios/app/main.mm
index 9f49bcd..bfab2da 100644
--- a/remoting/ios/app/main.mm
+++ b/remoting/ios/app/main.mm
@@ -14,6 +14,8 @@
 #include "base/at_exit.h"
 #include "base/command_line.h"
 #include "base/i18n/icu_util.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
 
 int main(int argc, char* argv[]) {
   // This class is designed to fulfill the dependents needs when it goes out of
@@ -32,6 +34,11 @@
   logging::SetMinLogLevel(-1);
 #endif
 
+  l10n_util::OverrideLocaleWithCocoaLocale();
+  ui::ResourceBundle::InitSharedInstanceWithLocale(
+      "" /* Overridden by cocal locale */, NULL,
+      ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES);
+
   @autoreleasepool {
     [AppInitializer initializeApp];
     return UIApplicationMain(
diff --git a/remoting/ios/app/remoting_view_controller.mm b/remoting/ios/app/remoting_view_controller.mm
index f4054cc1..5b2184c 100644
--- a/remoting/ios/app/remoting_view_controller.mm
+++ b/remoting/ios/app/remoting_view_controller.mm
@@ -28,7 +28,9 @@
 
 #include "base/strings/sys_string_conversions.h"
 #include "remoting/base/oauth_token_getter.h"
+#include "remoting/base/string_resources.h"
 #include "remoting/client/connect_to_host_info.h"
+#include "ui/base/l10n/l10n_util.h"
 
 static CGFloat kHostInset = 5.f;
 
@@ -74,7 +76,8 @@
     _appBar = [[MDCAppBar alloc] init];
     [self addChildViewController:_appBar.headerViewController];
 
-    self.navigationItem.title = @"chrome remote desktop";
+    self.navigationItem.title =
+        l10n_util::GetNSString(IDS_PRODUCT_NAME).lowercaseString;
 
     UIBarButtonItem* menuButton =
         [[UIBarButtonItem alloc] initWithImage:RemotingTheme.menuIcon
@@ -163,7 +166,7 @@
            completion:(void (^)())completionBlock {
   if (![cell.hostInfo isOnline]) {
     MDCSnackbarMessage* message = [[MDCSnackbarMessage alloc] init];
-    message.text = @"Host is offline.";
+    message.text = l10n_util::GetNSString(IDS_HOST_OFFLINE_TOOLTIP);
     [MDCSnackbarManager showMessage:message];
     return;
   }
diff --git a/remoting/ios/app/session_reconnect_view.mm b/remoting/ios/app/session_reconnect_view.mm
index 3c3aafe..7f4bdd5 100644
--- a/remoting/ios/app/session_reconnect_view.mm
+++ b/remoting/ios/app/session_reconnect_view.mm
@@ -11,6 +11,9 @@
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
 #import "remoting/ios/app/remoting_theme.h"
 
+#include "remoting/base/string_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
 static const CGFloat kReconnectButtonWidth = 120.f;
 static const CGFloat kReconnectButtonHeight = 30.f;
 
@@ -30,7 +33,8 @@
 
     _reconnectButton = [[MDCRaisedButton alloc] init];
     [_reconnectButton setElevation:4.0f forState:UIControlStateNormal];
-    [_reconnectButton setTitle:@"Reconnect" forState:UIControlStateNormal];
+    [_reconnectButton setTitle:l10n_util::GetNSString(IDS_RECONNECT)
+                      forState:UIControlStateNormal];
     [_reconnectButton addTarget:self
                          action:@selector(didTapReconnect:)
                forControlEvents:UIControlEventTouchUpInside];
diff --git a/remoting/ios/app/side_menu_items.mm b/remoting/ios/app/side_menu_items.mm
index fcb4be5..3ed69951 100644
--- a/remoting/ios/app/side_menu_items.mm
+++ b/remoting/ios/app/side_menu_items.mm
@@ -11,6 +11,9 @@
 #import "remoting/ios/app/app_delegate.h"
 #import "remoting/ios/app/remoting_theme.h"
 
+#include "remoting/base/string_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
 static NSString* const kFeedbackContext = @"SideMenuFeedbackContext";
 
 #pragma mark - SideMenuItem
@@ -50,17 +53,18 @@
   dispatch_once(&onceToken, ^{
     items = @[ @[
       [[SideMenuItem alloc]
-          initWithTitle:@"Send Feedback"
+          initWithTitle:l10n_util::GetNSString(IDS_ACTIONBAR_SEND_FEEDBACK)
                    icon:RemotingTheme.feedbackIcon
                  action:^{
                    [AppDelegate.instance
                        presentFeedbackFlowWithContext:kFeedbackContext];
                  }],
-      [[SideMenuItem alloc] initWithTitle:@"Help"
-                                     icon:RemotingTheme.helpIcon
-                                   action:^{
-                                     [AppDelegate.instance presentHelpCenter];
-                                   }],
+      [[SideMenuItem alloc]
+          initWithTitle:l10n_util::GetNSString(IDS_ACTIONBAR_HELP)
+                   icon:RemotingTheme.helpIcon
+                 action:^{
+                   [AppDelegate.instance presentHelpCenter];
+                 }],
     ] ];
   });
   return items;
diff --git a/remoting/ios/session/remoting_client.mm b/remoting/ios/session/remoting_client.mm
index 10e6844..53946ea 100644
--- a/remoting/ios/session/remoting_client.mm
+++ b/remoting/ios/session/remoting_client.mm
@@ -279,7 +279,8 @@
       break;
     case remoting::protocol::ErrorCode::HOST_CONFIGURATION_ERROR:
       _sessionDetails.error = SessionErrorHostConfigurationError;
-    case remoting::protocol::ErrorCode::UNKNOWN_ERROR:
+      break;
+    default:
       _sessionDetails.error = SessionErrorUnknownError;
       break;
   }
diff --git a/remoting/protocol/errors.cc b/remoting/protocol/errors.cc
index 383db8a..2af4a29 100644
--- a/remoting/protocol/errors.cc
+++ b/remoting/protocol/errors.cc
@@ -13,19 +13,22 @@
 namespace {
 
 const NameMapElement<ErrorCode> kErrorCodeNames[] = {
-  { OK, "OK" },
-  { PEER_IS_OFFLINE, "PEER_IS_OFFLINE" },
-  { SESSION_REJECTED, "SESSION_REJECTED" },
-  { INCOMPATIBLE_PROTOCOL, "INCOMPATIBLE_PROTOCOL" },
-  { AUTHENTICATION_FAILED, "AUTHENTICATION_FAILED" },
-  { INVALID_ACCOUNT, "INVALID_ACCOUNT" },
-  { CHANNEL_CONNECTION_ERROR, "CHANNEL_CONNECTION_ERROR" },
-  { SIGNALING_ERROR, "SIGNALING_ERROR" },
-  { SIGNALING_TIMEOUT, "SIGNALING_TIMEOUT" },
-  { HOST_OVERLOAD, "HOST_OVERLOAD" },
-  { MAX_SESSION_LENGTH, "MAX_SESSION_LENGTH" },
-  { HOST_CONFIGURATION_ERROR, "HOST_CONFIGURATION_ERROR" },
-  { UNKNOWN_ERROR, "UNKNOWN_ERROR" },
+    {OK, "OK"},
+    {PEER_IS_OFFLINE, "PEER_IS_OFFLINE"},
+    {SESSION_REJECTED, "SESSION_REJECTED"},
+    {INCOMPATIBLE_PROTOCOL, "INCOMPATIBLE_PROTOCOL"},
+    {AUTHENTICATION_FAILED, "AUTHENTICATION_FAILED"},
+    {INVALID_ACCOUNT, "INVALID_ACCOUNT"},
+    {CHANNEL_CONNECTION_ERROR, "CHANNEL_CONNECTION_ERROR"},
+    {SIGNALING_ERROR, "SIGNALING_ERROR"},
+    {SIGNALING_TIMEOUT, "SIGNALING_TIMEOUT"},
+    {HOST_OVERLOAD, "HOST_OVERLOAD"},
+    {MAX_SESSION_LENGTH, "MAX_SESSION_LENGTH"},
+    {HOST_CONFIGURATION_ERROR, "HOST_CONFIGURATION_ERROR"},
+    {ELEVATION_ERROR, "ELEVATION_ERROR"},
+    {HOST_CERTIFICATE_ERROR, "HOST_CERTIFICATE_ERROR"},
+    {HOST_REGISTRATION_ERROR, "HOST_REGISTRATION_ERROR"},
+    {UNKNOWN_ERROR, "UNKNOWN_ERROR"},
 };
 
 }  // namespace
diff --git a/remoting/protocol/errors.h b/remoting/protocol/errors.h
index 6a9dfd5..ee9abd4 100644
--- a/remoting/protocol/errors.h
+++ b/remoting/protocol/errors.h
@@ -29,7 +29,9 @@
   MAX_SESSION_LENGTH,
   HOST_CONFIGURATION_ERROR,
   UNKNOWN_ERROR,
-
+  ELEVATION_ERROR,
+  HOST_CERTIFICATE_ERROR,
+  HOST_REGISTRATION_ERROR,
   ERROR_CODE_MAX = UNKNOWN_ERROR,
 };
 
diff --git a/services/preferences/BUILD.gn b/services/preferences/BUILD.gn
index 841cc6b..3e7a94d 100644
--- a/services/preferences/BUILD.gn
+++ b/services/preferences/BUILD.gn
@@ -11,6 +11,11 @@
   source = "manifest.json"
 }
 
+service_manifest("local_state_manifest") {
+  name = "local_state"
+  source = "local_state_manifest.json"
+}
+
 source_set("preferences") {
   visibility = [
     ":*",
diff --git a/services/preferences/local_state_manifest.json b/services/preferences/local_state_manifest.json
new file mode 100644
index 0000000..f3c2468
--- /dev/null
+++ b/services/preferences/local_state_manifest.json
@@ -0,0 +1,15 @@
+{
+  "name": "local_state",
+  "display_name": "Local state preferences",
+  "interface_provider_specs": {
+    "service_manager:connector": {
+      "provides": {
+        "pref_client": [
+          "prefs::mojom::PrefStoreConnector"
+        ]
+      },
+      "requires": {
+      }
+    }
+  }
+}
diff --git a/services/preferences/public/interfaces/preferences.mojom b/services/preferences/public/interfaces/preferences.mojom
index 09f6bd11..02a8bf9 100644
--- a/services/preferences/public/interfaces/preferences.mojom
+++ b/services/preferences/public/interfaces/preferences.mojom
@@ -10,6 +10,7 @@
 import "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom";
 
 const string kServiceName = "preferences";
+const string kLocalStateServiceName = "local_state";
 const string kForwarderServiceName = "preferences_forwarder";
 
 // The know pref store types.
diff --git a/storage/browser/fileapi/sandbox_directory_database.cc b/storage/browser/fileapi/sandbox_directory_database.cc
index 91c4914..32844fc 100644
--- a/storage/browser/fileapi/sandbox_directory_database.cc
+++ b/storage/browser/fileapi/sandbox_directory_database.cc
@@ -746,11 +746,9 @@
   options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   if (env_override_)
     options.env = env_override_;
-  leveldb::DB* db;
-  leveldb::Status status = leveldb::DB::Open(options, path, &db);
+  leveldb::Status status = leveldb_env::OpenDB(options, path, &db_);
   ReportInitStatus(status);
   if (status.ok()) {
-    db_.reset(db);
     return true;
   }
   HandleError(FROM_HERE, status);
diff --git a/storage/browser/fileapi/sandbox_origin_database.cc b/storage/browser/fileapi/sandbox_origin_database.cc
index 2cfd3f3..e79760f 100644
--- a/storage/browser/fileapi/sandbox_origin_database.cc
+++ b/storage/browser/fileapi/sandbox_origin_database.cc
@@ -87,11 +87,9 @@
   options.reuse_logs = leveldb_env::kDefaultLogReuseOptionValue;
   if (env_override_)
     options.env = env_override_;
-  leveldb::DB* db;
-  leveldb::Status status = leveldb::DB::Open(options, path, &db);
+  leveldb::Status status = leveldb_env::OpenDB(options, path, &db_);
   ReportInitStatus(status);
   if (status.ok()) {
-    db_.reset(db);
     return true;
   }
   HandleError(FROM_HERE, status);
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 2f87b6fc..a1d2afeb 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -127,6 +127,26 @@
           "can_use_on_swarming_builders": false
         },
         "test": "vr_common_unittests"
+      },
+      {
+        "args": [
+          "--shared-prefs-file=../../chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json",
+          "--replace-system-package=com.google.vr.vrcore,../../third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
+          "--test-filter=WebViewWebVrTest#*"
+        ],
+        "name": "webview_instrumentation_test_apk-marlin-ddview-nougat",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "device_os": "NMF26U",
+              "device_type": "marlin"
+            }
+          ],
+          "hard_timeout": 960
+        },
+        "test": "webview_instrumentation_test_apk"
       }
     ],
     "instrumentation_tests": [
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 36bbaba..a73a4b0 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -327,7 +327,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-applies-to-012.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-width-002.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floating-replaced-height-008.xht [ Skip ]
-crbug.com/719615 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-001.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-005.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-028.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-029.xht [ Failure ]
@@ -349,7 +348,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-033.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-034.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-035.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-125.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-157.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-clear-008.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-clear-012.xht [ Failure ]
@@ -441,8 +439,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/absolute-replaced-height-032.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/absolute-replaced-height-033.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/absolute-replaced-height-036.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/absolute-replaced-width-013.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/absolute-replaced-width-027.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/absolute-replaced-width-036.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/absolute-replaced-width-037.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/absolute-replaced-width-043.xht [ Failure ]
@@ -537,7 +533,6 @@
 crbug.com/635619 virtual/layout_ng/fast/block/float/020.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/022.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/023.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/float/024.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/025.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/026.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/027.html [ Failure ]
@@ -628,7 +623,6 @@
 crbug.com/635619 virtual/layout_ng/fast/block/float/width-update-after-clear.html [ Failure ]
 
 ### virtual/layout_ng/fast/block/margin-collapse
-crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/025.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/032.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/033.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/043.html [ Failure ]
@@ -636,7 +630,6 @@
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/101.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/103.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/bfc-beside-float-complex-margin-collapsing.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/self-collapsing-block-creates-block-formatting-context.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/self-collapsing-block-with-overflow-hidden-and-float-child.html [ Failure ]
 
 ### virtual/layout_ng/fast/block/margin-collapse/block-inside-inline
@@ -645,7 +638,6 @@
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/011.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/012.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/015.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/block-inside-inline/025.html [ Failure ]
 
 ### virtual/layout_ng/fast/block/margin-collapse
 crbug.com/635619 virtual/layout_ng/fast/block/margin-collapse/clear-nested-float-more-than-one-previous-sibling-away.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/assert-when-moving-float-2-expected.txt b/third_party/WebKit/LayoutTests/fast/block/float/assert-when-moving-float-2-expected.txt
new file mode 100644
index 0000000..07a6f7f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/float/assert-when-moving-float-2-expected.txt
@@ -0,0 +1 @@
+fooPass if no assert in debug.
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/assert-when-moving-float-2.html b/third_party/WebKit/LayoutTests/fast/block/float/assert-when-moving-float-2.html
new file mode 100644
index 0000000..aad0589
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/float/assert-when-moving-float-2.html
@@ -0,0 +1,11 @@
+<div style="width: 5px;">
+  <img id="makeTaller" style="height: 50px; width: 1px"><img id="removeThis" style="width: 5px; height: 5px;"> <div style="float: left;">foo</div>Pass if no assert in debug.</div>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+var removeThis = document.getElementById("removeThis");
+removeThis.offsetTop;
+removeThis.parentNode.removeChild(removeThis); 
+;
+makeTaller.style.height = '55px';
+</script>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-aria-1.1-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-aria-1.1-expected.txt
index d7607b2..41e58de3 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-aria-1.1-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-aria-1.1-expected.txt
@@ -1,4 +1,4 @@
-
+Tests ARIA 1.1 accessibility markup.
 {
   "nodeId": "<string>",
   "ignored": false,
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-aria-1.1.js b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-aria-1.1.js
index 18a1c1a9..73a6bbe 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-aria-1.1.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-aria-1.1.js
@@ -9,7 +9,7 @@
     <button data-dump aria-keyshortcuts='Ctrl+A'>Select All</button>
 
     <input data-dump type='checkbox' aria-roledescription='Lightswitch' checked>
-  `, '');
+  `, 'Tests ARIA 1.1 accessibility markup.');
 
   var dumpAccessibilityNodesBySelectorAndCompleteTest =
       (await testRunner.loadScript('../resources/accessibility-dumpAccessibilityNodes.js'))(testRunner, session);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getNodeWithNoAXNode-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getNodeWithNoAXNode-expected.txt
index 4ac4872..0f0a2e5 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getNodeWithNoAXNode-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getNodeWithNoAXNode-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that node without AXNode reports accessibility values.
 {
   "nodeId": "<string>",
   "ignored": true,
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getNodeWithNoAXNode.js b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getNodeWithNoAXNode.js
index c4816d9a..3ac4ac9 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getNodeWithNoAXNode.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getNodeWithNoAXNode.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   let {page, session, dp} = await testRunner.startHTML(`
     <input type='text'></input>
-  `, '');
+  `, 'Tests that node without AXNode reports accessibility values.');
 
   var dumpAccessibilityNodesBySelectorAndCompleteTest =
       (await testRunner.loadScript('../resources/accessibility-dumpAccessibilityNodes.js'))(testRunner, session);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships-expected.txt
index 9154d60e..408926c5 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships-expected.txt
@@ -1,4 +1,4 @@
-
+Tests relationship accessibility values.
 {
   "nodeId": "<string>",
   "ignored": false,
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships.js b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships.js
index 272d7c0..c57837e9 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-getRelationships.js
@@ -38,7 +38,7 @@
         Ginger Ale
       </li>
     </ul>
-  `, '');
+  `, 'Tests relationship accessibility values.');
 
   var dumpAccessibilityNodesBySelectorAndCompleteTest =
       (await testRunner.loadScript('../resources/accessibility-dumpAccessibilityNodes.js'))(testRunner, session);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt
index e2bf251..2399847e1 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt
@@ -1,4 +1,4 @@
-
+Tests accessibility values of ignored nodes.
 
 WebArea
   tree
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes.js b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes.js
index 57799fb..d85f218 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes.js
@@ -44,7 +44,7 @@
       <div id='inert-root' inert>
         <button data-dump>button in inert subtree</button>
       </div>
-  `, '');
+  `, 'Tests accessibility values of ignored nodes.');
 
   var dumpAccessibilityNodesBySelectorAndCompleteTest =
       (await testRunner.loadScript('../resources/accessibility-dumpAccessibilityNodes.js'))(testRunner, session);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesModal-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesModal-expected.txt
index d500dde..45429f6 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesModal-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesModal-expected.txt
@@ -1,4 +1,4 @@
-
+Tests accessibility values of ignored nodes in model dialog.
 {
   "nodeId": "<string>",
   "ignored": true,
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesModal.js b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesModal.js
index 577d3c4..80bd147 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesModal.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodesModal.js
@@ -10,7 +10,7 @@
         (Dialog itself is not hidden)
         <div data-dump>Non-hidden element inside dialog</div>
     </dialog>
-  `, '');
+  `, 'Tests accessibility values of ignored nodes in model dialog.');
 
   var dumpAccessibilityNodesBySelectorAndCompleteTest =
       (await testRunner.loadScript('../resources/accessibility-dumpAccessibilityNodes.js'))(testRunner, session);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-modal-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-modal-expected.txt
index 3ef2b29..67638193 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-modal-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-modal-expected.txt
@@ -1,4 +1,4 @@
-
+Tests accessibility values in modal dialog.
 {
   "nodeId": "<string>",
   "ignored": false,
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-modal.js b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-modal.js
index e10563b..f63594c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-modal.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-modal.js
@@ -12,7 +12,7 @@
       <dialog data-dump>Closed Dialog</dialog>
       <dialog data-dump open>Open Dialog</dialog>
     </dialog>
-  `, '');
+  `, 'Tests accessibility values in modal dialog.');
 
   var dumpAccessibilityNodesBySelectorAndCompleteTest =
       (await testRunner.loadScript('../resources/accessibility-dumpAccessibilityNodes.js'))(testRunner, session);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-buttons-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-buttons-expected.txt
index f2c17fd..22b3e7e 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-buttons-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-buttons-expected.txt
@@ -1,4 +1,4 @@
-
+Tests name sources in buttons.
 {
   "nodeId": "<string>",
   "ignored": false,
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-buttons.js b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-buttons.js
index 8e7380c..d058005 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-buttons.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-buttons.js
@@ -35,7 +35,7 @@
        <button id='button11'>button11-content</button>
        <label for='button11'>label-for-button11</label>
      </div>
-  `, '');
+  `, 'Tests name sources in buttons.');
 
   var dumpAccessibilityNodesBySelectorAndCompleteTest =
       (await testRunner.loadScript('../resources/accessibility-dumpAccessibilityNodes.js'))(testRunner, session);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-img-figure-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-img-figure-expected.txt
index f3792a7a..e3f843b9 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-img-figure-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-img-figure-expected.txt
@@ -1,4 +1,4 @@
-
+Tests name sources in images and figures.
 {
   "nodeId": "<string>",
   "ignored": false,
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-img-figure.js b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-img-figure.js
index 4b531559a..e279b49 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-img-figure.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-img-figure.js
@@ -58,7 +58,7 @@
         <title>svg1-title</title>
       </svg>
     </div>
-  `, '');
+  `, 'Tests name sources in images and figures.');
 
   var dumpAccessibilityNodesBySelectorAndCompleteTest =
       (await testRunner.loadScript('../resources/accessibility-dumpAccessibilityNodes.js'))(testRunner, session);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input-buttons-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input-buttons-expected.txt
index 0a58e1b7..2b052dc 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input-buttons-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input-buttons-expected.txt
@@ -1,4 +1,4 @@
-
+Tests name sources in input[type=button].
 {
   "nodeId": "<string>",
   "ignored": false,
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input-buttons.js b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input-buttons.js
index 99007ba6..c440a6c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input-buttons.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input-buttons.js
@@ -53,7 +53,7 @@
 
       <input id='image-input5' type='image' src='resources/cake.png' title='image-input-title5'>
     </div>
-  `, '');
+  `, 'Tests name sources in input[type=button].');
 
   var dumpAccessibilityNodesBySelectorAndCompleteTest =
       (await testRunner.loadScript('../resources/accessibility-dumpAccessibilityNodes.js'))(testRunner, session);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input-expected.txt
index aac4641..c399f32 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input-expected.txt
@@ -1,4 +1,4 @@
-
+Tests name sources in inputs.
 {
   "nodeId": "<string>",
   "ignored": false,
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input.js b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input.js
index c6d5d94f..568c1846 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-input.js
@@ -43,7 +43,7 @@
 
       <input data-dump id='text12' type='text' title='text12-title' aria-placeholder='text12-aria-placeholder'>
   </div>
-  `, '');
+  `, 'Tests name sources in inputs.');
 
   var dumpAccessibilityNodesBySelectorAndCompleteTest =
       (await testRunner.loadScript('../resources/accessibility-dumpAccessibilityNodes.js'))(testRunner, session);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-labelledby-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-labelledby-expected.txt
index b497f66..ee02d5e2 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-labelledby-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-labelledby-expected.txt
@@ -1,4 +1,4 @@
-
+Tests name sources when used with aria-labelledby.
 {
   "nodeId": "<string>",
   "ignored": false,
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-labelledby.js b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-labelledby.js
index d861c55..cb98afd 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-labelledby.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-labelledby.js
@@ -65,7 +65,7 @@
       </ul>
       <div role='listitem' id='list1_item3'>C</div>
     </div>
-  `, '');
+  `, 'Tests name sources when used with aria-labelledby.');
 
   var dumpAccessibilityNodesBySelectorAndCompleteTest =
       (await testRunner.loadScript('../resources/accessibility-dumpAccessibilityNodes.js'))(testRunner, session);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-summary-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-summary-expected.txt
index 49a66e4..2f44c51 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-summary-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-summary-expected.txt
@@ -1,4 +1,4 @@
-
+Tests name sources in details and summary.
 {
   "nodeId": "<string>",
   "ignored": false,
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-summary.js b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-summary.js
index 7cb80c13..4f35f43d 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-summary.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-summary.js
@@ -39,7 +39,7 @@
       </details>
       <span hidden='true' id='labelledby5'>summary5-aria-labelledby</span>
     </div>
-  `, '');
+  `, 'Tests name sources in details and summary.');
 
   var dumpAccessibilityNodesBySelectorAndCompleteTest =
       (await testRunner.loadScript('../resources/accessibility-dumpAccessibilityNodes.js'))(testRunner, session);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-visiblity-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-visiblity-expected.txt
index e1983b06..49ddf6cb 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-visiblity-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-visiblity-expected.txt
@@ -1,4 +1,4 @@
-
+Tests name sources in invisible nodes.
 {
   "nodeId": "<string>",
   "ignored": false,
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-visiblity.js b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-visiblity.js
index c87c783..c034f03 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-visiblity.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-nameSources-visiblity.js
@@ -97,7 +97,7 @@
         After</label>
       <input data-dump id='input5'>
     </div>
-  `, '');
+  `, 'Tests name sources in invisible nodes.');
 
   var dumpAccessibilityNodesBySelectorAndCompleteTest =
       (await testRunner.loadScript('../resources/accessibility-dumpAccessibilityNodes.js'))(testRunner, session);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-create-start-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-create-start-expected.txt
index 45f747e2..a88d861 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-create-start-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-create-start-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that animation creation and start are reported over protocol.
 Animation created
 Animation started
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-create-start.js b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-create-start.js
index b9beac3f..75b33a0 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-create-start.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-create-start.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   let {page, session, dp} = await testRunner.startHTML(`
     <div id='node' style='background-color: red; height: 100px'></div>
-  `, '');
+  `, 'Tests that animation creation and start are reported over protocol.');
 
   dp.Animation.enable();
   session.evaluate(`node.animate([{ width: '100px' }, { width: '200px' }], 2000);`);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-css-replay-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-css-replay-expected.txt
index 63e18fa..dbbe49a 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-css-replay-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-css-replay-expected.txt
@@ -1,4 +1,4 @@
-
+Tests replaying css animation.
 Animation started
 Animation seeked
 Animation seeked
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-css-replay.js b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-css-replay.js
index ed77716..90041cf9 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-css-replay.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-css-replay.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   let {page, session, dp} = await testRunner.startHTML(`
     <div id='node' style='background-color: red; height: 100px; transition: width 100ms; width: 100px'></div>
-  `, '');
+  `, 'Tests replaying css animation.');
 
   dp.Animation.enable();
   session.evaluate(`node.style.width = '200px';`);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-empty-transition-cancel-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-empty-transition-cancel-expected.txt
index 411484a7..bd83b53 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-empty-transition-cancel-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-empty-transition-cancel-expected.txt
@@ -1,4 +1,4 @@
-
+Test that canceling css transition is reported over protocol.
 Animation created
 Animation canceled
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-empty-transition-cancel.js b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-empty-transition-cancel.js
index 0fd2256..abcce335 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-empty-transition-cancel.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-empty-transition-cancel.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   let {page, session, dp} = await testRunner.startHTML(`
     <div id='node' style='background-color: red; width: 100px'></div>
-  `, '');
+  `, 'Test that canceling css transition is reported over protocol.');
 
   dp.Animation.onAnimationCreated(() => testRunner.log('Animation created'));
   dp.Animation.onAnimationCanceled(() => testRunner.log('Animation canceled'));
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-multiple-frames-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-multiple-frames-expected.txt
index 33009db22..6770a4c9 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-multiple-frames-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-multiple-frames-expected.txt
@@ -1,4 +1,4 @@
-
+Tests animation notifications from multiple frames.
 Frame appended
 Animation started: start time is valid
 Frame appended
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-multiple-frames.js b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-multiple-frames.js
index dcf19cf..0657437 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-multiple-frames.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-multiple-frames.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests animation notifications from multiple frames.');
 
   await session.evaluate(`
     function appendIframe() {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-pause-close-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-pause-close-expected.txt
index 4873c3a2..1eeac32 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-pause-close-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-pause-close-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that the playback rate is reset on disabling.
 0
 1
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-pause-close.js b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-pause-close.js
index f099a2cf..64e32d4 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-pause-close.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-pause-close.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests that the playback rate is reset on disabling.');
 
   dp.Animation.enable();
   await dp.Animation.setPlaybackRate({ playbackRate: 0 });
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-paused-css-animation-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-paused-css-animation-expected.txt
index 411484a7..ce3e7f7 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-paused-css-animation-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-paused-css-animation-expected.txt
@@ -1,4 +1,4 @@
-
+Test that css animation can be paused over protocol.
 Animation created
 Animation canceled
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-paused-css-animation.js b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-paused-css-animation.js
index a52764b..a59171f 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-paused-css-animation.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-paused-css-animation.js
@@ -15,7 +15,7 @@
     }
     </style>
     <div id='node' style='background-color: red; width: 100px'></div>
-  `, '');
+  `, 'Test that css animation can be paused over protocol.');
 
 
   dp.Animation.enable();
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-resolve-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-resolve-expected.txt
index 9e19f321..473675c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-resolve-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-resolve-expected.txt
@@ -1,4 +1,4 @@
-
+Tests how animation could be resolved into remote object.
 Animation started
 Remote object:
 Animation
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-resolve.js b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-resolve.js
index 6bc0e5a..5f58877 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-resolve.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-resolve.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   let {page, session, dp} = await testRunner.startHTML(`
     <div id='node' style='background-color: red; height: 100px'></div>
-  `, '');
+  `, 'Tests how animation could be resolved into remote object.');
 
   dp.Animation.enable();
   session.evaluate(`
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-seek-past-end-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-seek-past-end-expected.txt
index 797aa06..9aa15b4 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-seek-past-end-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-seek-past-end-expected.txt
@@ -1,4 +1,4 @@
-
+Tests seeking animation past end time.
 Animation started
 100
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-seek-past-end.js b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-seek-past-end.js
index 53ecb41..56bef66 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-seek-past-end.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-seek-past-end.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   let {page, session, dp} = await testRunner.startHTML(`
     <div id='node' style='background-color: red; height: 100px; width: 100px'></div>
-  `, '');
+  `, 'Tests seeking animation past end time.');
 
   dp.Animation.enable();
   session.evaluate(`
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-start-cancel-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-start-cancel-expected.txt
index 3fc6b00..7de07b62 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-start-cancel-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-start-cancel-expected.txt
@@ -1,4 +1,4 @@
-
+Tests animationCanceled notification.
 Animation created
 Animation started
 Animation canceled
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-start-cancel.js b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-start-cancel.js
index 015d7a37..4629ad7 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-start-cancel.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-start-cancel.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   let {page, session, dp} = await testRunner.startHTML(`
     <div id='node' style='background-color: red; width: 100px'></div>
-  `, '');
+  `, 'Tests animationCanceled notification.');
 
   dp.Animation.onAnimationCreated(() => testRunner.log('Animation created'));
   dp.Animation.onAnimationStarted(() => testRunner.log('Animation started'));
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-zero-duration-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-zero-duration-expected.txt
index 45f747e2..945f13bf5 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-zero-duration-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-zero-duration-expected.txt
@@ -1,4 +1,4 @@
-
+Tests how zero-duration animations are reported over protocol.
 Animation created
 Animation started
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-zero-duration.js b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-zero-duration.js
index d39a9402..962538de 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-zero-duration.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/animation/animation-zero-duration.js
@@ -15,7 +15,7 @@
     }
     </style>
     <div id='node' style='background-color: red; width: 100px'></div>
-  `, '');
+  `, 'Tests how zero-duration animations are reported over protocol.');
 
   dp.Animation.enable();
   session.evaluate('node.classList.add("anim")');
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/console/console-dom-mutation-violations-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/console/console-dom-mutation-violations-expected.txt
index 03b0db9b..2e18d9a 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/console/console-dom-mutation-violations-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/console/console-dom-mutation-violations-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that dom modification event listener produces a violation.
 {
     method : Log.entryAdded
     params : {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/console/console-dom-mutation-violations.js b/third_party/WebKit/LayoutTests/inspector-protocol/console/console-dom-mutation-violations.js
index c1c53c6..cbad047 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/console/console-dom-mutation-violations.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/console/console-dom-mutation-violations.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests that dom modification event listener produces a violation.');
   dp.Log.onEntryAdded(testRunner.logMessage.bind(testRunner));
   dp.Log.enable();
   dp.Log.startViolationsReport({config: [{name: 'discouragedAPIUse', threshold: -1}]});
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/console/console-let-const-with-api-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/console/console-let-const-with-api-expected.txt
index 96202017..834265c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/console/console-let-const-with-api-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/console/console-let-const-with-api-expected.txt
@@ -1,4 +1,4 @@
-
+Tests how let/const declarations interact with command line api.
 first 'let a = 1;' result: wasThrown = false
 second 'let a = 1;' result: wasThrown = true
 exception message: Uncaught SyntaxError: Identifier 'a' has already been declared
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/console/console-let-const-with-api.js b/third_party/WebKit/LayoutTests/inspector-protocol/console/console-let-const-with-api.js
index fb650b9f..073eb438 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/console/console-let-const-with-api.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/console/console-let-const-with-api.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests how let/const declarations interact with command line api.');
 
   var response = await dp.Runtime.evaluate({expression: 'let a = 42;'});
   failIfError(response);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/access-obsolete-frame-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/access-obsolete-frame-expected.txt
index 87741ca..e217399 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/access-obsolete-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/access-obsolete-frame-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that accessing old call frame does not work.
 Paused on 'debugger;'
 resume
 restartFrame
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/access-obsolete-frame.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/access-obsolete-frame.js
index b9ec2d0..07047f1 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/access-obsolete-frame.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/access-obsolete-frame.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests that accessing old call frame does not work.');
 
   function logErrorResponse(response) {
     if (response.error) {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/call-frame-functionLocation-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/call-frame-functionLocation-expected.txt
index ccc8515..3426c32 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/call-frame-functionLocation-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/call-frame-functionLocation-expected.txt
@@ -1,4 +1,4 @@
-
+Tests function location in CallFrame.
 Paused on 'debugger;'
 Top frame location: {"scriptId":"42","lineNumber":8,"columnNumber":4}
 Top frame functionLocation: {"scriptId":"42","lineNumber":5,"columnNumber":21}
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/call-frame-functionLocation.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/call-frame-functionLocation.js
index f7f3db31..8443154 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/call-frame-functionLocation.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/call-frame-functionLocation.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests function location in CallFrame.');
 
   dp.Debugger.enable();
   dp.Runtime.evaluate({expression: `
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation-expected.txt
index 404cd9ac..12ce6028 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation-expected.txt
@@ -1,4 +1,4 @@
-
+Tests continueToLocation functionality.
 Paused on debugger statement
 Paused after continueToLocation
 Stopped on line 8, expected 8, requested 8, (0-based numbers).
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation.js
index 466535a..fd57785c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests continueToLocation functionality.');
 
   function statementsExample()
   {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-evaluate-in-worker-while-pause-in-page-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-evaluate-in-worker-while-pause-in-page-expected.txt
index aa6355b6..bb9d700 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-evaluate-in-worker-while-pause-in-page-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-evaluate-in-worker-while-pause-in-page-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that one can evaluate in worker while main page is paused.
 Started worker
 Paused on 'debugger;'
 Worker created
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-evaluate-in-worker-while-pause-in-page.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-evaluate-in-worker-while-pause-in-page.js
index 76ede5e..6bef769c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-evaluate-in-worker-while-pause-in-page.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-evaluate-in-worker-while-pause-in-page.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests that one can evaluate in worker while main page is paused.');
 
   await session.evaluate(`
     window.worker = new Worker('${testRunner.url('resources/dedicated-worker.js')}');
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker-expected.txt
index bd6d733..a7eec1f 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that worker can be paused.
 Started worker
 Worker created
 didConnectToWorker
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker-loop-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker-loop-expected.txt
index 0b8048b..6265038 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker-loop-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker-loop-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that worker can be interrupted and paused.
 Started worker
 Worker created
 didConnectToWorker
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker-loop.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker-loop.js
index ec3325f..31a44f6 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker-loop.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker-loop.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests that worker can be interrupted and paused.');
 
   await session.evaluate(`
     window.worker = new Worker('${testRunner.url('resources/dedicated-worker-loop.js')}');
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker.js
index 90542a2..9bbd5df 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-dedicated-worker.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests that worker can be paused.');
 
   await session.evaluate(`
     window.worker = new Worker('${testRunner.url('resources/dedicated-worker.js')}');
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-in-tight-loop-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-in-tight-loop-expected.txt
index a769f3e..99ce45d6 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-in-tight-loop-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-in-tight-loop-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that JS can be interrupted and paused.
 didEval
 didFireTimer
 SUCCESS: Paused
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-in-tight-loop.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-in-tight-loop.js
index f56dc97e..b643192 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-in-tight-loop.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-pause-in-tight-loop.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests that JS can be interrupted and paused.');
 
   await dp.Runtime.enable();
   await dp.Debugger.enable();
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-scope-skip-variables-with-empty-name-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-scope-skip-variables-with-empty-name-expected.txt
index f1a2108..38b54a7 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-scope-skip-variables-with-empty-name-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-scope-skip-variables-with-empty-name-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that we do not report scope variables with empty names.
 {
     result : [
         [0] : {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-scope-skip-variables-with-empty-name.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-scope-skip-variables-with-empty-name.js
index a9e8871..372ef23 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-scope-skip-variables-with-empty-name.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-scope-skip-variables-with-empty-name.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests that we do not report scope variables with empty names.');
 
   dp.Debugger.enable();
   dp.Runtime.evaluate({expression: `
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setBlackboxPatterns-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setBlackboxPatterns-expected.txt
index 3e19260..be84c2bf5 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setBlackboxPatterns-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setBlackboxPatterns-expected.txt
@@ -1,4 +1,4 @@
-
+Tests setBlackboxPatterns functionality.
 Pattern parser error: Uncaught SyntaxError: Invalid regular expression: /(foo([)/: Unterminated character class
 Paused in
 (...):1
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setBlackboxPatterns.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setBlackboxPatterns.js
index 65cc402..e0eb515 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setBlackboxPatterns.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setBlackboxPatterns.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests setBlackboxPatterns functionality.');
 
   await session.evaluate(`
     function bar()
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setEventListenerBreakpoint-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setEventListenerBreakpoint-expected.txt
index 77c15196..43f6249 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setEventListenerBreakpoint-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setEventListenerBreakpoint-expected.txt
@@ -1,4 +1,4 @@
-
+Tests event listener breakpoints.
 PASS: Debugger was enabled
 Error on attempt to set event listener breakpoint when DOM is disabled: undefined
 PASS: DOM was enabled
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setEventListenerBreakpoint.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setEventListenerBreakpoint.js
index 15ff82f..af14c45 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setEventListenerBreakpoint.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setEventListenerBreakpoint.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests event listener breakpoints.');
 
   function finishIfError(message) {
     if (message.result)
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setTimeout-sourceUrl-dedicated-worker-loop-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setTimeout-sourceUrl-dedicated-worker-loop-expected.txt
index c4ac494d..16fb012 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setTimeout-sourceUrl-dedicated-worker-loop-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setTimeout-sourceUrl-dedicated-worker-loop-expected.txt
@@ -1,4 +1,4 @@
-
+Tests sourceURL in setTimeout from worker.
 Started worker
 Worker created
 didConnectToWorker
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setTimeout-sourceUrl-dedicated-worker-loop.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setTimeout-sourceUrl-dedicated-worker-loop.js
index 7133bb2..7f44c60 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setTimeout-sourceUrl-dedicated-worker-loop.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setTimeout-sourceUrl-dedicated-worker-loop.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests sourceURL in setTimeout from worker.');
 
   await session.evaluate(`
     window.worker = new Worker('${testRunner.url('resources/dedicated-worker-string-setTimeout.js')}');
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-getEventListeners-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-getEventListeners-expected.txt
index 231a947..6569a286 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-getEventListeners-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-getEventListeners-expected.txt
@@ -1,4 +1,4 @@
-
+Tests how DOMDebugger reports event listeners for nodes.
 Event listeners of window
   type:click
   useCapture:true
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-getEventListeners.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-getEventListeners.js
index 3a7b1dd2..2cf2e497 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-getEventListeners.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-getEventListeners.js
@@ -2,7 +2,7 @@
   let {page, session, dp} = await testRunner.startHTML(`
     <div id='listeners1' onload='return 42;'></div>
     <div id='listeners2'></div>
-  `, ``);
+  `, `Tests how DOMDebugger reports event listeners for nodes.`);
 
   function logGetListenersResult(title, response) {
     testRunner.log('Event listeners of ' + title);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-script-blocked-by-csp-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-script-blocked-by-csp-expected.txt
index a6902f5..b0baeb3 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-script-blocked-by-csp-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-script-blocked-by-csp-expected.txt
@@ -1,4 +1,4 @@
-
+Tests pausing on scriptBlockedbyCSP breakpoint.
 
 -------
 blockedEventHandler
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-script-blocked-by-csp.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-script-blocked-by-csp.js
index 8f700db..b127cb58 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-script-blocked-by-csp.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-script-blocked-by-csp.js
@@ -8,7 +8,7 @@
     <button id='testButton' onclick='alert(1);'>Button</button>
     </body>
     </html>
-  `, ``);
+  `, `Tests pausing on scriptBlockedbyCSP breakpoint.`);
 
   dp.Debugger.enable();
   dp.DOM.enable();
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-setInnerHTML-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-setInnerHTML-expected.txt
index 4dce98314..3ca0cd7 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-setInnerHTML-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-setInnerHTML-expected.txt
@@ -1,3 +1,3 @@
-
+Tests pausing on setInnerHTML breakpoint.
 Paused on the innerHTML assignment: modifyHTML@:7
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-setInnerHTML.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-setInnerHTML.js
index 486242e..479040e 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-setInnerHTML.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-setInnerHTML.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   let {page, session, dp} = await testRunner.startHTML(`
     <div id='divUnderTest'></div>
-  `, ``);
+  `, `Tests pausing on setInnerHTML breakpoint.`);
 
   dp.Debugger.enable();
   dp.DOM.enable();
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/postMessage-on-pause-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/postMessage-on-pause-expected.txt
index 96cf4515..f8200e7 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/postMessage-on-pause-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/postMessage-on-pause-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that worker can be paused in postMessage.
 Paused on 'debugger;'
 PASS: message has not been dispatched yet.
 PASS: message has not been dispatched yet.
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/postMessage-on-pause.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/postMessage-on-pause.js
index 6a2b7b1..c0ce838 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/postMessage-on-pause.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/postMessage-on-pause.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests that worker can be paused in postMessage.');
 
   dp.Debugger.enable();
   dp.Runtime.evaluate({expression: `
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/scriptParsedHash-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/scriptParsedHash-expected.txt
index b5a0f54..abc78e2 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/scriptParsedHash-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/scriptParsedHash-expected.txt
@@ -1,4 +1,4 @@
-
+Tests hash field in scriptParsed event.
 Hash received: 1C6D2E82E4E4F1BA4CB5762843D429DC872EBA18
 Hash received: EBF1ECD351E7A3294CB5762843D429DC872EBA18
 Hash received: 22D0043331237371241FC675A984B967025A3DC0
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/scriptParsedHash.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/scriptParsedHash.js
index 8e5db35c..37bf722 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/scriptParsedHash.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/scriptParsedHash.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests hash field in scriptParsed event.');
 
   var hashes = new Set(['1C6D2E82E4E4F1BA4CB5762843D429DC872EBA18',
                         'EBF1ECD351E7A3294CB5762843D429DC872EBA18',
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/setScriptSource-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/setScriptSource-expected.txt
index 9e355e2..8381592c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/setScriptSource-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/setScriptSource-expected.txt
@@ -1,4 +1,4 @@
-
+Tests setScriptSource functionality.
 Function evaluate: {"type":"number","value":6,"description":"6"}
 PASS, result value: 6
 Function evaluate: {"type":"number","value":8,"description":"8"}
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/setScriptSource.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/setScriptSource.js
index 31b4f61..ac5142078 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/setScriptSource.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/setScriptSource.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests setScriptSource functionality.');
 
   function logEqualsCheck(actual, expected) {
     if (actual == expected) {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/step-over-caught-exception-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/step-over-caught-exception-expected.txt
index e6ce4af3..5afa4fe 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/step-over-caught-exception-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/step-over-caught-exception-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that stepping over caught exception does not pause.
 testFunction:13
 testFunction:15
 testFunction:13
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/step-over-caught-exception.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/step-over-caught-exception.js
index a30526d..c9fbf90c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/step-over-caught-exception.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/step-over-caught-exception.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests that stepping over caught exception does not pause.');
 
   dp.Debugger.enable();
   dp.Runtime.enable();
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/stepping-with-blackboxed-ranges-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/stepping-with-blackboxed-ranges-expected.txt
index e4a3e75..df694fc 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/stepping-with-blackboxed-ranges-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/stepping-with-blackboxed-ranges-expected.txt
@@ -1,4 +1,4 @@
-
+Tests how stepping works with some source ranges blackboxed.
 foo: 14:4
 blackboxedBoo: 3:12
 notBlackboxedFoo: 3:12
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/stepping-with-blackboxed-ranges.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/stepping-with-blackboxed-ranges.js
index 49757284..c51c9d4 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/stepping-with-blackboxed-ranges.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/stepping-with-blackboxed-ranges.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests how stepping works with some source ranges blackboxed.');
 
   function printCallFrames(response) {
     var callFrames = response.params.callFrames;
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/updateCallFrameScopes-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/updateCallFrameScopes-expected.txt
index 55d32b9..6275691 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/updateCallFrameScopes-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/updateCallFrameScopes-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that evaluation on call frame affects scope variables.
 Paused on 'debugger;'
 Variable value changed
 Stacktrace re-read again
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/updateCallFrameScopes.js b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/updateCallFrameScopes.js
index 09e007d..03706f0 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/updateCallFrameScopes.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/updateCallFrameScopes.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests that evaluation on call frame affects scope variables.');
 
   var newVariableValue = 55;
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-childNodeCount-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-childNodeCount-expected.txt
index bc68f00..ebd981b0 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-childNodeCount-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-childNodeCount-expected.txt
@@ -1,4 +1,4 @@
-
+Tests how DOM.childNodeCountUpdated event works.
 Node arrived with childNodeCount: 2
 childCountUpdated: 3
 childCountUpdated: 2
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-childNodeCount.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-childNodeCount.js
index 87a82d9..d35e10f8 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-childNodeCount.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-childNodeCount.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   var {page, session, dp} = await testRunner.startHTML(`
         <div id='container' style='display:none'><div>child1</div><div>child2</div></div>
-  `, '');
+  `, 'Tests how DOM.childNodeCountUpdated event works.');
   var NodeTracker = await testRunner.loadScript('../resources/node-tracker.js');
   var nodeTracker = new NodeTracker(dp);
   var containerNodeId;
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-collect-class-names-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-collect-class-names-expected.txt
index 7eb410f..adbc2bf 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-collect-class-names-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-collect-class-names-expected.txt
@@ -1,4 +1,4 @@
-
+Tests collecting class names in DOM domain.
 All class names: 
 body-class
 class1
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-collect-class-names.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-collect-class-names.js
index 7ae0e31..8fedc3e2 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-collect-class-names.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-collect-class-names.js
@@ -10,7 +10,7 @@
     <div class='class5 class6'></div>
     <div id='shadow-host'></div>
     </body>
-  `, '');
+  `, 'Tests collecting class names in DOM domain.');
 
   await session.evaluate(() => {
     var host = document.querySelector('#shadow-host');
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-focus-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-focus-expected.txt
index 7eb2762..9a45af0a 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-focus-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-focus-expected.txt
@@ -1,4 +1,4 @@
-
+Tests DOM.focus method.
 BODY
 second
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-focus.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-focus.js
index b37f2104..180f64e5 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-focus.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-focus.js
@@ -2,7 +2,7 @@
   var {page, session, dp} = await testRunner.startHTML(`
     <input></input>
     <input id='second'></input>
-  `, '');
+  `, 'Tests DOM.focus method.');
 
   testRunner.log(await session.evaluate(getActiveElement));
   var document = (await dp.DOM.getDocument()).result.root;
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getBoxModel-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getBoxModel-expected.txt
index ee0c60e..823d855f 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getBoxModel-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getBoxModel-expected.txt
@@ -1,4 +1,4 @@
-
+Tests DOM.getBoxModel method.
 #text: Could not compute box model.
 BR: Could not compute box model.
 #text: Could not compute box model.
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getBoxModel.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getBoxModel.js
index 355a27f..22e56807 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getBoxModel.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getBoxModel.js
@@ -7,7 +7,7 @@
     <div style='position:absolute;top:100;left:0;width:100;height:100;background:red'></div>
     <div style='position:absolute;top:200;left:100;width:100;height:100;background:green'></div>
     <div style='position:absolute;top:150;left:50;width:100;height:100;background:blue;transform:rotate(45deg);'></div>
-  `, '');
+  `, 'Tests DOM.getBoxModel method.');
   var NodeTracker = await testRunner.loadScript('../resources/node-tracker.js');
   var nodeTracker = new NodeTracker(dp);
   dp.DOM.enable();
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getEventListeners-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getEventListeners-expected.txt
index d64df28..d52035d 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getEventListeners-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getEventListeners-expected.txt
@@ -1,4 +1,4 @@
-
+Tests retrieving event listeners from DOMDebugger.
 Fetching listeners for depth = undefined and pierce = undefined
 {
     listeners : [
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getEventListeners.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getEventListeners.js
index 77d57ef..9297de9a 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getEventListeners.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getEventListeners.js
@@ -20,7 +20,7 @@
         <iframe src='../dom/resources/iframe-with-listener.html' width='400' height='200'></iframe>
         <div id='shadow-host'></div>
     </body>
-  `, '');
+  `, 'Tests retrieving event listeners from DOMDebugger.');
 
   await session.evaluate(() => {
     var host = document.querySelector('#shadow-host').createShadowRoot();
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getFlattenedDocument-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getFlattenedDocument-expected.txt
index f3872528..48ca8e9 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getFlattenedDocument-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getFlattenedDocument-expected.txt
@@ -1,4 +1,4 @@
-
+Tests DOM.getFlattenedDocument method.
 {
     nodes : [
         [0] : {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getFlattenedDocument.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getFlattenedDocument.js
index 0226158d..d97be28 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getFlattenedDocument.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getFlattenedDocument.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  var {page, session, dp} = await testRunner.startURL('resources/dom-getFlattenedDocument.html', '');
+  var {page, session, dp} = await testRunner.startURL('resources/dom-getFlattenedDocument.html', 'Tests DOM.getFlattenedDocument method.');
 
   await session.evaluate(() => {
     var host = document.querySelector('#shadow-host').createShadowRoot();
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation-expected.txt
index fb08317..e5201d7 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation-expected.txt
@@ -1,4 +1,4 @@
-
+Tests DOM.getNodeForLocation method.
 Node: {
     attributes : [
         [0] : style
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation-skip-shadow-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation-skip-shadow-expected.txt
index 6de23ac..390385a 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation-skip-shadow-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation-skip-shadow-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that DOM.getNodeForLocation method correctly skips shadow dom when instructed.
 Node: {
     attributes : [
         [0] : type
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation-skip-shadow.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation-skip-shadow.js
index 8d1fa44..9e29d17 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation-skip-shadow.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation-skip-shadow.js
@@ -3,7 +3,7 @@
     <form action='#'>
         <input type='text' style='position:absolute;top:0;left:0;width:100;height:100' />
     </form>
-  `, '');
+  `, 'Tests that DOM.getNodeForLocation method correctly skips shadow dom when instructed.');
 
   var NodeTracker = await testRunner.loadScript('../resources/node-tracker.js');
   var nodeTracker = new NodeTracker(dp);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation.js
index 0efa2331..a784b8ef 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-getNodeForLocation.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   var {page, session, dp} = await testRunner.startHTML(`
     <div style='position:absolute;top:0;left:0;width:100;height:100'></div>
-  `, '');
+  `, 'Tests DOM.getNodeForLocation method.');
   var NodeTracker = await testRunner.loadScript('../resources/node-tracker.js');
   var nodeTracker = new NodeTracker(dp);
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-relayout-boundary-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-relayout-boundary-expected.txt
index 3134f64..aa97ef65 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-relayout-boundary-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-relayout-boundary-expected.txt
@@ -1,4 +1,4 @@
-
+Tests DOM.getRelayoutBoundary method.
 Relayout boundary for div#outer is: html
 Relayout boundary for div#boundary is: div#boundary
 Relayout boundary for div#inner is: div#boundary
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-relayout-boundary.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-relayout-boundary.js
index 147ffa9..85c98c6 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-relayout-boundary.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-relayout-boundary.js
@@ -18,7 +18,7 @@
         </div>
     </div>
     </body>
-  `, '');
+  `, 'Tests DOM.getRelayoutBoundary method.');
 
   var DOMHelper = await testRunner.loadScript('../resources/dom-helper.js');
   var NodeTracker = await testRunner.loadScript('../resources/node-tracker.js');
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-depth-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-depth-expected.txt
index bd4942a1..378f971 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-depth-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-depth-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that DOM.requestChildNodes respects depth parameter.
 
 === Get the Document ===
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-depth.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-depth.js
index 4d43543d3..375c696 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-depth.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-depth.js
@@ -20,7 +20,7 @@
             </div>
         </div>
     </div>
-  `, '');
+  `, 'Tests that DOM.requestChildNodes respects depth parameter.');
   testRunner.log("\n=== Get the Document ===\n");
   var response = await dp.DOM.getDocument();
   var bodyId = response.result.root.children[0].children[1].nodeId;
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames-expected.txt
index ab12676..b4befbd 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames-expected.txt
@@ -1,4 +1,4 @@
-
+Tests how DOM.requestChildNodes pierces through frames.
 {
     method : DOM.setChildNodes
     params : {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames.js
index 01db208..fc9ea1a 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  var {page, session, dp} = await testRunner.startURL('resources/dom-request-child-nodes-traverse-frames.html', '');
+  var {page, session, dp} = await testRunner.startURL('resources/dom-request-child-nodes-traverse-frames.html', 'Tests how DOM.requestChildNodes pierces through frames.');
 
   var response = await dp.DOM.getDocument();
   var rootId = response.result.root.children[0].children[1].nodeId;
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes-expected.txt
index 3339db2..4aab7f0 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes-expected.txt
@@ -1,4 +1,4 @@
-
+Tests how DOM.getDocument reports all child nodes when asked.
 {
     id : <messageId>
     result : {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes.js
index f9d57a7..b621e43c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  var {page, session, dp} = await testRunner.startURL('./resources/dom-request-document-with-child-nodes.html', '');
+  var {page, session, dp} = await testRunner.startURL('./resources/dom-request-document-with-child-nodes.html', 'Tests how DOM.getDocument reports all child nodes when asked.');
   var response = await dp.DOM.getDocument({depth: -1});
   var iframeOwner = response.result.root.children[0].children[1].children[0].children[0].children[0].children[0];
   if (iframeOwner.contentDocument.children) {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setInspectModeEnabled-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setInspectModeEnabled-expected.txt
index f2c9ae0..d19c27b 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setInspectModeEnabled-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setInspectModeEnabled-expected.txt
@@ -1,3 +1,3 @@
-
+Tests inspect mode.
 DOM.inspectNodeRequested: div
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setInspectModeEnabled.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setInspectModeEnabled.js
index 041f2d4..b2bc173 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setInspectModeEnabled.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setInspectModeEnabled.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   var {page, session, dp} = await testRunner.startHTML(`
     <div style="position:absolute;top:100;left:100;width:100;height:100;background:black"></div>
-  `, '');
+  `, 'Tests inspect mode.');
   var NodeTracker = await testRunner.loadScript('../resources/node-tracker.js');
   var nodeTracker = new NodeTracker(dp);
   dp.DOM.enable();
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML-expected.txt
index 6686493..3174681c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML-expected.txt
@@ -1,4 +1,4 @@
-
+Tests how DOM domain works with outerHTML.
 {
     id : <messageId>
     result : {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML.js
index db1d9cf0..c2ac481 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML.js
@@ -2,7 +2,7 @@
   var {page, session, dp} = await testRunner.startHTML(`
     <div id="id">Привет мир</div>
     <div>Привет мир 2</div>
-  `, '');
+  `, 'Tests how DOM domain works with outerHTML.');
 
   var message = await dp.DOM.getDocument();
   message = await dp.DOM.querySelector({ nodeId: message.result.root.nodeId, selector: "body" });
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/push-children-on-pseudo-addition-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/push-children-on-pseudo-addition-expected.txt
index a134109..3b5dacc 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/push-children-on-pseudo-addition-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/push-children-on-pseudo-addition-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that DOM pushes child node updates on pseudo-element addition.
 
 === Get the Document ===
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/push-children-on-pseudo-addition.js b/third_party/WebKit/LayoutTests/inspector-protocol/dom/push-children-on-pseudo-addition.js
index 8fd19e2..02a8f46b 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/push-children-on-pseudo-addition.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/push-children-on-pseudo-addition.js
@@ -3,7 +3,7 @@
     <style id='style'>
     </style>
     <div id='for-pseudo'><span id='inner-span'></span></div>
-  `, '');
+  `, 'Tests that DOM pushes child node updates on pseudo-element addition.');
 
   var DOMHelper = await testRunner.loadScript('../resources/dom-helper.js');
   var NodeTracker = await testRunner.loadScript('../resources/node-tracker.js');
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent-expected.txt
index 61ff70cc..b3a4cdf 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent-expected.txt
@@ -1,4 +1,4 @@
-
+Tests Input.dispatchKeyEvent method.
 -----Event-----
 type: keydown
 keyCode: 65
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent-focus-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent-focus-expected.txt
index 16ba9092..b616e4a7 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent-focus-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent-focus-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that Input.dispatchKeyEvent method affects focus.
 focus foo
 blur foo
 focus bar
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent-focus.js b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent-focus.js
index d22ffd8..e1c1aa8 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent-focus.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent-focus.js
@@ -5,7 +5,7 @@
       <input id='bar'>
       <input id='baz'>
     </div>
-  `, ``);
+  `, `Tests that Input.dispatchKeyEvent method affects focus.`);
 
   function type(text) {
     for (var i = 0; i < text.length; ++i) {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent.js b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent.js
index 43ca9f0..91eeed68 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchKeyEvent.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank(``);
+  let {page, session, dp} = await testRunner.startBlank(`Tests Input.dispatchKeyEvent method.`);
 
   await session.evaluate(`
     window.addEventListener('keydown', logEvent);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchMouseEvent-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchMouseEvent-expected.txt
index 6d3b378..912f9b6c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchMouseEvent-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchMouseEvent-expected.txt
@@ -1,4 +1,4 @@
-
+Tests Input.dispatchMouseEvent method.
 -----Event-----
 type: mousedown
 button: 0
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchMouseEvent.js b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchMouseEvent.js
index e567ece..bc24f93 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchMouseEvent.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchMouseEvent.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank(``);
+  let {page, session, dp} = await testRunner.startBlank(`Tests Input.dispatchMouseEvent method.`);
 
   await session.evaluate(`
     var logs = [];
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchTouchEvent-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchTouchEvent-expected.txt
index b29e0f4..eacc0da 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchTouchEvent-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchTouchEvent-expected.txt
@@ -1,4 +1,4 @@
-
+Tests Input.dispatchTouchEvent method.
 -----Event-----
 type: touchstart
 ----Touches----
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchTouchEvent.js b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchTouchEvent.js
index 19c715be..f7636812 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchTouchEvent.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchTouchEvent.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank(``);
+  let {page, session, dp} = await testRunner.startBlank(`Tests Input.dispatchTouchEvent method.`);
 
   await session.evaluate(`
     var logs = [];
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/input/emulateTouchFromMouseEvent-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/input/emulateTouchFromMouseEvent-expected.txt
index 992646a6..c3e41d45 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/input/emulateTouchFromMouseEvent-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/input/emulateTouchFromMouseEvent-expected.txt
@@ -1,4 +1,4 @@
-
+Tests Input.emulateTouchFromMouseEvent method.
 -----Event-----
 type: touchstart
 ----Touches----
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/input/emulateTouchFromMouseEvent.js b/third_party/WebKit/LayoutTests/inspector-protocol/input/emulateTouchFromMouseEvent.js
index b893db28b..f7f037e 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/input/emulateTouchFromMouseEvent.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/input/emulateTouchFromMouseEvent.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank(``);
+  let {page, session, dp} = await testRunner.startBlank(`Tests Input.emulateTouchFromMouseEvent method.`);
 
   await session.evaluate(`
     var logs = [];
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/input/eventTimestamp-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/input/eventTimestamp-expected.txt
index a9ecd20..084a3a35 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/input/eventTimestamp-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/input/eventTimestamp-expected.txt
@@ -1,4 +1,4 @@
-
+Tests timestamps in multiple input domain methods.
 -----Event-----
 type: keydown
 -----Event-----
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/input/eventTimestamp.js b/third_party/WebKit/LayoutTests/inspector-protocol/input/eventTimestamp.js
index ab819f4..26334ec 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/input/eventTimestamp.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/input/eventTimestamp.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank(``);
+  let {page, session, dp} = await testRunner.startBlank(`Tests timestamps in multiple input domain methods.`);
 
   await session.evaluate(`
     var logs = [];
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/layers/get-layers-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/layers/get-layers-expected.txt
index 0aebf27..fb32d80 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/layers/get-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/layers/get-layers-expected.txt
@@ -1,4 +1,4 @@
-
+Tests LayerTree domain reporting layers.
 
 [
     {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/layers/get-layers.js b/third_party/WebKit/LayoutTests/inspector-protocol/layers/get-layers.js
index d5b92584..807675b 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/layers/get-layers.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/layers/get-layers.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startURL('../resources/get-layers.html', '');
+  let {page, session, dp} = await testRunner.startURL('../resources/get-layers.html', 'Tests LayerTree domain reporting layers.');
 
   function layerMutations(oldLayers, newLayers) {
     var oldLayerIds = oldLayers.map(layer => layer.layerId);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/createIsolatedWorld-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/page/createIsolatedWorld-expected.txt
index 25412b51..95ad768 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/createIsolatedWorld-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/createIsolatedWorld-expected.txt
@@ -1,4 +1,4 @@
-
+Tests Page.createIsolatedWorld method.
 Runtime enabled
 Page enabled
 Main Frame obtained
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/createIsolatedWorld.js b/third_party/WebKit/LayoutTests/inspector-protocol/page/createIsolatedWorld.js
index 08fff78e..d79c8a13 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/createIsolatedWorld.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/createIsolatedWorld.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests Page.createIsolatedWorld method.');
 
   var reportedExecutionContextId;
   dp.Runtime.onExecutionContextCreated(message => {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/enable-disable-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/page/enable-disable-expected.txt
index cfb1129..89173568 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/enable-disable-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/enable-disable-expected.txt
@@ -1,4 +1,4 @@
-
+Tests enabling/disabling Page domain while recording Timeline.
 Timeline started
 Page enabled
 Page disabled
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/enable-disable.js b/third_party/WebKit/LayoutTests/inspector-protocol/page/enable-disable.js
index cf8a7c2..dd6d1cc 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/enable-disable.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/enable-disable.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests enabling/disabling Page domain while recording Timeline.');
 
   var log = [];
   dp.Timeline.onEventRecorded(msg => {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedDetached-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedDetached-expected.txt
index 0a98a03..dbc7395 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedDetached-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedDetached-expected.txt
@@ -1,4 +1,4 @@
-
+Tests frame lifetime events.
 Attached
 Started loading
 Navigated
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedDetached.js b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedDetached.js
index 2289713..c88388c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedDetached.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedDetached.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests frame lifetime events.');
 
   dp.Page.enable();
   session.evaluate(`
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedStacktrace-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedStacktrace-expected.txt
index 67103ef..e6e7fc9a 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedStacktrace-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedStacktrace-expected.txt
@@ -1,4 +1,4 @@
-
+Tests stackTrace reported on frame attach.
 Frame Attached
 Stack is empty
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedStacktrace.js b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedStacktrace.js
index c33f020..9a5fbdc 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedStacktrace.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameAttachedStacktrace.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startURL('../resources/frame-attached-stacktrace-page.html', '');
+  let {page, session, dp} = await testRunner.startURL('../resources/frame-attached-stacktrace-page.html', 'Tests stackTrace reported on frame attach.');
 
   const expectedNumberOfFrames = 3;
   var currentFrameCount = 0;
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameScheduledNavigation-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameScheduledNavigation-expected.txt
index 4ff01d8..9b3ed5d7 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameScheduledNavigation-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameScheduledNavigation-expected.txt
@@ -1,4 +1,4 @@
-
+Tests frameScheduledNavigation event when navigation is initiated in JS.
 Scheduled navigation with delay 0
 Started loading
 Cleared scheduled navigation
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameScheduledNavigation.js b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameScheduledNavigation.js
index ce7b7b2..22c99657 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameScheduledNavigation.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameScheduledNavigation.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests frameScheduledNavigation event when navigation is initiated in JS.');
 
   dp.Page.enable();
   session.evaluate(`
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameStartedLoading-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameStartedLoading-expected.txt
index 560ef57..58a9004a 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameStartedLoading-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameStartedLoading-expected.txt
@@ -1,4 +1,4 @@
-
+Tests frameStartedLoading/frameStoppedLoading events.
 Started loading
 Stopped loading
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameStartedLoading.js b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameStartedLoading.js
index 369d91a..c73e90f 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/frameStartedLoading.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/frameStartedLoading.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests frameStartedLoading/frameStoppedLoading events.');
 
   dp.Page.enable();
   session.evaluate(`
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/javascriptDialogEvents-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/page/javascriptDialogEvents-expected.txt
index c7caed0..16ef90dc 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/javascriptDialogEvents-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/javascriptDialogEvents-expected.txt
@@ -1,4 +1,4 @@
-
+Tests that javascript dialogs send events.
 Opening dialog: type=beforeunload; message=beforeunload in javascriptDialogEvents
 Closed dialog: result=false
 Opening dialog: type=alert; message=alert
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/javascriptDialogEvents.js b/third_party/WebKit/LayoutTests/inspector-protocol/page/javascriptDialogEvents.js
index 67902583..aeefa7b5 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/javascriptDialogEvents.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/javascriptDialogEvents.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank('Tests that javascript dialogs send events.');
 
   await session.evaluate(`
     testRunner.setShouldStayOnPageAfterHandlingBeforeUnload(true);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript-expected.txt
index 0e62f4f..7289139 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript-expected.txt
@@ -1,4 +1,4 @@
-
+Tests Runtime.compileScript functionality.
 Compiling script: foo1.js
          persist: false
 compilation result: {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript.js b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript.js
index 7bfc5ca..81d1e85 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank(``);
+  let {page, session, dp} = await testRunner.startBlank(`Tests Runtime.compileScript functionality.`);
 
   await dp.Debugger.enable();
   dp.Debugger.onScriptParsed(messageObject => {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-line-and-column-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-line-and-column-expected.txt
index 77b39d2..1a0cf7a 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-line-and-column-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-line-and-column-expected.txt
@@ -1,4 +1,4 @@
-
+Tests line and column numbers in reported console messages.
 {
     method : Runtime.consoleAPICalled
     params : {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-line-and-column.js b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-line-and-column.js
index dadc4fe..020f6621 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-line-and-column.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-line-and-column.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank(``);
+  let {page, session, dp} = await testRunner.startBlank(`Tests line and column numbers in reported console messages.`);
 
   dp.Runtime.enable();
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-timestamp-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-timestamp-expected.txt
index 6eedb95..a909c043 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-timestamp-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-timestamp-expected.txt
@@ -1,4 +1,4 @@
-
+Tests timestamp field in reported console messages.
 Message has timestamp: true
 Message timestamp doesn't differ too much from current time (one minute interval): true
 Message 1 has non-decreasing timestamp: true
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-timestamp.js b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-timestamp.js
index 8c523c39..014cd9f 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-timestamp.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-timestamp.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank(``);
+  let {page, session, dp} = await testRunner.startBlank(`Tests timestamp field in reported console messages.`);
 
   var messages = [];
   dp.Runtime.onConsoleAPICalled(data => {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-execution-contexts-events-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-execution-contexts-events-expected.txt
index e5721cd..148f6faf 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-execution-contexts-events-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-execution-contexts-events-expected.txt
@@ -1,4 +1,4 @@
-
+Tests execution context lifetime events.
 Page context was created
 Create new frame
 Frame context was created
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-execution-contexts-events.js b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-execution-contexts-events.js
index 7ba4496cc..36ad61f7 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-execution-contexts-events.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-execution-contexts-events.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank(``);
+  let {page, session, dp} = await testRunner.startBlank(`Tests execution context lifetime events.`);
 
   dp.Runtime.enable();
   await dp.Runtime.onceExecutionContextCreated();
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties-expected.txt
index 64279ca..3748dd6 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties-expected.txt
@@ -1,4 +1,4 @@
-
+Test Runtime.getProperties with different flag combinations.
 Properties of Object(5)
   __proto__ own object undefined
   foo own string cat
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties-preview-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties-preview-expected.txt
index cdbe4aa..f0970e0b9 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties-preview-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties-preview-expected.txt
@@ -1,4 +1,4 @@
-
+Tests preview provided by Runtime.getProperties.
 p1 : Object
 p2 : Object
 p1 : {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties-preview.js b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties-preview.js
index 9707bb4b..c6c1d2fd 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties-preview.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties-preview.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank(``);
+  let {page, session, dp} = await testRunner.startBlank(`Tests preview provided by Runtime.getProperties.`);
 
   function printResult(response) {
     for (var property of response.result.result) {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties.js b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties.js
index bde1a362..59663b8e 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-getProperties.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank(``);
+  let {page, session, dp} = await testRunner.startBlank(`Test Runtime.getProperties with different flag combinations.`);
 
   // A helper function that dumps object properties and internal properties in sorted order.
   function logGetPropertiesResult(title, protocolResult) {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/fetch-as-stream-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/fetch-as-stream-expected.txt
index 2bae8ca..e48555d 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/fetch-as-stream-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/fetch-as-stream-expected.txt
@@ -1,4 +1,4 @@
-
+Tests fetching trace through IO domain stream.
 Recording started
 Tracing complete
 Error after legit close: undefined
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/fetch-as-stream.js b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/fetch-as-stream.js
index ea02efa9..cdb421d 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/fetch-as-stream.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/fetch-as-stream.js
@@ -10,7 +10,7 @@
     </style>
     <div id='test'>
     </div>
-  `, '');
+  `, 'Tests fetching trace through IO domain stream.');
 
   var TracingHelper = await testRunner.loadScript('../resources/tracing-test.js');
   var tracingHelper = new TracingHelper(testRunner, session);
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/page-frames-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/page-frames-expected.txt
index aac0ec27..26ab8ac 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/page-frames-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/page-frames-expected.txt
@@ -1,4 +1,4 @@
-
+Tests certain trace events in iframes.
 Recording started
 Tracing complete
 Frames in TracingStartedInPage
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/page-frames.js b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/page-frames.js
index c3801fc..1deedd9d 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/page-frames.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/page-frames.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   let {page, session, dp} = await testRunner.startHTML(`
     <iframe src='data:text/html,<script>window.foo = 42</script>' name='frame0'></iframe>
-  `, '');
+  `, 'Tests certain trace events in iframes.');
 
   function performActions() {
     var frame1 = document.createElement('iframe');
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-dispatchEvent-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-dispatchEvent-expected.txt
index 9491d6a..25c203b9 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-dispatchEvent-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-dispatchEvent-expected.txt
@@ -1,4 +1,4 @@
-
+Tests trace events for event dispatching.
 Recording started
 Tracing complete
 SUCCESS: found click event
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-dispatchEvent.js b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-dispatchEvent.js
index bf55a78..6fe9e024 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-dispatchEvent.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-dispatchEvent.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   let {page, session, dp} = await testRunner.startHTML(`
     <div id='my-div'></div>
-  `, '');
+  `, 'Tests trace events for event dispatching.');
 
   function performAction() {
     var div = document.querySelector('#my-div');
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-layout-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-layout-expected.txt
index 17a2c83..236cdad 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-layout-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-layout-expected.txt
@@ -1,4 +1,4 @@
-
+Tests trace events for layout.
 Recording started
 Tracing complete
 UpdateLayoutTree frames match: true
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-layout.js b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-layout.js
index e22295cb..7bda756 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-layout.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-layout.js
@@ -7,7 +7,7 @@
     }
     </style>
     <div id='myDiv'>DIV</div>
-  `, '');
+  `, 'Tests trace events for layout.');
 
   function performActions() {
     var div = document.querySelector('#myDiv');
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-raf-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-raf-expected.txt
index a23325c..2a7d6de 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-raf-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-raf-expected.txt
@@ -1,4 +1,4 @@
-
+Tests trace events for rafs.
 Recording started
 Tracing complete
 RequestAnimationFrame has frame: true
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-raf.js b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-raf.js
index 6cb273f6..82e5469 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-raf.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-raf.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   let {page, session, dp} = await testRunner.startHTML(`
     <div id='myDiv'>DIV</div>
-  `, '');
+  `, 'Tests trace events for rafs.');
 
   function performActions() {
     var callback;
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-timer-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-timer-expected.txt
index aaf1656..5fec2ed 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-timer-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-timer-expected.txt
@@ -1,4 +1,4 @@
-
+Tests trace events for timer firing.
 Recording started
 Tracing complete
 TimerInstall has frame: true
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-timer.js b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-timer.js
index 84e086fe7..c63eb17 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-timer.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/timeline/timeline-timer.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   let {page, session, dp} = await testRunner.startHTML(`
     <div id='myDiv'>DIV</div>
-  `, '');
+  `, 'Tests trace events for timer firing.');
 
   function performActions() {
     var callback;
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/worker/worker-console-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/worker/worker-console-expected.txt
index 759dc25..43aab3c2 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/worker/worker-console-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/worker/worker-console-expected.txt
@@ -1,4 +1,4 @@
-
+Tests how console messages from worker get into page's console once worker is destroyed.
 Starting worker
 Logging in worker: message0
 Got log message from page: message0
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/worker/worker-console.js b/third_party/WebKit/LayoutTests/inspector-protocol/worker/worker-console.js
index a294421..e65ba26 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/worker/worker-console.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/worker/worker-console.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank('');
+  let {page, session, dp} = await testRunner.startBlank(`Tests how console messages from worker get into page's console once worker is destroyed.`);
 
   await session.evaluate(`
     var worker = null;
diff --git a/third_party/WebKit/LayoutTests/platform/linux/inspector-protocol/input/dispatchMouseEvent-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/inspector-protocol/input/dispatchMouseEvent-expected.txt
index 6d3b378..912f9b6c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/inspector-protocol/input/dispatchMouseEvent-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/inspector-protocol/input/dispatchMouseEvent-expected.txt
@@ -1,4 +1,4 @@
-
+Tests Input.dispatchMouseEvent method.
 -----Event-----
 type: mousedown
 button: 0
diff --git a/third_party/WebKit/LayoutTests/platform/win/inspector-protocol/input/dispatchMouseEvent-expected.txt b/third_party/WebKit/LayoutTests/platform/win/inspector-protocol/input/dispatchMouseEvent-expected.txt
index 210832f..91036d1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/inspector-protocol/input/dispatchMouseEvent-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/inspector-protocol/input/dispatchMouseEvent-expected.txt
@@ -1,4 +1,4 @@
-
+Tests Input.dispatchMouseEvent method.
 -----Event-----
 type: mousedown
 button: 0
diff --git a/third_party/WebKit/Source/build/scripts/templates/CSSValueIDMappingsGenerated.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/CSSValueIDMappingsGenerated.h.tmpl
index db77907..4310055 100644
--- a/third_party/WebKit/Source/build/scripts/templates/CSSValueIDMappingsGenerated.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/CSSValueIDMappingsGenerated.h.tmpl
@@ -65,25 +65,36 @@
   {% endif %}
   {% endfor %}
     default:
-      DCHECK(v >= {{mapping.start_segment[2]}} && v <= {{mapping.end_segment[2]}}) ;
+      DCHECK_GE(v, {{mapping.start_segment[2]}});
+      DCHECK_LE(v, {{mapping.end_segment[2]}});
       return static_cast<{{enum_name}}>(v - {{mapping.start_segment[2]}} + static_cast<int>({{enum_name}}::{{mapping.start_segment[0]}}));
   }
   {% else %}
-  DCHECK(v >= {{mapping.start_segment[2]}} && v <= {{mapping.end_segment[2]}}) ;
+  DCHECK_GE(v, {{mapping.start_segment[2]}});
+  DCHECK_LE(v, {{mapping.end_segment[2]}});
   return static_cast<{{enum_name}}>(v - {{mapping.start_segment[2]}} + static_cast<int>({{enum_name}}::{{mapping.start_segment[0]}}));
   {% endif %}
 }
 
 inline CSSValueID platformEnumToCSSValueIDGenerated({{enum_name}} v) {
+  {% if mapping['mapping'] | length > mapping.longest_segment_length %}
   switch (v) {
   {% for cs_value, cs_num, css_value, css_num in mapping['mapping']: %}
+  {% if cs_num < mapping.start_segment[1] or cs_num > mapping.end_segment[1] %}
     case {{enum_name}}::{{cs_value}}:
       return {{css_value}};
+  {% endif %}
   {% endfor %}
     default:
-      NOTREACHED();
-      return CSSValueNone;
+      DCHECK_GE(v, {{enum_name}}::{{mapping.start_segment[0]}});
+      DCHECK_LE(v, {{enum_name}}::{{mapping.end_segment[0]}});
+      return static_cast<CSSValueID>(static_cast<int>(v) - static_cast<int>({{enum_name}}::{{mapping.start_segment[0]}}) + static_cast<int>({{mapping.start_segment[2]}}));
   }
+  {% else %}
+  DCHECK_GE(v, {{enum_name}}::{{mapping.start_segment[0]}});
+  DCHECK_LE(v, {{enum_name}}::{{mapping.end_segment[0]}});
+  return static_cast<CSSValueID>(static_cast<int>(v) - static_cast<int>({{enum_name}}::{{mapping.start_segment[0]}}) + static_cast<int>({{mapping.start_segment[2]}}));
+  {% endif %}
 }
 
 {% endif %}
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 92d9102a..6e5f7fa 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -200,6 +200,7 @@
     "//third_party/WebKit/Source/core/paint",
     "//third_party/WebKit/Source/core/plugins",
     "//third_party/WebKit/Source/core/probe",
+    "//third_party/WebKit/Source/core/resize_observer",
     "//third_party/WebKit/Source/core/streams",
     "//third_party/WebKit/Source/core/style:rendering",
     "//third_party/WebKit/Source/core/style:svg_style",
@@ -596,16 +597,23 @@
     "$blink_core_output_dir/css/properties/CSSPropertyDescriptor.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIAnimation.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBackgroundPosition.h",
+    "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderBottom.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderColor.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderImage.h",
+    "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderLeft.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderRadius.h",
+    "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderRight.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderSpacing.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderStyle.h",
+    "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderTop.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderWidth.h",
+    "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIColumnRule.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIColumns.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIFlex.h",
+    "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIFlexFlow.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIFont.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIFontVariant.h",
+    "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIListStyle.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIMargin.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIOutline.h",
     "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIOverflow.h",
@@ -1269,7 +1277,6 @@
     "dom/NodeTest.cpp",
     "dom/NthIndexCacheTest.cpp",
     "dom/RangeTest.cpp",
-    "dom/ResizeObserverTest.cpp",
     "dom/ScriptModuleResolverImplTest.cpp",
     "dom/ScriptRunnerTest.cpp",
     "dom/ScriptedAnimationControllerTest.cpp",
@@ -1529,6 +1536,7 @@
     "paint/TextPainterTest.cpp",
     "paint/TextSelectionRepaintTest.cpp",
     "paint/VideoPainterTest.cpp",
+    "resize_observer/ResizeObserverTest.cpp",
     "scheduler/ActiveConnectionThrottlingTest.cpp",
     "scheduler/FrameThrottlingTest.cpp",
     "scheduler/ThrottlingTest.cpp",
diff --git a/third_party/WebKit/Source/core/core_idl_files.gni b/third_party/WebKit/Source/core/core_idl_files.gni
index f0b1a5f..43a1b81f 100644
--- a/third_party/WebKit/Source/core/core_idl_files.gni
+++ b/third_party/WebKit/Source/core/core_idl_files.gni
@@ -115,8 +115,6 @@
                     "dom/NodeList.idl",
                     "dom/ProcessingInstruction.idl",
                     "dom/Range.idl",
-                    "dom/ResizeObserver.idl",
-                    "dom/ResizeObserverEntry.idl",
                     "dom/ShadowRoot.idl",
                     "dom/StaticRange.idl",
                     "dom/Text.idl",
@@ -277,6 +275,8 @@
                     "page/PagePopupController.idl",
                     "page/scrolling/ScrollState.idl",
                     "page/scrolling/ScrollStateCallback.idl",
+                    "resize_observer/ResizeObserver.idl",
+                    "resize_observer/ResizeObserverEntry.idl",
                     "streams/UnderlyingSourceBase.idl",
                     "svg/SVGAElement.idl",
                     "svg/SVGAngle.idl",
diff --git a/third_party/WebKit/Source/core/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn
index b6c4755..1a2a7002 100644
--- a/third_party/WebKit/Source/core/css/BUILD.gn
+++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -544,16 +544,23 @@
     "properties/CSSPropertyWebkitBorderWidthUtils.h",
     "properties/CSSShorthandPropertyAPIAnimation.cpp",
     "properties/CSSShorthandPropertyAPIBackgroundPosition.cpp",
+    "properties/CSSShorthandPropertyAPIBorderBottom.cpp",
     "properties/CSSShorthandPropertyAPIBorderColor.cpp",
     "properties/CSSShorthandPropertyAPIBorderImage.cpp",
+    "properties/CSSShorthandPropertyAPIBorderLeft.cpp",
     "properties/CSSShorthandPropertyAPIBorderRadius.cpp",
+    "properties/CSSShorthandPropertyAPIBorderRight.cpp",
     "properties/CSSShorthandPropertyAPIBorderSpacing.cpp",
     "properties/CSSShorthandPropertyAPIBorderStyle.cpp",
+    "properties/CSSShorthandPropertyAPIBorderTop.cpp",
     "properties/CSSShorthandPropertyAPIBorderWidth.cpp",
+    "properties/CSSShorthandPropertyAPIColumnRule.cpp",
     "properties/CSSShorthandPropertyAPIColumns.cpp",
     "properties/CSSShorthandPropertyAPIFlex.cpp",
+    "properties/CSSShorthandPropertyAPIFlexFlow.cpp",
     "properties/CSSShorthandPropertyAPIFont.cpp",
     "properties/CSSShorthandPropertyAPIFontVariant.cpp",
+    "properties/CSSShorthandPropertyAPIListStyle.cpp",
     "properties/CSSShorthandPropertyAPIMargin.cpp",
     "properties/CSSShorthandPropertyAPIOffset.cpp",
     "properties/CSSShorthandPropertyAPIOutline.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index 8ca3dd5d..3e366778 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -2532,12 +2532,6 @@
       field_group: "rare-inherited",
     },
     {
-      name: "text-decoration",
-      api_class: true,
-      longhands: ["text-decoration-line", "text-decoration-style", "text-decoration-color"],
-      use_handlers_for: "CSSPropertyTextDecorationLine",
-    },
-    {
       name: "text-decoration-color",
       api_class: true,
       api_methods: ["parseSingleValue"],
@@ -3705,6 +3699,8 @@
     {
       name: "border-bottom",
       longhands: ["border-bottom-width", "border-bottom-style", "border-bottom-color"],
+      api_class: true,
+      api_methods: ["parseShorthand"],
     },
     {
       name: "border-color",
@@ -3721,6 +3717,8 @@
     {
       name: "border-left",
       longhands: ["border-left-width", "border-left-style", "border-left-color"],
+      api_class: true,
+      api_methods: ["parseShorthand"],
     },
     {
       name: "border-radius",
@@ -3731,6 +3729,8 @@
     {
       name: "border-right",
       longhands: ["border-right-width", "border-right-style", "border-right-color"],
+      api_class: true,
+      api_methods: ["parseShorthand"],
     },
     {
       name: "border-spacing",
@@ -3749,6 +3749,8 @@
     {
       name: "border-top",
       longhands: ["border-top-width", "border-top-style", "border-top-color"],
+      api_class: true,
+      api_methods: ["parseShorthand"],
     },
     {
       name: "border-width",
@@ -3765,6 +3767,8 @@
     {
       name: "flex-flow",
       longhands: ["flex-direction", "flex-wrap"],
+      api_class: true,
+      api_methods: ["parseShorthand"],
     },
     {
       name: "font",
@@ -3827,6 +3831,8 @@
     {
       name: "list-style",
       longhands: ["list-style-type", "list-style-position", "list-style-image"],
+      api_class: true,
+      api_methods: ["parseShorthand"],
     },
     {
       name: "margin",
@@ -3922,6 +3928,13 @@
       runtime_flag: "CSSScrollSnapPoints",
     },
     {
+      name: "text-decoration",
+      longhands: ["text-decoration-line", "text-decoration-style", "text-decoration-color"],
+      api_class: true,
+      api_methods: ["parseShorthand"],
+      use_handlers_for: "CSSPropertyTextDecorationLine",
+    },
+    {
       name: "transition",
       longhands: ["transition-property", "transition-duration", "transition-timing-function", "transition-delay"],
       api_class: true,
@@ -3966,6 +3979,8 @@
     {
       name: "column-rule",
       longhands: ["column-rule-width", "column-rule-style", "column-rule-color"],
+      api_class: true,
+      api_methods: ["parseShorthand"],
     },
     {
       name: "columns",
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index f214cfa..e70d68f 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -1344,39 +1344,6 @@
   }
 }
 
-bool CSSPropertyParser::ConsumeShorthandGreedily(
-    const StylePropertyShorthand& shorthand,
-    bool important) {
-  // Existing shorthands have at most 6 longhands.
-  DCHECK_LE(shorthand.length(), 6u);
-  const CSSValue* longhands[6] = {nullptr, nullptr, nullptr,
-                                  nullptr, nullptr, nullptr};
-  const CSSPropertyID* shorthand_properties = shorthand.properties();
-  do {
-    bool found_longhand = false;
-    for (size_t i = 0; !found_longhand && i < shorthand.length(); ++i) {
-      if (longhands[i])
-        continue;
-      longhands[i] = ParseSingleValue(shorthand_properties[i], shorthand.id());
-      if (longhands[i])
-        found_longhand = true;
-    }
-    if (!found_longhand)
-      return false;
-  } while (!range_.AtEnd());
-
-  for (size_t i = 0; i < shorthand.length(); ++i) {
-    if (longhands[i]) {
-      AddParsedProperty(shorthand_properties[i], shorthand.id(), *longhands[i],
-                        important);
-    } else {
-      AddParsedProperty(shorthand_properties[i], shorthand.id(),
-                        *CSSInitialValue::Create(), important);
-    }
-  }
-  return true;
-}
-
 bool CSSPropertyParser::ConsumeBorder(bool important) {
   CSSValue* width = nullptr;
   const CSSValue* style = nullptr;
@@ -2067,9 +2034,6 @@
   }
 
   switch (property) {
-    case CSSPropertyTextDecoration:
-      DCHECK(RuntimeEnabledFeatures::CSS3TextDecorationsEnabled());
-      return ConsumeShorthandGreedily(textDecorationShorthand(), important);
     case CSSPropertyMarker: {
       const CSSValue* marker = ParseSingleValue(CSSPropertyMarkerStart);
       if (!marker || !range_.AtEnd())
@@ -2082,20 +2046,6 @@
                         important);
       return true;
     }
-    case CSSPropertyFlexFlow:
-      return ConsumeShorthandGreedily(flexFlowShorthand(), important);
-    case CSSPropertyColumnRule:
-      return ConsumeShorthandGreedily(columnRuleShorthand(), important);
-    case CSSPropertyListStyle:
-      return ConsumeShorthandGreedily(listStyleShorthand(), important);
-    case CSSPropertyBorderTop:
-      return ConsumeShorthandGreedily(borderTopShorthand(), important);
-    case CSSPropertyBorderRight:
-      return ConsumeShorthandGreedily(borderRightShorthand(), important);
-    case CSSPropertyBorderBottom:
-      return ConsumeShorthandGreedily(borderBottomShorthand(), important);
-    case CSSPropertyBorderLeft:
-      return ConsumeShorthandGreedily(borderLeftShorthand(), important);
     case CSSPropertyBorder:
       return ConsumeBorder(important);
     case CSSPropertyPageBreakAfter:
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
index 6f3ef0a..51c5700 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -84,7 +84,6 @@
   bool ConsumeBorder(bool important);
 
   bool ParseShorthand(CSSPropertyID, bool important);
-  bool ConsumeShorthandGreedily(const StylePropertyShorthand&, bool important);
   bool Consume2Values(const StylePropertyShorthand&, bool important);
 
   bool ConsumeBackgroundShorthand(const StylePropertyShorthand&,
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.h
index 040ccc2b..69dcd0d 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.h
@@ -131,19 +131,18 @@
                                     CSSParserTokenRange&,
                                     bool& needs_legacy_parsing);
 
-// ConsumeShorthandVia2LonghandAPIs and ConsumeShorthandGreedilyViaLonghandAPIs
-// are based on CSSPropertyParsers' Consume2Values and ConsumeShorthandGreedily.
-// They all delegate parsing of a shorthand property to its respective longhand
+// ConsumeShorthandVia2LonghandAPIs is based on CSSPropertyParsers'
+// Consume2Values.
+// They both delegate parsing of a shorthand property to its respective longhand
 // components. The difference is the functions in this Helpers file expect
 // component longhands to have API implementations already because each
 // shorthand will call its component longhand APIs' parseShorthand method.
-// Consume2Values and ConsumeShorthandGreedily will be removed soon, when
-// shorthand properties are ribbonised (i.e. have their own APIs). Until then,
-// there is a slight code duplication between the two versions for the following
-// reasons:
+// Consume2Values will be removed soon, when shorthand properties are ribbonised
+// (i.e. have their own APIs). Until then, there is a slight code duplication
+// between the two versions for the following reasons:
 // 1. An alternative to code duplicate is to have the old Consume*
-//    (e.g. ConsumeShorthandGreedily) call the new Consume*
-//    (e.g. ConsumeShorthandGreedilyViaLonghandAPIs). However, the
+//    (e.g. Consume2Values) call the new Consume*
+//    (e.g. ConsumeShorthandVia2LonghandAPIs). However, the
 //    new Consume* expects ALL component longhands to have APIs and will parse
 ///   all longhands via their APIs. In order to parse shorthands, where some
 //    component longhands do not have APIs, the new Consume* will need to return
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderBottom.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderBottom.cpp
new file mode 100644
index 0000000..f0df4aa9
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderBottom.cpp
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSShorthandPropertyAPIBorderBottom.h"
+#include "core/StylePropertyShorthand.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+
+namespace blink {
+
+bool CSSShorthandPropertyAPIBorderBottom::parseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    bool,
+    HeapVector<CSSProperty, 256>& properties) {
+  return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
+      borderBottomShorthand(), important, context, range, properties);
+}
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderLeft.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderLeft.cpp
new file mode 100644
index 0000000..0c8ed47
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderLeft.cpp
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSShorthandPropertyAPIBorderLeft.h"
+#include "core/StylePropertyShorthand.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+
+namespace blink {
+
+bool CSSShorthandPropertyAPIBorderLeft::parseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    bool,
+    HeapVector<CSSProperty, 256>& properties) {
+  return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
+      borderLeftShorthand(), important, context, range, properties);
+}
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderRight.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderRight.cpp
new file mode 100644
index 0000000..902af09
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderRight.cpp
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSShorthandPropertyAPIBorderRight.h"
+#include "core/StylePropertyShorthand.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+
+namespace blink {
+
+bool CSSShorthandPropertyAPIBorderRight::parseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    bool,
+    HeapVector<CSSProperty, 256>& properties) {
+  return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
+      borderRightShorthand(), important, context, range, properties);
+}
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderTop.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderTop.cpp
new file mode 100644
index 0000000..1609aa86
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderTop.cpp
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSShorthandPropertyAPIBorderTop.h"
+#include "core/StylePropertyShorthand.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+
+namespace blink {
+
+bool CSSShorthandPropertyAPIBorderTop::parseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    bool,
+    HeapVector<CSSProperty, 256>& properties) {
+  return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
+      borderTopShorthand(), important, context, range, properties);
+}
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIColumnRule.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIColumnRule.cpp
new file mode 100644
index 0000000..0ab2f7a
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIColumnRule.cpp
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSShorthandPropertyAPIColumnRule.h"
+#include "core/StylePropertyShorthand.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+
+namespace blink {
+
+bool CSSShorthandPropertyAPIColumnRule::parseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    bool,
+    HeapVector<CSSProperty, 256>& properties) {
+  return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
+      columnRuleShorthand(), important, context, range, properties);
+}
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFlexFlow.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFlexFlow.cpp
new file mode 100644
index 0000000..dac11bf
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIFlexFlow.cpp
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSShorthandPropertyAPIFlexFlow.h"
+#include "core/StylePropertyShorthand.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+
+namespace blink {
+
+bool CSSShorthandPropertyAPIFlexFlow::parseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    bool,
+    HeapVector<CSSProperty, 256>& properties) {
+  return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
+      flexFlowShorthand(), important, context, range, properties);
+}
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIListStyle.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIListStyle.cpp
new file mode 100644
index 0000000..e7ca662
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIListStyle.cpp
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSShorthandPropertyAPIListStyle.h"
+#include "core/StylePropertyShorthand.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+
+namespace blink {
+
+bool CSSShorthandPropertyAPIListStyle::parseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    bool,
+    HeapVector<CSSProperty, 256>& properties) {
+  return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
+      listStyleShorthand(), important, context, range, properties);
+}
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPITextDecoration.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPITextDecoration.cpp
index 1e19ea7..bd0a529 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPITextDecoration.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPITextDecoration.cpp
@@ -3,5 +3,20 @@
 // found in the LICENSE file.
 
 #include "core/css/properties/CSSShorthandPropertyAPITextDecoration.h"
+#include "core/StylePropertyShorthand.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "platform/RuntimeEnabledFeatures.h"
 
-namespace blink {}  // namespace blink
+namespace blink {
+
+bool CSSShorthandPropertyAPITextDecoration::parseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    bool,
+    HeapVector<CSSProperty, 256>& properties) {
+  DCHECK(RuntimeEnabledFeatures::CSS3TextDecorationsEnabled());
+  return CSSPropertyParserHelpers::ConsumeShorthandGreedilyViaLonghandAPIs(
+      textDecorationShorthand(), important, context, range, properties);
+}
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/BUILD.gn b/third_party/WebKit/Source/core/dom/BUILD.gn
index 1a93ebf..b68f5073 100644
--- a/third_party/WebKit/Source/core/dom/BUILD.gn
+++ b/third_party/WebKit/Source/core/dom/BUILD.gn
@@ -227,14 +227,6 @@
     "RawDataDocumentParser.h",
     "RemoteSecurityContext.cpp",
     "RemoteSecurityContext.h",
-    "ResizeObservation.cpp",
-    "ResizeObservation.h",
-    "ResizeObserver.cpp",
-    "ResizeObserver.h",
-    "ResizeObserverController.cpp",
-    "ResizeObserverController.h",
-    "ResizeObserverEntry.cpp",
-    "ResizeObserverEntry.h",
     "SandboxFlags.cpp",
     "SandboxFlags.h",
     "ScopedWindowFocusAllowedIndicator.h",
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index b128210c..79e6b56 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -93,7 +93,6 @@
 #include "core/dom/NodeWithIndex.h"
 #include "core/dom/NthIndexCache.h"
 #include "core/dom/ProcessingInstruction.h"
-#include "core/dom/ResizeObserverController.h"
 #include "core/dom/ScriptRunner.h"
 #include "core/dom/ScriptedAnimationController.h"
 #include "core/dom/ScriptedIdleTaskController.h"
@@ -208,6 +207,7 @@
 #include "core/page/scrolling/SnapCoordinator.h"
 #include "core/page/scrolling/TopDocumentRootScrollerController.h"
 #include "core/probe/CoreProbes.h"
+#include "core/resize_observer/ResizeObserverController.h"
 #include "core/svg/SVGDocumentExtensions.h"
 #include "core/svg/SVGScriptElement.h"
 #include "core/svg/SVGTitleElement.h"
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index 6b4d879..c6ec05f1 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -67,7 +67,6 @@
 #include "core/dom/NodeComputedStyle.h"
 #include "core/dom/PresentationAttributeStyle.h"
 #include "core/dom/PseudoElement.h"
-#include "core/dom/ResizeObservation.h"
 #include "core/dom/ScriptableDocumentParser.h"
 #include "core/dom/SelectorQuery.h"
 #include "core/dom/ShadowRoot.h"
@@ -132,6 +131,7 @@
 #include "core/page/scrolling/TopDocumentRootScrollerController.h"
 #include "core/paint/PaintLayer.h"
 #include "core/probe/CoreProbes.h"
+#include "core/resize_observer/ResizeObservation.h"
 #include "core/svg/SVGAElement.h"
 #include "core/svg/SVGElement.h"
 #include "core/svg/SVGTreeScopeResources.h"
diff --git a/third_party/WebKit/Source/core/dom/ElementRareData.cpp b/third_party/WebKit/Source/core/dom/ElementRareData.cpp
index f67ca38..feffb99 100644
--- a/third_party/WebKit/Source/core/dom/ElementRareData.cpp
+++ b/third_party/WebKit/Source/core/dom/ElementRareData.cpp
@@ -31,8 +31,8 @@
 #include "core/dom/ElementRareData.h"
 
 #include "core/css/cssom/InlineStylePropertyMap.h"
-#include "core/dom/ResizeObservation.h"
-#include "core/dom/ResizeObserver.h"
+#include "core/resize_observer/ResizeObservation.h"
+#include "core/resize_observer/ResizeObserver.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelection.cpp b/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
index 3d291db..4ee9cb8 100644
--- a/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
@@ -608,6 +608,40 @@
   return end;
 }
 
+// The selection starts in editable content or non-editable content inside a
+// different editable ancestor, move forward until non-editable content inside
+// the same lowest editable ancestor is reached.
+template <typename Strategy>
+PositionTemplate<Strategy> AdjustSelectionStartToAvoidCrossingEditingBoundaries(
+    const PositionTemplate<Strategy>& start,
+    ContainerNode* start_root,
+    Element* base_editable_ancestor) {
+  Element* const start_editable_ancestor =
+      LowestEditableAncestor(start.ComputeContainerNode());
+  if (start_root || start_editable_ancestor != base_editable_ancestor) {
+    PositionTemplate<Strategy> position = NextVisuallyDistinctCandidate(start);
+    Element* shadow_ancestor =
+        start_root ? start_root->OwnerShadowHost() : nullptr;
+    if (position.IsNull() && shadow_ancestor)
+      position = PositionTemplate<Strategy>::BeforeNode(*shadow_ancestor);
+    while (position.IsNotNull() &&
+           !(LowestEditableAncestor(position.ComputeContainerNode()) ==
+                 base_editable_ancestor &&
+             !IsEditablePosition(position))) {
+      Element* root = RootEditableElementOf(position);
+      shadow_ancestor = root ? root->OwnerShadowHost() : nullptr;
+      position = IsAtomicNode(position.ComputeContainerNode())
+                     ? PositionTemplate<Strategy>::InParentAfterNode(
+                           *position.ComputeContainerNode())
+                     : NextVisuallyDistinctCandidate(position);
+      if (position.IsNull() && shadow_ancestor)
+        position = PositionTemplate<Strategy>::BeforeNode(*shadow_ancestor);
+    }
+    return CreateVisiblePosition(position).DeepEquivalent();
+  }
+  return start;
+}
+
 template <typename Strategy>
 void VisibleSelectionTemplate<
     Strategy>::AdjustSelectionToAvoidCrossingEditingBoundaries() {
@@ -667,40 +701,14 @@
       return;
     }
 
-    // The selection starts in editable content or non-editable content inside a
-    // different editable ancestor, move forward until non-editable content
-    // inside the same lowest editable ancestor is reached.
-    Element* start_editable_ancestor =
-        LowestEditableAncestor(start_.ComputeContainerNode());
-    if (start_root || start_editable_ancestor != base_editable_ancestor) {
-      PositionTemplate<Strategy> p = NextVisuallyDistinctCandidate(start_);
-      Element* shadow_ancestor =
-          start_root ? start_root->OwnerShadowHost() : nullptr;
-      if (p.IsNull() && shadow_ancestor)
-        p = PositionTemplate<Strategy>::BeforeNode(*shadow_ancestor);
-      while (p.IsNotNull() &&
-             !(LowestEditableAncestor(p.ComputeContainerNode()) ==
-                   base_editable_ancestor &&
-               !IsEditablePosition(p))) {
-        Element* root = RootEditableElementOf(p);
-        shadow_ancestor = root ? root->OwnerShadowHost() : nullptr;
-        p = IsAtomicNode(p.ComputeContainerNode())
-                ? PositionTemplate<Strategy>::InParentAfterNode(
-                      *p.ComputeContainerNode())
-                : NextVisuallyDistinctCandidate(p);
-        if (p.IsNull() && shadow_ancestor)
-          p = PositionTemplate<Strategy>::BeforeNode(*shadow_ancestor);
-      }
-      const VisiblePositionTemplate<Strategy> next = CreateVisiblePosition(p);
-
-      if (next.IsNull()) {
-        // The selection crosses an Editing boundary.  This is a
-        // programmer error in the editing code.  Happy debugging!
-        NOTREACHED();
-        *this = VisibleSelectionTemplate<Strategy>();
-        return;
-      }
-      start_ = next.DeepEquivalent();
+    start_ = AdjustSelectionStartToAvoidCrossingEditingBoundaries(
+        start_, start_root, base_editable_ancestor);
+    if (start_.IsNull()) {
+      // The selection crosses an Editing boundary.  This is a
+      // programmer error in the editing code.  Happy debugging!
+      NOTREACHED();
+      *this = VisibleSelectionTemplate<Strategy>();
+      return;
     }
   }
 }
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
index 58efa09..b62bc7f 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
@@ -37,7 +37,6 @@
 #include "core/editing/Position.h"
 #include "core/editing/VisiblePosition.h"
 #include "core/editing/VisibleUnits.h"
-#include "core/editing/iterators/TextIteratorTextNodeHandler.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/UseCounter.h"
 #include "core/html/HTMLElement.h"
@@ -191,9 +190,7 @@
       shadow_depth_(
           ShadowDepthOf<Strategy>(*start_container_, *end_container_)),
       behavior_(AdjustBehaviorFlags<Strategy>(behavior)),
-      text_state_(new TextIteratorTextState()),
-      text_node_handler_(
-          new TextIteratorTextNodeHandler(behavior_, text_state_)) {
+      text_node_handler_(behavior_, &text_state_) {
   DCHECK(start_container_);
   DCHECK(end_container_);
 
@@ -259,12 +256,12 @@
 
   if (needs_handle_replaced_element_) {
     HandleReplacedElement();
-    if (text_state_->PositionNode())
+    if (text_state_.PositionNode())
       return true;
   }
 
   // Try to emit more text runs if we are handling a text node.
-  return text_node_handler_->HandleRemainingTextRuns();
+  return text_node_handler_.HandleRemainingTextRuns();
 }
 
 template <typename Strategy>
@@ -275,7 +272,7 @@
   if (node_)
     DCHECK(!node_->GetDocument().NeedsLayoutTreeUpdate()) << node_;
 
-  text_state_->ResetRunInformation();
+  text_state_.ResetRunInformation();
 
   if (HandleRememberedProgress())
     return;
@@ -362,7 +359,7 @@
           HandleNonTextNode();
         }
         iteration_progress_ = kHandledNode;
-        if (text_state_->PositionNode())
+        if (text_state_.PositionNode())
           return;
       }
     }
@@ -395,7 +392,7 @@
           parent_node = Strategy::Parent(*node_);
           if (have_layout_object)
             ExitNode();
-          if (text_state_->PositionNode()) {
+          if (text_state_.PositionNode()) {
             iteration_progress_ = kHandledChildren;
             return;
           }
@@ -456,7 +453,7 @@
     iteration_progress_ = kHandledNone;
 
     // how would this ever be?
-    if (text_state_->PositionNode())
+    if (text_state_.PositionNode())
       return;
   }
 }
@@ -480,16 +477,16 @@
   // an offset range with unbounded endpoint(s) in an easy but still clear way.
   if (node_ != start_container_) {
     if (node_ != end_container_)
-      text_node_handler_->HandleTextNodeWhole(text);
+      text_node_handler_.HandleTextNodeWhole(text);
     else
-      text_node_handler_->HandleTextNodeEndAt(text, end_offset_);
+      text_node_handler_.HandleTextNodeEndAt(text, end_offset_);
     return;
   }
   if (node_ != end_container_) {
-    text_node_handler_->HandleTextNodeStartFrom(text, start_offset_);
+    text_node_handler_.HandleTextNodeStartFrom(text, start_offset_);
     return;
   }
-  text_node_handler_->HandleTextNodeInRange(text, start_offset_, end_offset_);
+  text_node_handler_.HandleTextNodeInRange(text, start_offset_, end_offset_);
 }
 
 template <typename Strategy>
@@ -526,9 +523,9 @@
     return;
   }
 
-  DCHECK_EQ(last_text_node_, text_node_handler_->GetNode());
+  DCHECK_EQ(last_text_node_, text_node_handler_.GetNode());
   if (last_text_node_) {
-    if (text_node_handler_->FixLeadingWhiteSpaceForReplacedElement(
+    if (text_node_handler_.FixLeadingWhiteSpaceForReplacedElement(
             Strategy::Parent(*last_text_node_))) {
       needs_handle_replaced_element_ = true;
       return;
@@ -548,11 +545,11 @@
     return;
   }
 
-  text_state_->UpdateForReplacedElement(node_);
+  text_state_.UpdateForReplacedElement(node_);
 
   if (EmitsImageAltText() && TextIterator::SupportsAltText(node_)) {
-    text_state_->EmitAltText(node_);
-    if (text_state_->length())
+    text_state_.EmitAltText(node_);
+    if (text_state_.length())
       return;
   }
 }
@@ -680,11 +677,11 @@
 
   // Leave element positioned flush with start of a paragraph
   // (e.g. do not insert tab before a table cell at the start of a paragraph)
-  if (text_state_->LastCharacter() == '\n')
+  if (text_state_.LastCharacter() == '\n')
     return false;
 
   // Otherwise, show the position if we have emitted any characters
-  if (text_state_->HasEmitted())
+  if (text_state_.HasEmitted())
     return true;
 
   // We've not emitted anything yet. Generally, there is no need for any
@@ -789,7 +786,7 @@
   // FIXME: !m_hasEmitted does not necessarily mean there was a collapsed
   // block... it could have been an hr (e.g.). Also, a collapsed block could
   // have height (e.g. a table) and therefore look like a blank line.
-  if (!text_state_->HasEmitted())
+  if (!text_state_.HasEmitted())
     return;
 
   // Emit with a position *inside* m_node, after m_node's contents, in
@@ -808,7 +805,7 @@
 
     // FIXME: We need to emit a '\n' as we leave an empty block(s) that
     // contain a VisiblePosition when doing selection preservation.
-    if (text_state_->LastCharacter() != '\n') {
+    if (text_state_.LastCharacter() != '\n') {
       // insert a newline with a position following this block's contents.
       SpliceBuffer(kNewlineCharacter, Strategy::Parent(*base_node), base_node,
                    1, 1);
@@ -823,7 +820,7 @@
   }
 
   // If nothing was emitted, see if we need to emit a space.
-  if (!text_state_->PositionNode() && ShouldEmitSpaceBeforeAndAfterNode(node_))
+  if (!text_state_.PositionNode() && ShouldEmitSpaceBeforeAndAfterNode(node_))
     SpliceBuffer(kSpaceCharacter, Strategy::Parent(*base_node), base_node, 1,
                  1);
 }
@@ -834,16 +831,16 @@
                                                    Node* offset_base_node,
                                                    int text_start_offset,
                                                    int text_end_offset) {
-  text_state_->SpliceBuffer(c, text_node, offset_base_node, text_start_offset,
-                            text_end_offset);
-  text_node_handler_->ResetCollapsedWhiteSpaceFixup();
+  text_state_.SpliceBuffer(c, text_node, offset_base_node, text_start_offset,
+                           text_end_offset);
+  text_node_handler_.ResetCollapsedWhiteSpaceFixup();
 }
 
 template <typename Strategy>
 EphemeralRangeTemplate<Strategy> TextIteratorAlgorithm<Strategy>::Range()
     const {
   // use the current run information, if we have it
-  if (text_state_->PositionNode()) {
+  if (text_state_.PositionNode()) {
     return EphemeralRangeTemplate<Strategy>(StartPositionInCurrentContainer(),
                                             EndPositionInCurrentContainer());
   }
@@ -858,8 +855,8 @@
 
 template <typename Strategy>
 Document* TextIteratorAlgorithm<Strategy>::OwnerDocument() const {
-  if (text_state_->PositionNode())
-    return &text_state_->PositionNode()->GetDocument();
+  if (text_state_.PositionNode())
+    return &text_state_.PositionNode()->GetDocument();
   if (end_container_)
     return &end_container_->GetDocument();
   return 0;
@@ -867,7 +864,7 @@
 
 template <typename Strategy>
 Node* TextIteratorAlgorithm<Strategy>::GetNode() const {
-  if (text_state_->PositionNode() || end_container_) {
+  if (text_state_.PositionNode() || end_container_) {
     Node* node = CurrentContainer();
     if (node->IsCharacterDataNode())
       return node;
@@ -878,9 +875,9 @@
 
 template <typename Strategy>
 int TextIteratorAlgorithm<Strategy>::StartOffsetInCurrentContainer() const {
-  if (text_state_->PositionNode()) {
-    text_state_->FlushPositionOffsets();
-    return text_state_->PositionStartOffset();
+  if (text_state_.PositionNode()) {
+    text_state_.FlushPositionOffsets();
+    return text_state_.PositionStartOffset();
   }
   DCHECK(end_container_);
   return end_offset_;
@@ -888,9 +885,9 @@
 
 template <typename Strategy>
 int TextIteratorAlgorithm<Strategy>::EndOffsetInCurrentContainer() const {
-  if (text_state_->PositionNode()) {
-    text_state_->FlushPositionOffsets();
-    return text_state_->PositionEndOffset();
+  if (text_state_.PositionNode()) {
+    text_state_.FlushPositionOffsets();
+    return text_state_.PositionEndOffset();
   }
   DCHECK(end_container_);
   return end_offset_;
@@ -898,8 +895,8 @@
 
 template <typename Strategy>
 Node* TextIteratorAlgorithm<Strategy>::CurrentContainer() const {
-  if (text_state_->PositionNode()) {
-    return text_state_->PositionNode();
+  if (text_state_.PositionNode()) {
+    return text_state_.PositionNode();
   }
   DCHECK(end_container_);
   return end_container_;
@@ -980,7 +977,7 @@
     ForwardsTextBuffer* output,
     int position,
     int copy_length) const {
-  text_state_->AppendTextTo(output, position, copy_length);
+  text_state_.AppendTextTo(output, position, copy_length);
 }
 
 // --------
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
index 2095016..e71dc6bf 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
@@ -32,13 +32,12 @@
 #include "core/editing/FindOptions.h"
 #include "core/editing/iterators/FullyClippedStateStack.h"
 #include "core/editing/iterators/TextIteratorBehavior.h"
+#include "core/editing/iterators/TextIteratorTextNodeHandler.h"
 #include "core/editing/iterators/TextIteratorTextState.h"
 #include "platform/heap/Handle.h"
 
 namespace blink {
 
-class TextIteratorTextNodeHandler;
-
 CORE_EXPORT String
 PlainText(const EphemeralRange&,
           const TextIteratorBehavior& = TextIteratorBehavior());
@@ -68,7 +67,7 @@
 
   ~TextIteratorAlgorithm();
 
-  bool AtEnd() const { return !text_state_->PositionNode() || should_stop_; }
+  bool AtEnd() const { return !text_state_.PositionNode() || should_stop_; }
   void Advance();
   bool IsInsideAtomicInlineElement() const;
   bool IsInTextSecurityMode() const;
@@ -83,10 +82,10 @@
   PositionTemplate<Strategy> StartPositionInCurrentContainer() const;
   PositionTemplate<Strategy> EndPositionInCurrentContainer() const;
 
-  const TextIteratorTextState& GetText() const { return *text_state_; }
-  int length() const { return text_state_->length(); }
+  const TextIteratorTextState& GetText() const { return text_state_; }
+  int length() const { return text_state_.length(); }
   UChar CharacterAt(unsigned index) const {
-    return text_state_->CharacterAt(index);
+    return text_state_.CharacterAt(index);
   }
 
   bool BreaksAtReplacedElement() {
@@ -235,10 +234,10 @@
   bool handle_shadow_root_ = false;
 
   // Contains state of emitted text.
-  const Member<TextIteratorTextState> text_state_;
+  TextIteratorTextState text_state_;
 
   // Helper for extracting text content from text nodes.
-  const Member<TextIteratorTextNodeHandler> text_node_handler_;
+  TextIteratorTextNodeHandler text_node_handler_;
 };
 
 extern template class CORE_EXTERN_TEMPLATE_EXPORT
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp
index e4bf6ae..1cb0ea43 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp
@@ -16,12 +16,7 @@
 TextIteratorTextNodeHandler::TextIteratorTextNodeHandler(
     const TextIteratorBehavior& behavior,
     TextIteratorTextState* text_state)
-    : behavior_(behavior), text_state_(text_state) {}
-
-DEFINE_TRACE(TextIteratorTextNodeHandler) {
-  visitor->Trace(text_node_);
-  visitor->Trace(text_state_);
-}
+    : behavior_(behavior), text_state_(*text_state) {}
 
 bool TextIteratorTextNodeHandler::HandleRemainingTextRuns() {
   if (ShouldProceedToRemainingText())
@@ -29,13 +24,13 @@
   // Handle remembered text box
   if (text_box_) {
     HandleTextBox();
-    return text_state_->PositionNode();
+    return text_state_.PositionNode();
   }
   // Handle remembered pre-formatted text node.
   if (!needs_handle_pre_formatted_text_node_)
     return false;
   HandlePreFormattedTextNode();
-  return text_state_->PositionNode();
+  return text_state_.PositionNode();
 }
 
 bool TextIteratorTextNodeHandler::ShouldHandleFirstLetter(
@@ -260,8 +255,8 @@
                                text_box_start == run_start && run_start > 0);
       if (need_space &&
           !layout_object->Style()->IsCollapsibleWhiteSpace(
-              text_state_->LastCharacter()) &&
-          text_state_->LastCharacter()) {
+              text_state_.LastCharacter()) &&
+          text_state_.LastCharacter()) {
         if (run_start > 0 && str[run_start - 1] == ' ') {
           unsigned space_run_start = run_start - 1;
           while (space_run_start > 0 && str[space_run_start - 1] == ' ')
@@ -328,7 +323,7 @@
         // If we are doing a subrun that doesn't go to the end of the text box,
         // come back again to finish handling this text box; don't advance to
         // the next one.
-        if (static_cast<unsigned>(text_state_->PositionEndOffset()) <
+        if (static_cast<unsigned>(text_state_.PositionEndOffset()) <
             text_box_end + text_start_offset)
           return;
 
@@ -440,8 +435,8 @@
                                                Node* offset_base_node,
                                                int text_start_offset,
                                                int text_end_offset) {
-  text_state_->SpliceBuffer(c, text_node, offset_base_node, text_start_offset,
-                            text_end_offset);
+  text_state_.SpliceBuffer(c, text_node, offset_base_node, text_start_offset,
+                           text_end_offset);
   ResetCollapsedWhiteSpaceFixup();
 }
 
@@ -453,10 +448,10 @@
                                                 : layout_object->GetText();
   if (behavior_.EmitsSpaceForNbsp())
     string.Replace(kNoBreakSpaceCharacter, kSpaceCharacter);
-  text_state_->EmitText(text_node,
-                        text_start_offset + layout_object->TextStartOffset(),
-                        text_end_offset + layout_object->TextStartOffset(),
-                        string, text_start_offset, text_end_offset);
+  text_state_.EmitText(text_node,
+                       text_start_offset + layout_object->TextStartOffset(),
+                       text_end_offset + layout_object->TextStartOffset(),
+                       string, text_start_offset, text_end_offset);
   ResetCollapsedWhiteSpaceFixup();
 }
 
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.h b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.h
index 48d1596..f83104b7 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.h
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.h
@@ -19,12 +19,12 @@
 
 // TextIteratorTextNodeHandler extracts plain text from a text node by calling
 // HandleTextNode() function. It should be used only by TextIterator.
-class TextIteratorTextNodeHandler final
-    : public GarbageCollectedFinalized<TextIteratorTextNodeHandler> {
+class TextIteratorTextNodeHandler {
+  STACK_ALLOCATED();
+
  public:
   TextIteratorTextNodeHandler(const TextIteratorBehavior&,
                               TextIteratorTextState*);
-  ~TextIteratorTextNodeHandler() {}
 
   Text* GetNode() const { return text_node_; }
 
@@ -44,8 +44,6 @@
   void HandleTextNodeEndAt(Text*, int end_offset);
   void HandleTextNodeInRange(Text*, int start_offset, int end_offset);
 
-  DECLARE_TRACE();
-
  private:
   void HandlePreFormattedTextNode();
   void HandleTextBox();
@@ -99,7 +97,7 @@
   const TextIteratorBehavior behavior_;
 
   // Contains state of emitted text.
-  const Member<TextIteratorTextState> text_state_;
+  TextIteratorTextState& text_state_;
 
   DISALLOW_COPY_AND_ASSIGN(TextIteratorTextNodeHandler);
 };
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp
index 3aa98ff..d3326ee 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp
@@ -32,11 +32,6 @@
 
 namespace blink {
 
-DEFINE_TRACE(TextIteratorTextState) {
-  visitor->Trace(position_node_);
-  visitor->Trace(position_offset_base_node_);
-}
-
 UChar TextIteratorTextState::CharacterAt(unsigned index) const {
   SECURITY_DCHECK(index < static_cast<unsigned>(length()));
   if (!(index < static_cast<unsigned>(length())))
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.h b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.h
index 1bfbdbd5e..7f6a494 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.h
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.h
@@ -33,11 +33,11 @@
 
 namespace blink {
 
-class CORE_EXPORT TextIteratorTextState
-    : public GarbageCollectedFinalized<TextIteratorTextState> {
+class CORE_EXPORT TextIteratorTextState {
+  STACK_ALLOCATED();
+
  public:
-  TextIteratorTextState() {}
-  ~TextIteratorTextState() {}
+  TextIteratorTextState() = default;
 
   // Return properties of the current text.
   int length() const { return text_length_; }
@@ -77,8 +77,6 @@
     text_length_ = 0;
   }
 
-  DECLARE_TRACE();
-
  private:
   int text_length_ = 0;
 
diff --git a/third_party/WebKit/Source/core/exported/WebViewTest.cpp b/third_party/WebKit/Source/core/exported/WebViewTest.cpp
index e355fd0..bf4a1c6c 100644
--- a/third_party/WebKit/Source/core/exported/WebViewTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebViewTest.cpp
@@ -43,6 +43,7 @@
 #include "core/editing/FrameSelection.h"
 #include "core/editing/InputMethodController.h"
 #include "core/editing/markers/DocumentMarkerController.h"
+#include "core/exported/FakeWebPlugin.h"
 #include "core/exported/WebSettingsImpl.h"
 #include "core/exported/WebViewBase.h"
 #include "core/frame/EventHandlerRegistry.h"
@@ -55,6 +56,7 @@
 #include "core/fullscreen/Fullscreen.h"
 #include "core/html/HTMLIFrameElement.h"
 #include "core/html/HTMLInputElement.h"
+#include "core/html/HTMLObjectElement.h"
 #include "core/html/HTMLTextAreaElement.h"
 #include "core/inspector/DevToolsEmulator.h"
 #include "core/layout/api/LayoutViewItem.h"
@@ -4399,4 +4401,37 @@
   }
 }
 
+TEST_P(WebViewTest, SetZoomLevelWhilePluginFocused) {
+  class PluginCreatingWebFrameClient
+      : public FrameTestHelpers::TestWebFrameClient {
+   public:
+    // WebFrameClient overrides:
+    WebPlugin* CreatePlugin(const WebPluginParams& params) override {
+      return new FakeWebPlugin(params);
+    }
+  };
+  PluginCreatingWebFrameClient frame_client;
+  WebViewBase* web_view = web_view_helper_.Initialize(&frame_client);
+  WebURL base_url = URLTestHelpers::ToKURL("https://example.com/");
+  FrameTestHelpers::LoadHTMLString(
+      web_view->MainFrameImpl(),
+      "<!DOCTYPE html><html><body>"
+      "<object type='application/x-webkit-test-plugin'></object>"
+      "</body></html>",
+      base_url);
+  // Verify the plugin is loaded.
+  LocalFrame* main_frame = web_view->MainFrameImpl()->GetFrame();
+  HTMLObjectElement* plugin_element =
+      toHTMLObjectElement(main_frame->GetDocument()->body()->firstChild());
+  EXPECT_TRUE(plugin_element->OwnedPlugin());
+  // Focus the plugin element, and then change the zoom level on the WebView.
+  plugin_element->focus();
+  EXPECT_FLOAT_EQ(1.0f, main_frame->PageZoomFactor());
+  web_view->SetZoomLevel(-1.0);
+  // Even though the plugin is focused, the entire frame's zoom factor should
+  // still be updated.
+  EXPECT_FLOAT_EQ(5.0f / 6.0f, main_frame->PageZoomFactor());
+  web_view_helper_.Reset();  // Remove dependency on locally scoped client.
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index 457f705a..b0cb87a 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -35,7 +35,6 @@
 #include "core/dom/AXObjectCache.h"
 #include "core/dom/DOMNodeIds.h"
 #include "core/dom/ElementVisibilityObserver.h"
-#include "core/dom/ResizeObserverController.h"
 #include "core/dom/StyleChangeReason.h"
 #include "core/dom/TaskRunnerHelper.h"
 #include "core/editing/DragCaret.h"
@@ -101,6 +100,7 @@
 #include "core/paint/PrePaintTreeWalk.h"
 #include "core/plugins/PluginView.h"
 #include "core/probe/CoreProbes.h"
+#include "core/resize_observer/ResizeObserverController.h"
 #include "core/style/ComputedStyle.h"
 #include "core/svg/SVGDocumentExtensions.h"
 #include "core/svg/SVGSVGElement.h"
diff --git a/third_party/WebKit/Source/core/html/track/TextTrackContainer.cpp b/third_party/WebKit/Source/core/html/track/TextTrackContainer.cpp
index 3a96fa2..a486cd42 100644
--- a/third_party/WebKit/Source/core/html/track/TextTrackContainer.cpp
+++ b/third_party/WebKit/Source/core/html/track/TextTrackContainer.cpp
@@ -29,12 +29,12 @@
 
 #include "core/html/track/TextTrackContainer.h"
 
-#include "core/dom/ResizeObserver.h"
-#include "core/dom/ResizeObserverEntry.h"
 #include "core/html/HTMLVideoElement.h"
 #include "core/html/track/CueTimeline.h"
 #include "core/layout/LayoutBlockFlow.h"
 #include "core/layout/LayoutVideo.h"
+#include "core/resize_observer/ResizeObserver.h"
+#include "core/resize_observer/ResizeObserverEntry.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/layout/FlexibleBoxAlgorithm.cpp b/third_party/WebKit/Source/core/layout/FlexibleBoxAlgorithm.cpp
index 8de5dce1..bd3b0c76 100644
--- a/third_party/WebKit/Source/core/layout/FlexibleBoxAlgorithm.cpp
+++ b/third_party/WebKit/Source/core/layout/FlexibleBoxAlgorithm.cpp
@@ -48,40 +48,96 @@
   DCHECK(!box->IsOutOfFlowPositioned());
 }
 
+void FlexLine::FreezeViolations(Vector<FlexItem*>& violations) {
+  for (size_t i = 0; i < violations.size(); ++i) {
+    DCHECK(!violations[i]->frozen) << i;
+    LayoutBox* child = violations[i]->box;
+    LayoutUnit child_size = violations[i]->flexed_content_size;
+    remaining_free_space -= child_size - violations[i]->flex_base_content_size;
+    total_flex_grow -= child->Style()->FlexGrow();
+    total_flex_shrink -= child->Style()->FlexShrink();
+    total_weighted_flex_shrink -=
+        child->Style()->FlexShrink() * violations[i]->flex_base_content_size;
+    // totalWeightedFlexShrink can be negative when we exceed the precision of
+    // a double when we initially calcuate totalWeightedFlexShrink. We then
+    // subtract each child's weighted flex shrink with full precision, now
+    // leading to a negative result. See
+    // css3/flexbox/large-flex-shrink-assert.html
+    total_weighted_flex_shrink = std::max(total_weighted_flex_shrink, 0.0);
+    violations[i]->frozen = true;
+  }
+}
+
+void FlexLine::FreezeInflexibleItems() {
+  // Per https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths step 2,
+  // we freeze all items with a flex factor of 0 as well as those with a min/max
+  // size violation.
+  FlexSign flex_sign = Sign();
+  remaining_free_space = container_main_inner_size - sum_flex_base_size;
+
+  Vector<FlexItem*> new_inflexible_items;
+  for (size_t i = 0; i < line_items.size(); ++i) {
+    FlexItem& flex_item = line_items[i];
+    LayoutBox* child = flex_item.box;
+    DCHECK(!flex_item.box->IsOutOfFlowPositioned());
+    DCHECK(!flex_item.frozen) << i;
+    float flex_factor = (flex_sign == kPositiveFlexibility)
+                            ? child->Style()->FlexGrow()
+                            : child->Style()->FlexShrink();
+    if (flex_factor == 0 ||
+        (flex_sign == kPositiveFlexibility &&
+         flex_item.flex_base_content_size >
+             flex_item.hypothetical_main_content_size) ||
+        (flex_sign == kNegativeFlexibility &&
+         flex_item.flex_base_content_size <
+             flex_item.hypothetical_main_content_size)) {
+      flex_item.flexed_content_size = flex_item.hypothetical_main_content_size;
+      new_inflexible_items.push_back(&flex_item);
+    }
+  }
+  FreezeViolations(new_inflexible_items);
+  initial_free_space = remaining_free_space;
+}
+
 FlexLayoutAlgorithm::FlexLayoutAlgorithm(const ComputedStyle* style,
                                          LayoutUnit line_break_length,
                                          const Vector<FlexItem>& all_items)
     : style_(style),
       line_break_length_(line_break_length),
-      all_items_(all_items) {}
+      all_items_(all_items),
+      next_item_index_(0) {}
 
-bool FlexLayoutAlgorithm::ComputeNextFlexLine(size_t* next_index,
-                                              FlexLine* line) {
-  line->Reset();
+FlexLine* FlexLayoutAlgorithm::ComputeNextFlexLine() {
+  FlexLine new_line;
 
   bool line_has_in_flow_item = false;
 
-  for (; *next_index < all_items_.size(); ++*next_index) {
-    const FlexItem& flex_item = all_items_[*next_index];
+  for (; next_item_index_ < all_items_.size(); ++next_item_index_) {
+    const FlexItem& flex_item = all_items_[next_item_index_];
     DCHECK(!flex_item.box->IsOutOfFlowPositioned());
     if (IsMultiline() &&
-        line->sum_hypothetical_main_size +
+        new_line.sum_hypothetical_main_size +
                 flex_item.HypotheticalMainAxisMarginBoxSize() >
             line_break_length_ &&
         line_has_in_flow_item)
       break;
-    line->line_items.push_back(flex_item);
+    new_line.line_items.push_back(flex_item);
     line_has_in_flow_item = true;
-    line->sum_flex_base_size += flex_item.FlexBaseMarginBoxSize();
-    line->total_flex_grow += flex_item.box->Style()->FlexGrow();
-    line->total_flex_shrink += flex_item.box->Style()->FlexShrink();
-    line->total_weighted_flex_shrink +=
+    new_line.sum_flex_base_size += flex_item.FlexBaseMarginBoxSize();
+    new_line.total_flex_grow += flex_item.box->Style()->FlexGrow();
+    new_line.total_flex_shrink += flex_item.box->Style()->FlexShrink();
+    new_line.total_weighted_flex_shrink +=
         flex_item.box->Style()->FlexShrink() * flex_item.flex_base_content_size;
-    line->sum_hypothetical_main_size +=
+    new_line.sum_hypothetical_main_size +=
         flex_item.HypotheticalMainAxisMarginBoxSize();
   }
-  DCHECK(line->line_items.size() > 0 || *next_index == all_items_.size());
-  return line->line_items.size() > 0;
+  DCHECK(new_line.line_items.size() > 0 ||
+         next_item_index_ == all_items_.size());
+  if (new_line.line_items.size() > 0) {
+    flex_lines_.push_back(std::move(new_line));
+    return &flex_lines_.back();
+  }
+  return nullptr;
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/FlexibleBoxAlgorithm.h b/third_party/WebKit/Source/core/layout/FlexibleBoxAlgorithm.h
index 665b0e2..80e51ad5 100644
--- a/third_party/WebKit/Source/core/layout/FlexibleBoxAlgorithm.h
+++ b/third_party/WebKit/Source/core/layout/FlexibleBoxAlgorithm.h
@@ -42,6 +42,11 @@
 
 class LayoutBox;
 
+enum FlexSign {
+  kPositiveFlexibility,
+  kNegativeFlexibility,
+};
+
 class FlexItem {
  public:
   FlexItem(LayoutBox*,
@@ -74,16 +79,29 @@
   bool frozen;
 };
 
-struct FlexLine {
-  void Reset() {
-    line_items.clear();
-    sum_flex_base_size = LayoutUnit();
+class FlexLine {
+ public:
+  FlexLine() {
     total_flex_grow = total_flex_shrink = total_weighted_flex_shrink = 0;
-    sum_hypothetical_main_size = LayoutUnit();
-    cross_axis_offset = cross_axis_extent = max_ascent = LayoutUnit();
   }
 
+  FlexSign Sign() const {
+    return sum_hypothetical_main_size < container_main_inner_size
+               ? kPositiveFlexibility
+               : kNegativeFlexibility;
+  }
+
+  void SetContainerMainInnerSize(LayoutUnit size) {
+    container_main_inner_size = size;
+  }
+
+  void FreezeInflexibleItems();
+
+  // This modifies remaining_free_space.
+  void FreezeViolations(Vector<FlexItem*>& violations);
+
   // These fields get filled in by ComputeNextFlexLine.
+  // TODO(cbiesinger): Consider moving to a constructor.
   Vector<FlexItem> line_items;
   LayoutUnit sum_flex_base_size;
   double total_flex_grow;
@@ -93,6 +111,17 @@
   // according to its min and max main size properties
   LayoutUnit sum_hypothetical_main_size;
 
+  // This gets set by SetContainerMainInnerSize
+  LayoutUnit container_main_inner_size;
+  // initial_free_space is the initial amount of free space in this flexbox.
+  // remaining_free_space starts out at the same value but as we place and lay
+  // out flex items we subtract from it. Note that both values can be
+  // negative.
+  // These get set by FreezeInflexibleItems, see spec:
+  // https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths step 3
+  LayoutUnit initial_free_space;
+  LayoutUnit remaining_free_space;
+
   // These get filled in by LayoutAndPlaceChildren (for now)
   // TODO(cbiesinger): Move that to FlexibleBoxAlgorithm.
   LayoutUnit cross_axis_offset;
@@ -108,7 +137,11 @@
                       LayoutUnit line_break_length,
                       const Vector<FlexItem>& all_items);
 
-  bool ComputeNextFlexLine(size_t* next_index, FlexLine*);
+  Vector<FlexLine>& FlexLines() { return flex_lines_; }
+
+  // Computes the next flex line, stores it in FlexLines(), and returns a
+  // pointer to it. Returns nullptr if there are no more lines.
+  FlexLine* ComputeNextFlexLine();
 
  private:
   bool IsMultiline() const { return style_->FlexWrap() != EFlexWrap::kNowrap; }
@@ -116,6 +149,8 @@
   const ComputedStyle* style_;
   LayoutUnit line_break_length_;
   const Vector<FlexItem>& all_items_;
+  Vector<FlexLine> flex_lines_;
+  size_t next_item_index_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp
index 0e28db6..cc2681ec 100644
--- a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp
@@ -951,8 +951,6 @@
 
 void LayoutFlexibleBox::LayoutFlexItems(bool relayout_children,
                                         SubtreeLayoutScope& layout_scope) {
-  Vector<FlexLine> line_contexts;
-
   PaintLayerScrollableArea::PreventRelayoutScope prevent_relayout_scope(
       layout_scope);
 
@@ -978,44 +976,32 @@
   FlexLayoutAlgorithm flex_algorithm(Style(), line_break_length, all_items);
   LayoutUnit cross_axis_offset =
       FlowAwareBorderBefore() + FlowAwarePaddingBefore();
-  size_t next_index = 0;
-  FlexLine current_line;
-  while (flex_algorithm.ComputeNextFlexLine(&next_index, &current_line)) {
-    DCHECK_GE(current_line.line_items.size(), 0ULL);
-    LayoutUnit container_main_inner_size =
-        MainAxisContentExtent(current_line.sum_hypothetical_main_size);
-    // availableFreeSpace is the initial amount of free space in this flexbox.
-    // remainingFreeSpace starts out at the same value but as we place and lay
-    // out flex items we subtract from it. Note that both values can be
-    // negative.
-    LayoutUnit remaining_free_space =
-        container_main_inner_size - current_line.sum_flex_base_size;
-    FlexSign flex_sign =
-        (current_line.sum_hypothetical_main_size < container_main_inner_size)
-            ? kPositiveFlexibility
-            : kNegativeFlexibility;
-    FreezeInflexibleItems(flex_sign, current_line, remaining_free_space);
-    // The initial free space gets calculated after freezing inflexible items.
-    // https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths step 3
-    const LayoutUnit initial_free_space = remaining_free_space;
-    while (!ResolveFlexibleLengths(flex_sign, current_line, initial_free_space,
-                                   remaining_free_space)) {
-      DCHECK_GE(current_line.total_flex_grow, 0);
-      DCHECK_GE(current_line.total_weighted_flex_shrink, 0);
+  FlexLine* current_line;
+  while ((current_line = flex_algorithm.ComputeNextFlexLine())) {
+    DCHECK_GE(current_line->line_items.size(), 0ULL);
+    current_line->SetContainerMainInnerSize(
+        MainAxisContentExtent(current_line->sum_hypothetical_main_size));
+    current_line->FreezeInflexibleItems();
+
+    while (!ResolveFlexibleLengths(current_line,
+                                   current_line->initial_free_space,
+                                   current_line->remaining_free_space)) {
+      DCHECK_GE(current_line->total_flex_grow, 0);
+      DCHECK_GE(current_line->total_weighted_flex_shrink, 0);
     }
 
     // Recalculate the remaining free space. The adjustment for flex factors
     // between 0..1 means we can't just use remainingFreeSpace here.
-    remaining_free_space = container_main_inner_size;
-    for (size_t i = 0; i < current_line.line_items.size(); ++i) {
-      FlexItem& flex_item = current_line.line_items[i];
+    current_line->remaining_free_space =
+        current_line->container_main_inner_size;
+    for (size_t i = 0; i < current_line->line_items.size(); ++i) {
+      FlexItem& flex_item = current_line->line_items[i];
       DCHECK(!flex_item.box->IsOutOfFlowPositioned());
-      remaining_free_space -= flex_item.FlexedMarginBoxSize();
+      current_line->remaining_free_space -= flex_item.FlexedMarginBoxSize();
     }
     LayoutAndPlaceChildren(cross_axis_offset, current_line,
-                           remaining_free_space, relayout_children,
-                           layout_scope);
-    line_contexts.push_back(current_line);
+                           current_line->remaining_free_space,
+                           relayout_children, layout_scope);
   }
   if (HasLineIfEmpty()) {
     // Even if ComputeNextFlexLine returns true, the flexbox might not have
@@ -1028,7 +1014,7 @@
   }
 
   UpdateLogicalHeight();
-  RepositionLogicalHeightDependentFlexItems(line_contexts);
+  RepositionLogicalHeightDependentFlexItems(flex_algorithm.FlexLines());
 }
 
 LayoutUnit LayoutFlexibleBox::AutoMarginOffsetInMainAxis(
@@ -1373,66 +1359,9 @@
                   margin);
 }
 
-void LayoutFlexibleBox::FreezeViolations(Vector<FlexItem*>& violations,
-                                         LayoutUnit& available_free_space,
-                                         double& total_flex_grow,
-                                         double& total_flex_shrink,
-                                         double& total_weighted_flex_shrink) {
-  for (size_t i = 0; i < violations.size(); ++i) {
-    DCHECK(!violations[i]->frozen) << i;
-    LayoutBox* child = violations[i]->box;
-    LayoutUnit child_size = violations[i]->flexed_content_size;
-    available_free_space -= child_size - violations[i]->flex_base_content_size;
-    total_flex_grow -= child->Style()->FlexGrow();
-    total_flex_shrink -= child->Style()->FlexShrink();
-    total_weighted_flex_shrink -=
-        child->Style()->FlexShrink() * violations[i]->flex_base_content_size;
-    // totalWeightedFlexShrink can be negative when we exceed the precision of
-    // a double when we initially calcuate totalWeightedFlexShrink. We then
-    // subtract each child's weighted flex shrink with full precision, now
-    // leading to a negative result. See
-    // css3/flexbox/large-flex-shrink-assert.html
-    total_weighted_flex_shrink = std::max(total_weighted_flex_shrink, 0.0);
-    violations[i]->frozen = true;
-  }
-}
-
-void LayoutFlexibleBox::FreezeInflexibleItems(
-    FlexSign flex_sign,
-    FlexLine& line,
-    LayoutUnit& remaining_free_space) {
-  // Per https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths step 2,
-  // we freeze all items with a flex factor of 0 as well as those with a min/max
-  // size violation.
-  Vector<FlexItem*> new_inflexible_items;
-  for (size_t i = 0; i < line.line_items.size(); ++i) {
-    FlexItem& flex_item = line.line_items[i];
-    LayoutBox* child = flex_item.box;
-    DCHECK(!flex_item.box->IsOutOfFlowPositioned());
-    DCHECK(!flex_item.frozen) << i;
-    float flex_factor = (flex_sign == kPositiveFlexibility)
-                            ? child->Style()->FlexGrow()
-                            : child->Style()->FlexShrink();
-    if (flex_factor == 0 ||
-        (flex_sign == kPositiveFlexibility &&
-         flex_item.flex_base_content_size >
-             flex_item.hypothetical_main_content_size) ||
-        (flex_sign == kNegativeFlexibility &&
-         flex_item.flex_base_content_size <
-             flex_item.hypothetical_main_content_size)) {
-      flex_item.flexed_content_size = flex_item.hypothetical_main_content_size;
-      new_inflexible_items.push_back(&flex_item);
-    }
-  }
-  FreezeViolations(new_inflexible_items, remaining_free_space,
-                   line.total_flex_grow, line.total_flex_shrink,
-                   line.total_weighted_flex_shrink);
-}
-
 // Returns true if we successfully ran the algorithm and sized the flex items.
 bool LayoutFlexibleBox::ResolveFlexibleLengths(
-    FlexSign flex_sign,
-    FlexLine& line,
+    FlexLine* line,
     LayoutUnit initial_free_space,
     LayoutUnit& remaining_free_space) {
   LayoutUnit total_violation;
@@ -1440,17 +1369,18 @@
   Vector<FlexItem*> min_violations;
   Vector<FlexItem*> max_violations;
 
+  FlexSign flex_sign = line->Sign();
   double sum_flex_factors = (flex_sign == kPositiveFlexibility)
-                                ? line.total_flex_grow
-                                : line.total_flex_shrink;
+                                ? line->total_flex_grow
+                                : line->total_flex_shrink;
   if (sum_flex_factors > 0 && sum_flex_factors < 1) {
     LayoutUnit fractional(initial_free_space * sum_flex_factors);
     if (fractional.Abs() < remaining_free_space.Abs())
       remaining_free_space = fractional;
   }
 
-  for (size_t i = 0; i < line.line_items.size(); ++i) {
-    FlexItem& flex_item = line.line_items[i];
+  for (size_t i = 0; i < line->line_items.size(); ++i) {
+    FlexItem& flex_item = line->line_items[i];
     LayoutBox* child = flex_item.box;
 
     // This check also covers out-of-flow children.
@@ -1459,19 +1389,19 @@
 
     LayoutUnit child_size = flex_item.flex_base_content_size;
     double extra_space = 0;
-    if (remaining_free_space > 0 && line.total_flex_grow > 0 &&
+    if (remaining_free_space > 0 && line->total_flex_grow > 0 &&
         flex_sign == kPositiveFlexibility &&
-        std::isfinite(line.total_flex_grow)) {
+        std::isfinite(line->total_flex_grow)) {
       extra_space = remaining_free_space * child->Style()->FlexGrow() /
-                    line.total_flex_grow;
+                    line->total_flex_grow;
     } else if (remaining_free_space < 0 &&
-               line.total_weighted_flex_shrink > 0 &&
+               line->total_weighted_flex_shrink > 0 &&
                flex_sign == kNegativeFlexibility &&
-               std::isfinite(line.total_weighted_flex_shrink) &&
+               std::isfinite(line->total_weighted_flex_shrink) &&
                child->Style()->FlexShrink()) {
       extra_space = remaining_free_space * child->Style()->FlexShrink() *
                     flex_item.flex_base_content_size /
-                    line.total_weighted_flex_shrink;
+                    line->total_weighted_flex_shrink;
     }
     if (std::isfinite(extra_space))
       child_size += LayoutUnit::FromFloatRound(extra_space);
@@ -1491,9 +1421,8 @@
   }
 
   if (total_violation) {
-    FreezeViolations(total_violation < 0 ? max_violations : min_violations,
-                     remaining_free_space, line.total_flex_grow,
-                     line.total_flex_shrink, line.total_weighted_flex_shrink);
+    line->FreezeViolations(total_violation < 0 ? max_violations
+                                               : min_violations);
   } else {
     remaining_free_space -= used_free_space;
   }
@@ -1769,18 +1698,18 @@
 DISABLE_CFI_PERF
 void LayoutFlexibleBox::LayoutAndPlaceChildren(
     LayoutUnit& cross_axis_offset,
-    FlexLine& current_line,
+    FlexLine* current_line,
     LayoutUnit available_free_space,
     bool relayout_children,
     SubtreeLayoutScope& layout_scope) {
   const StyleContentAlignmentData justify_content = ResolvedJustifyContent();
 
-  LayoutUnit auto_margin_offset =
-      AutoMarginOffsetInMainAxis(current_line.line_items, available_free_space);
+  LayoutUnit auto_margin_offset = AutoMarginOffsetInMainAxis(
+      current_line->line_items, available_free_space);
   LayoutUnit main_axis_offset =
       FlowAwareBorderStart() + FlowAwarePaddingStart();
   main_axis_offset += InitialContentPositionOffset(
-      available_free_space, justify_content, current_line.line_items.size());
+      available_free_space, justify_content, current_line->line_items.size());
   if (Style()->FlexDirection() == EFlexDirection::kRowReverse &&
       ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
     main_axis_offset += IsHorizontalFlow() ? VerticalScrollbarWidth()
@@ -1794,8 +1723,8 @@
   LayoutUnit max_child_cross_axis_extent;
   bool should_flip_main_axis = !IsColumnFlow() && !IsLeftToRightFlow();
   bool is_paginated = View()->GetLayoutState()->IsPaginated();
-  for (size_t i = 0; i < current_line.line_items.size(); ++i) {
-    const FlexItem& flex_item = current_line.line_items[i];
+  for (size_t i = 0; i < current_line->line_items.size(); ++i) {
+    const FlexItem& flex_item = current_line->line_items[i];
     LayoutBox* child = flex_item.box;
 
     DCHECK(!flex_item.box->IsOutOfFlowPositioned());
@@ -1844,12 +1773,12 @@
                             CrossAxisExtentForChild(*child)) -
                            ascent;
 
-      current_line.max_ascent = std::max(current_line.max_ascent, ascent);
+      current_line->max_ascent = std::max(current_line->max_ascent, ascent);
       max_descent = std::max(max_descent, descent);
 
       // TODO(cbiesinger): Take scrollbar into account
       child_cross_axis_margin_box_extent =
-          current_line.max_ascent + max_descent;
+          current_line->max_ascent + max_descent;
     } else {
       child_cross_axis_margin_box_extent =
           CrossAxisIntrinsicExtentForChild(*child) +
@@ -1876,11 +1805,11 @@
     SetFlowAwareLocationForChild(*child, child_location);
     main_axis_offset += child_main_extent + FlowAwareMarginEndForChild(*child);
 
-    if (i != current_line.line_items.size() - 1) {
+    if (i != current_line->line_items.size() - 1) {
       // The last item does not get extra space added.
       main_axis_offset += ContentDistributionSpaceBetweenChildren(
           available_free_space, justify_content,
-          current_line.line_items.size());
+          current_line->line_items.size());
     }
 
     if (is_paginated)
@@ -1897,14 +1826,14 @@
     // items since the start depends on the height of the flexbox, which we
     // only know after we've positioned all the flex items.
     UpdateLogicalHeight();
-    LayoutColumnReverse(current_line.line_items, cross_axis_offset,
+    LayoutColumnReverse(current_line->line_items, cross_axis_offset,
                         available_free_space);
   }
 
   if (number_of_in_flow_children_on_first_line_ == -1)
-    number_of_in_flow_children_on_first_line_ = current_line.line_items.size();
-  current_line.cross_axis_offset = cross_axis_offset;
-  current_line.cross_axis_extent = max_child_cross_axis_extent;
+    number_of_in_flow_children_on_first_line_ = current_line->line_items.size();
+  current_line->cross_axis_offset = cross_axis_offset;
+  current_line->cross_axis_extent = max_child_cross_axis_extent;
 
   cross_axis_offset += max_child_cross_axis_extent;
 }
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.h b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.h
index 849a896..c77c5a2d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.h
+++ b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.h
@@ -38,7 +38,7 @@
 namespace blink {
 
 class FlexItem;
-struct FlexLine;
+class FlexLine;
 
 class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
  public:
@@ -99,11 +99,6 @@
   void RemoveChild(LayoutObject*) override;
 
  private:
-  enum FlexSign {
-    kPositiveFlexibility,
-    kNegativeFlexibility,
-  };
-
   enum ChildLayoutType { kLayoutIfNeeded, kForceLayout, kNeverLayout };
 
   enum class TransformedWritingMode {
@@ -197,25 +192,16 @@
       LayoutUnit child_size);
   FlexItem ConstructFlexItem(LayoutBox& child, ChildLayoutType);
 
-  void FreezeInflexibleItems(FlexSign,
-                             FlexLine&,
-                             LayoutUnit& remaining_free_space);
-  bool ResolveFlexibleLengths(FlexSign,
-                              FlexLine&,
+  bool ResolveFlexibleLengths(FlexLine*,
                               LayoutUnit initial_free_space,
                               LayoutUnit& remaining_free_space);
-  void FreezeViolations(Vector<FlexItem*>&,
-                        LayoutUnit& available_free_space,
-                        double& total_flex_grow,
-                        double& total_flex_shrink,
-                        double& total_weighted_flex_shrink);
 
   void ResetAutoMarginsAndLogicalTopInCrossAxis(LayoutBox& child);
   void SetOverrideMainAxisContentSizeForChild(LayoutBox& child,
                                               LayoutUnit child_preferred_size);
   void PrepareChildForPositionedLayout(LayoutBox& child);
   void LayoutAndPlaceChildren(LayoutUnit& cross_axis_offset,
-                              FlexLine&,
+                              FlexLine*,
                               LayoutUnit available_free_space,
                               bool relayout_children,
                               SubtreeLayoutScope&);
diff --git a/third_party/WebKit/Source/core/layout/LayoutText.cpp b/third_party/WebKit/Source/core/layout/LayoutText.cpp
index 4a91a268..3a53c40 100644
--- a/third_party/WebKit/Source/core/layout/LayoutText.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutText.cpp
@@ -27,8 +27,10 @@
 #include <algorithm>
 #include "core/dom/AXObjectCache.h"
 #include "core/dom/Text.h"
+#include "core/editing/FrameSelection.h"
 #include "core/editing/VisiblePosition.h"
 #include "core/editing/iterators/TextIterator.h"
+#include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/Settings.h"
 #include "core/layout/LayoutBlock.h"
@@ -1916,11 +1918,18 @@
     start_pos = 0;
     end_pos = TextLength();
   } else {
-    std::tie(start_pos, end_pos) = SelectionStartEnd();
-    if (GetSelectionState() == SelectionState::kStart)
+    const FrameSelection& frame_selection = GetFrame()->Selection();
+    if (GetSelectionState() == SelectionState::kStart) {
+      start_pos = frame_selection.LayoutSelectionStart().value();
       end_pos = TextLength();
-    else if (GetSelectionState() == SelectionState::kEnd)
+    } else if (GetSelectionState() == SelectionState::kEnd) {
       start_pos = 0;
+      end_pos = frame_selection.LayoutSelectionEnd().value();
+    } else {
+      DCHECK(GetSelectionState() == SelectionState::kStartAndEnd);
+      start_pos = frame_selection.LayoutSelectionStart().value();
+      end_pos = frame_selection.LayoutSelectionEnd().value();
+    }
   }
 
   LayoutRect rect;
diff --git a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
index 01e36ed..bf61a56 100644
--- a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
+++ b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
@@ -1516,8 +1516,13 @@
         current_style_->CollapseWhiteSpace())
       trailing_objects_.Clear();
 
-    if (!width_.FitsOnLine() && width_.FitsOnLine(0, kExcludeWhitespace) &&
-        ignoring_spaces_ && next_object_) {
+    // If we are going to break before a float on an object that is just
+    // collapsible white space then make sure the line break is moved to
+    // the float.
+    if (width_.FitsOnLine(0, kExcludeWhitespace) && next_object_ &&
+        next_object_.IsFloating() && current_.GetLineLayoutItem().IsText() &&
+        LineLayoutText(current_.GetLineLayoutItem())
+            .IsAllCollapsibleWhitespace()) {
       width_.Commit();
       line_break_.MoveToStartOf(next_object_);
     }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
index 3a1d7aa..e36f204e 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -445,15 +445,23 @@
 }
 
 WTF::Optional<NGPreviousInflowPosition> NGBlockLayoutAlgorithm::HandleInflow(
-    const NGPreviousInflowPosition& previous_inflow_position,
+    const NGPreviousInflowPosition& const_previous_inflow_position,
     NGLayoutInputNode child,
     NGBreakToken* child_break_token) {
   DCHECK(child);
   DCHECK(!child.IsFloating());
   DCHECK(!child.IsOutOfFlowPositioned());
 
+  // We need a copy of the previous inflow position as we may change it.
+  NGPreviousInflowPosition previous_inflow_position(
+      const_previous_inflow_position);
+
+  // TODO(ikilpatrick): We may only want to position pending floats if there is
+  // something that we *might* clear in the unpositioned list. E.g. we may
+  // clear an already placed left float, but the unpositioned list may only have
+  // right floats.
   bool should_position_pending_floats =
-      !child.CreatesNewFormattingContext() &&
+      !child.CreatesNewFormattingContext() && child.IsBlock() &&
       ClearanceMayAffectLayout(ConstraintSpace(), unpositioned_floats_,
                                child.Style());
 
@@ -469,10 +477,25 @@
     if (updated && abort_when_bfc_resolved_)
       return WTF::nullopt;
 
+    bool positioned_direct_child_floats = !unpositioned_floats_.IsEmpty();
+
     // TODO(ikilpatrick): Check if origin_point_block_offset is correct -
     // MaybeUpdateFragmentBfcOffset might have changed it due to clearance.
     PositionPendingFloats(origin_point_block_offset, &container_builder_,
                           &unpositioned_floats_, MutableConstraintSpace());
+
+    // When we have resolved our BFC (as a child is going to clear some floats),
+    // *and* we positioned floats which are direct children, we need to
+    // artificially "reset" the previous inflow position, e.g. we clear the
+    // margin strut, and set the offset to our block-start border edge.
+    //
+    // This behaviour is similar to if we had block-start border or padding.
+    if (positioned_direct_child_floats && updated) {
+      previous_inflow_position.bfc_block_offset =
+          container_builder_.BfcOffset()->block_offset;
+      previous_inflow_position.margin_strut = NGMarginStrut();
+      previous_inflow_position.logical_block_offset = LayoutUnit();
+    }
   }
 
   // Perform layout on the child.
@@ -519,6 +542,10 @@
     return WTF::nullopt;
   }
 
+  // We have special behaviour for an empty block which gets pushed down due to
+  // clearance, see comment inside ComputeInflowPosition.
+  bool empty_block_affected_by_clearance = false;
+
   // We try and position the child within the block formatting context. This
   // may cause our BFC offset to be resolved, in which case we should abort our
   // layout if needed.
@@ -532,10 +559,9 @@
                                &child_bfc_offset))
       return WTF::nullopt;
   } else if (container_builder_.BfcOffset()) {
-    DCHECK(IsEmptyBlock(child, *layout_result));
-
     child_bfc_offset =
-        PositionWithParentBfc(*child_space, child_data, *layout_result);
+        PositionWithParentBfc(child, *child_space, child_data, *layout_result,
+                              &empty_block_affected_by_clearance);
   } else
     DCHECK(IsEmptyBlock(child, *layout_result));
 
@@ -581,7 +607,7 @@
 
   return ComputeInflowPosition(previous_inflow_position, child, child_data,
                                child_bfc_offset, logical_offset, *layout_result,
-                               fragment);
+                               fragment, empty_block_affected_by_clearance);
 }
 
 NGInflowChildData NGBlockLayoutAlgorithm::ComputeChildData(
@@ -614,15 +640,36 @@
     const WTF::Optional<NGLogicalOffset>& child_bfc_offset,
     const NGLogicalOffset& logical_offset,
     const NGLayoutResult& layout_result,
-    const NGFragment& fragment) {
+    const NGFragment& fragment,
+    bool empty_block_affected_by_clearance) {
   // Determine the child's end BFC block offset and logical offset, for the
   // next child to use.
   LayoutUnit child_end_bfc_block_offset;
   LayoutUnit logical_block_offset;
 
   if (IsEmptyBlock(child, layout_result)) {
-    child_end_bfc_block_offset = previous_inflow_position.bfc_block_offset;
-    logical_block_offset = previous_inflow_position.logical_block_offset;
+    if (empty_block_affected_by_clearance) {
+      // If an empty block was affected by clearance (that is it got pushed
+      // down past a float), we need to do something slightly bizarre.
+      //
+      // Instead of just passing through the previous inflow position, we make
+      // the inflow position our new position (which was affected by the
+      // float), minus what the margin strut would be placed at.
+      //
+      // Another way of thinking about this is that when you *add* back the
+      // margin strut, you end up with the same position as you started with.
+      //
+      // This behaviour isn't known to be in any CSS specification.
+      child_end_bfc_block_offset = child_bfc_offset.value().block_offset -
+                                   layout_result.EndMarginStrut().Sum();
+      logical_block_offset =
+          logical_offset.block_offset - layout_result.EndMarginStrut().Sum();
+    } else {
+      // The default behaviour for empty blocks is they just pass through the
+      // previous inflow position.
+      child_end_bfc_block_offset = previous_inflow_position.bfc_block_offset;
+      logical_block_offset = previous_inflow_position.logical_block_offset;
+    }
 
     if (!container_builder_.BfcOffset()) {
       DCHECK_EQ(child_end_bfc_block_offset,
@@ -731,9 +778,13 @@
 }
 
 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc(
+    const NGLayoutInputNode& child,
     const NGConstraintSpace& space,
     const NGInflowChildData& child_data,
-    const NGLayoutResult& layout_result) {
+    const NGLayoutResult& layout_result,
+    bool* empty_block_affected_by_clearance) {
+  DCHECK(IsEmptyBlock(child, layout_result));
+
   // The child must be an in-flow zero-block-size fragment, use its end margin
   // strut for positioning.
   NGLogicalOffset child_bfc_offset = {
@@ -743,7 +794,12 @@
       child_data.bfc_offset_estimate.block_offset +
           layout_result.EndMarginStrut().Sum()};
 
-  AdjustToClearance(space.ClearanceOffset(), &child_bfc_offset);
+  bool affected_by_clearance =
+      AdjustToClearance(space.ClearanceOffset(), &child_bfc_offset);
+
+  if (IsEmptyBlock(child, layout_result))
+    *empty_block_affected_by_clearance = affected_by_clearance;
+
   return child_bfc_offset;
 }
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
index 55a1a63..96a61878 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
@@ -85,7 +85,8 @@
       const WTF::Optional<NGLogicalOffset>& child_bfc_offset,
       const NGLogicalOffset& logical_offset,
       const NGLayoutResult& layout_result,
-      const NGFragment& fragment);
+      const NGFragment& fragment,
+      bool empty_block_affected_by_clearance);
 
   // Positions the fragment that establishes a new formatting context.
   //
@@ -126,9 +127,12 @@
   //   BFC Offset is known here because of the padding.
   //   <div style="padding: 1px">
   //     <div id="empty-div" style="margins: 1px"></div>
-  NGLogicalOffset PositionWithParentBfc(const NGConstraintSpace&,
-                                        const NGInflowChildData& child_data,
-                                        const NGLayoutResult&);
+  NGLogicalOffset PositionWithParentBfc(
+      const NGLayoutInputNode& child,
+      const NGConstraintSpace&,
+      const NGInflowChildData& child_data,
+      const NGLayoutResult&,
+      bool* empty_block_affected_by_clearance);
 
   NGLogicalOffset PositionLegacy(const NGConstraintSpace& child_space,
                                  const NGInflowChildData& child_data);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
index cdd4379..8c9585f 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -667,6 +667,142 @@
   EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(0)), child->Offset());
 }
 
+// An empty block level element (with margins collapsing through it) has
+// non-trivial behaviour with margins collapsing.
+TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsEmptyBlockWithClearance) {
+  SetBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    body {
+      position: relative;
+      outline: solid purple 1px;
+      width: 200px;
+    }
+    #float {
+      background: orange;
+      float: left;
+      width: 50px;
+      height: 50px;
+    }
+    #zero {
+      outline: solid red 1px;
+      clear: left;
+    }
+    #abs {
+      background: cyan;
+      position: absolute;
+      width: 20px;
+      height: 20px;
+    }
+    #inflow {
+      background: green;
+      height: 20px;
+    }
+    </style>
+    <div id="float"></div>
+    <div id="zero">
+      <!-- This exists to produce complex margin struts. -->
+      <div id="zero-inner"></div>
+    </div>
+    <div id="abs"></div>
+    <div id="inflow"></div>
+  )HTML");
+
+  const NGPhysicalBoxFragment* zero;
+  const NGPhysicalBoxFragment* abs;
+  const NGPhysicalBoxFragment* inflow;
+  RefPtr<const NGPhysicalBoxFragment> fragment;
+  auto run_test = [&](const Length& zero_inner_margin_top,
+                      const Length& zero_inner_margin_bottom,
+                      const Length& zero_margin_bottom,
+                      const Length& inflow_margin_top) {
+    // Set the style of the elements we care about.
+    Element* zero_inner = GetDocument().getElementById("zero-inner");
+    zero_inner->MutableComputedStyle()->SetMarginTop(zero_inner_margin_top);
+    zero_inner->MutableComputedStyle()->SetMarginBottom(
+        zero_inner_margin_bottom);
+
+    Element* zero_element = GetDocument().getElementById("zero");
+    zero_element->MutableComputedStyle()->SetMarginBottom(zero_margin_bottom);
+
+    Element* inflow_element = GetDocument().getElementById("inflow");
+    inflow_element->MutableComputedStyle()->SetMarginTop(inflow_margin_top);
+
+    std::tie(fragment, std::ignore) = RunBlockLayoutAlgorithmForElement(
+        GetDocument().getElementsByTagName("html")->item(0));
+    FragmentChildIterator iterator(fragment.Get());
+
+    // body
+    const NGPhysicalBoxFragment* child = iterator.NextChild();
+    EXPECT_EQ(NGPhysicalOffset(LayoutUnit(8), LayoutUnit(8)), child->Offset());
+
+    // #float
+    iterator.SetParent(child);
+    child = iterator.NextChild();
+    EXPECT_EQ(NGPhysicalSize(LayoutUnit(50), LayoutUnit(50)), child->Size());
+    EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(0)), child->Offset());
+
+    // We need to manually test the position of #zero, #abs, #inflow.
+    zero = iterator.NextChild();
+    inflow = iterator.NextChild();  // NOTE: Layout reordered the fragments.
+    abs = iterator.NextChild();
+  };
+
+  // Base case of no margins.
+  run_test(
+      /* #zero-inner margin-top */ Length(0, kFixed),
+      /* #zero-inner margin-bottom */ Length(0, kFixed),
+      /* #zero margin-bottom */ Length(0, kFixed),
+      /* #inflow margin-top */ Length(0, kFixed));
+
+  // #zero, #abs, #inflow should all be positioned at the float.
+  EXPECT_EQ(LayoutUnit(50), zero->Offset().top);
+  EXPECT_EQ(LayoutUnit(50), abs->Offset().top);
+  EXPECT_EQ(LayoutUnit(50), inflow->Offset().top);
+
+  // A margin strut which resolves to -50 (-70 + 20) adjusts the position of
+  // #zero to the float clearance.
+  run_test(
+      /* #zero-inner margin-top */ Length(-60, kFixed),
+      /* #zero-inner margin-bottom */ Length(20, kFixed),
+      /* #zero margin-bottom */ Length(-70, kFixed),
+      /* #inflow margin-top */ Length(50, kFixed));
+
+  // #zero is placed at the float, the margin strut is at:
+  // 90 = (50 - (-60 + 20)).
+  EXPECT_EQ(LayoutUnit(50), zero->Offset().top);
+
+  // #abs estimates its position with the margin strut:
+  // 40 = (90 + (-70 + 20)).
+  EXPECT_EQ(LayoutUnit(40), abs->Offset().top);
+
+  // #inflow has similar behaviour to #abs, but includes its margin.
+  // 70 = (90 + (-70 + 50))
+  EXPECT_EQ(LayoutUnit(70), inflow->Offset().top);
+
+  // A margin strut which resolves to 60 (-10 + 70) means that #zero doesn't
+  // get adjusted to clear the float, and we have normal behaviour.
+  //
+  // NOTE: This case below has wildly different results on different browsers,
+  // we may have to change the behaviour here in the future for web compat.
+  run_test(
+      /* #zero-inner margin-top */ Length(70, kFixed),
+      /* #zero-inner margin-bottom */ Length(-10, kFixed),
+      /* #zero margin-bottom */ Length(-20, kFixed),
+      /* #inflow margin-top */ Length(80, kFixed));
+
+  // #zero is placed at 60 (-10 + 70).
+  EXPECT_EQ(LayoutUnit(60), zero->Offset().top);
+
+  // #abs estimates its position with the margin strut:
+  // 50 = (0 + (-20 + 70)).
+  EXPECT_EQ(LayoutUnit(50), abs->Offset().top);
+
+  // #inflow has similar behaviour to #abs, but includes its margin.
+  // 60 = (0 + (-20 + 80))
+  EXPECT_EQ(LayoutUnit(60), inflow->Offset().top);
+}
+
 // Verifies that a box's size includes its borders and padding, and that
 // children are positioned inside the content box.
 TEST_F(NGBlockLayoutAlgorithmTest, BorderAndPadding) {
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_space_utils.cc b/third_party/WebKit/Source/core/layout/ng/ng_space_utils.cc
index 66e2182..f3cf0531 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_space_utils.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_space_utils.cc
@@ -70,13 +70,15 @@
          !is_in_parallel_flow;
 }
 
-void AdjustToClearance(const WTF::Optional<LayoutUnit>& clearance_offset,
+bool AdjustToClearance(const WTF::Optional<LayoutUnit>& clearance_offset,
                        NGLogicalOffset* offset) {
   DCHECK(offset);
-  if (clearance_offset) {
-    offset->block_offset =
-        std::max(clearance_offset.value(), offset->block_offset);
+  if (clearance_offset && clearance_offset.value() > offset->block_offset) {
+    offset->block_offset = clearance_offset.value();
+    return true;
   }
+
+  return false;
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_space_utils.h b/third_party/WebKit/Source/core/layout/ng/ng_space_utils.h
index 579141cf..c2c9737 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_space_utils.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_space_utils.h
@@ -29,7 +29,7 @@
                        const ComputedStyle& style);
 
 // Adjusts {@code offset} to the clearance line.
-CORE_EXPORT void AdjustToClearance(
+CORE_EXPORT bool AdjustToClearance(
     const WTF::Optional<LayoutUnit>& clearance_offset,
     NGLogicalOffset* offset);
 
diff --git a/third_party/WebKit/Source/core/paint/EmbeddedContentPainter.cpp b/third_party/WebKit/Source/core/paint/EmbeddedContentPainter.cpp
index 18da82b9..8ebba762 100644
--- a/third_party/WebKit/Source/core/paint/EmbeddedContentPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/EmbeddedContentPainter.cpp
@@ -23,25 +23,8 @@
   SelectionState s = layout_embedded_content_.GetSelectionState();
   if (s == SelectionState::kNone)
     return false;
-  if (s == SelectionState::kInside)
-    return true;
 
-  int selection_start, selection_end;
-  std::tie(selection_start, selection_end) =
-      layout_embedded_content_.SelectionStartEnd();
-  if (s == SelectionState::kStart)
-    return selection_start == 0;
-
-  int end = layout_embedded_content_.GetNode()->hasChildren()
-                ? layout_embedded_content_.GetNode()->CountChildren()
-                : 1;
-  if (s == SelectionState::kEnd)
-    return selection_end == end;
-  if (s == SelectionState::kStartAndEnd)
-    return selection_start == 0 && selection_end == end;
-
-  DCHECK(0);
-  return false;
+  return true;
 }
 
 void EmbeddedContentPainter::Paint(const PaintInfo& paint_info,
diff --git a/third_party/WebKit/Source/core/resize_observer/BUILD.gn b/third_party/WebKit/Source/core/resize_observer/BUILD.gn
new file mode 100644
index 0000000..e9a9cfec
--- /dev/null
+++ b/third_party/WebKit/Source/core/resize_observer/BUILD.gn
@@ -0,0 +1,23 @@
+# 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("//third_party/WebKit/Source/core/core.gni")
+
+blink_core_sources("resize_observer") {
+  sources = [
+    "ResizeObservation.cpp",
+    "ResizeObservation.h",
+    "ResizeObserver.cpp",
+    "ResizeObserver.h",
+    "ResizeObserverController.cpp",
+    "ResizeObserverController.h",
+    "ResizeObserverEntry.cpp",
+    "ResizeObserverEntry.h",
+  ]
+
+  configs += [
+    # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+    "//build/config/compiler:no_size_t_to_int_warning",
+  ]
+}
diff --git a/third_party/WebKit/Source/core/dom/ResizeObservation.cpp b/third_party/WebKit/Source/core/resize_observer/ResizeObservation.cpp
similarity index 94%
rename from third_party/WebKit/Source/core/dom/ResizeObservation.cpp
rename to third_party/WebKit/Source/core/resize_observer/ResizeObservation.cpp
index 916aa32..1e4cabb 100644
--- a/third_party/WebKit/Source/core/dom/ResizeObservation.cpp
+++ b/third_party/WebKit/Source/core/resize_observer/ResizeObservation.cpp
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/dom/ResizeObservation.h"
+#include "core/resize_observer/ResizeObservation.h"
 
-#include "core/dom/ResizeObserver.h"
 #include "core/layout/LayoutBox.h"
+#include "core/resize_observer/ResizeObserver.h"
 #include "core/svg/SVGElement.h"
 #include "core/svg/SVGGraphicsElement.h"
 
diff --git a/third_party/WebKit/Source/core/dom/ResizeObservation.h b/third_party/WebKit/Source/core/resize_observer/ResizeObservation.h
similarity index 95%
rename from third_party/WebKit/Source/core/dom/ResizeObservation.h
rename to third_party/WebKit/Source/core/resize_observer/ResizeObservation.h
index 64362c6..f5f304f 100644
--- a/third_party/WebKit/Source/core/dom/ResizeObservation.h
+++ b/third_party/WebKit/Source/core/resize_observer/ResizeObservation.h
@@ -6,7 +6,7 @@
 #define ResizeObservation_h
 
 #include "core/CoreExport.h"
-#include "core/dom/ResizeObserverEntry.h"
+#include "core/resize_observer/ResizeObserverEntry.h"
 #include "platform/geometry/LayoutSize.h"
 #include "platform/heap/Handle.h"
 
diff --git a/third_party/WebKit/Source/core/dom/ResizeObserver.cpp b/third_party/WebKit/Source/core/resize_observer/ResizeObserver.cpp
similarity index 95%
rename from third_party/WebKit/Source/core/dom/ResizeObserver.cpp
rename to third_party/WebKit/Source/core/resize_observer/ResizeObserver.cpp
index 3a5c57b..cc9e5ad 100644
--- a/third_party/WebKit/Source/core/dom/ResizeObserver.cpp
+++ b/third_party/WebKit/Source/core/resize_observer/ResizeObserver.cpp
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/dom/ResizeObserver.h"
+#include "core/resize_observer/ResizeObserver.h"
 
 #include "bindings/core/v8/ResizeObserverCallback.h"
 #include "core/dom/Element.h"
-#include "core/dom/ResizeObservation.h"
-#include "core/dom/ResizeObserverController.h"
-#include "core/dom/ResizeObserverEntry.h"
 #include "core/frame/LocalFrameView.h"
+#include "core/resize_observer/ResizeObservation.h"
+#include "core/resize_observer/ResizeObserverController.h"
+#include "core/resize_observer/ResizeObserverEntry.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/dom/ResizeObserver.h b/third_party/WebKit/Source/core/resize_observer/ResizeObserver.h
similarity index 100%
rename from third_party/WebKit/Source/core/dom/ResizeObserver.h
rename to third_party/WebKit/Source/core/resize_observer/ResizeObserver.h
diff --git a/third_party/WebKit/Source/core/dom/ResizeObserver.idl b/third_party/WebKit/Source/core/resize_observer/ResizeObserver.idl
similarity index 100%
rename from third_party/WebKit/Source/core/dom/ResizeObserver.idl
rename to third_party/WebKit/Source/core/resize_observer/ResizeObserver.idl
diff --git a/third_party/WebKit/Source/core/dom/ResizeObserverController.cpp b/third_party/WebKit/Source/core/resize_observer/ResizeObserverController.cpp
similarity index 93%
rename from third_party/WebKit/Source/core/dom/ResizeObserverController.cpp
rename to third_party/WebKit/Source/core/resize_observer/ResizeObserverController.cpp
index db85900..34315e3 100644
--- a/third_party/WebKit/Source/core/dom/ResizeObserverController.cpp
+++ b/third_party/WebKit/Source/core/resize_observer/ResizeObserverController.cpp
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/dom/ResizeObserverController.h"
+#include "core/resize_observer/ResizeObserverController.h"
 
-#include "core/dom/ResizeObserver.h"
+#include "core/resize_observer/ResizeObserver.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/dom/ResizeObserverController.h b/third_party/WebKit/Source/core/resize_observer/ResizeObserverController.h
similarity index 100%
rename from third_party/WebKit/Source/core/dom/ResizeObserverController.h
rename to third_party/WebKit/Source/core/resize_observer/ResizeObserverController.h
diff --git a/third_party/WebKit/Source/core/dom/ResizeObserverEntry.cpp b/third_party/WebKit/Source/core/resize_observer/ResizeObserverEntry.cpp
similarity index 86%
rename from third_party/WebKit/Source/core/dom/ResizeObserverEntry.cpp
rename to third_party/WebKit/Source/core/resize_observer/ResizeObserverEntry.cpp
index 05391a6..c9b9015e 100644
--- a/third_party/WebKit/Source/core/dom/ResizeObserverEntry.cpp
+++ b/third_party/WebKit/Source/core/resize_observer/ResizeObserverEntry.cpp
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/dom/ResizeObserverEntry.h"
+#include "core/resize_observer/ResizeObserverEntry.h"
 
 #include "core/dom/Element.h"
-#include "core/dom/ResizeObservation.h"
 #include "core/geometry/DOMRectReadOnly.h"
+#include "core/resize_observer/ResizeObservation.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/dom/ResizeObserverEntry.h b/third_party/WebKit/Source/core/resize_observer/ResizeObserverEntry.h
similarity index 100%
rename from third_party/WebKit/Source/core/dom/ResizeObserverEntry.h
rename to third_party/WebKit/Source/core/resize_observer/ResizeObserverEntry.h
diff --git a/third_party/WebKit/Source/core/dom/ResizeObserverEntry.idl b/third_party/WebKit/Source/core/resize_observer/ResizeObserverEntry.idl
similarity index 100%
rename from third_party/WebKit/Source/core/dom/ResizeObserverEntry.idl
rename to third_party/WebKit/Source/core/resize_observer/ResizeObserverEntry.idl
diff --git a/third_party/WebKit/Source/core/dom/ResizeObserverTest.cpp b/third_party/WebKit/Source/core/resize_observer/ResizeObserverTest.cpp
similarity index 96%
rename from third_party/WebKit/Source/core/dom/ResizeObserverTest.cpp
rename to third_party/WebKit/Source/core/resize_observer/ResizeObserverTest.cpp
index c1a99bb..6328e78 100644
--- a/third_party/WebKit/Source/core/dom/ResizeObserverTest.cpp
+++ b/third_party/WebKit/Source/core/resize_observer/ResizeObserverTest.cpp
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/dom/ResizeObserver.h"
+#include "core/resize_observer/ResizeObserver.h"
 
 #include "bindings/core/v8/ScriptController.h"
 #include "bindings/core/v8/ScriptSourceCode.h"
 #include "bindings/core/v8/V8GCController.h"
-#include "core/dom/ResizeObservation.h"
-#include "core/dom/ResizeObserverController.h"
 #include "core/exported/WebViewBase.h"
+#include "core/resize_observer/ResizeObservation.h"
+#include "core/resize_observer/ResizeObserverController.h"
 #include "core/testing/sim/SimCompositor.h"
 #include "core/testing/sim/SimDisplayItemList.h"
 #include "core/testing/sim/SimRequest.h"
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/whatsnew.png b/third_party/WebKit/Source/devtools/front_end/Images/whatsnew.png
index 9bb608b8..f634073 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/whatsnew.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/whatsnew.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/help/ReleaseNoteText.js b/third_party/WebKit/Source/devtools/front_end/help/ReleaseNoteText.js
index 2cb717fe..88745cd7 100644
--- a/third_party/WebKit/Source/devtools/front_end/help/ReleaseNoteText.js
+++ b/third_party/WebKit/Source/devtools/front_end/help/ReleaseNoteText.js
@@ -12,6 +12,33 @@
 /** @type {!Array<!Help.ReleaseNote>} */
 Help.releaseNoteText = [
   {
+    version: 4,
+    header: 'Highlights from the Chrome 61 update',
+    highlights: [
+      {
+        title: 'Mobile device throttling',
+        subtitle: 'Simulate a mobile device\'s CPU and network throttling from Device Mode.',
+        link: 'https://developers.google.com/web/updates/2017/07/devtools-release-notes#throttling',
+      },
+      {
+        title: 'Storage usage',
+        subtitle: 'See how much storage (IndexedDB, local, session, cache, etc.) an origin is using.',
+        link: 'https://developers.google.com/web/updates/2017/07/devtools-release-notes#storage',
+      },
+      {
+        title: 'Cache timestamps',
+        subtitle: 'View when a service worker cached a response.',
+        link: 'https://developers.google.com/web/updates/2017/07/devtools-release-notes#time-cached',
+      },
+      {
+        title: 'ES6 Modules support',
+        subtitle: 'Debug ES6 Modules natively from the Sources panel.',
+        link: 'https://developers.google.com/web/updates/2017/07/devtools-release-notes#modules',
+      }
+    ],
+    link: 'https://developers.google.com/web/updates/2017/07/devtools-release-notes',
+  },
+  {
     version: 3,
     header: 'Highlights from the Chrome 60 update',
     highlights: [
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
index 755d78c..bd73b89 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
@@ -31,8 +31,6 @@
 #include "core/dom/MutationObserver.h"
 #include "core/dom/MutationObserverInit.h"
 #include "core/dom/MutationRecord.h"
-#include "core/dom/ResizeObserver.h"
-#include "core/dom/ResizeObserverEntry.h"
 #include "core/dom/TaskRunnerHelper.h"
 #include "core/events/KeyboardEvent.h"
 #include "core/events/MouseEvent.h"
@@ -49,6 +47,8 @@
 #include "core/layout/LayoutObject.h"
 #include "core/layout/LayoutTheme.h"
 #include "core/page/SpatialNavigation.h"
+#include "core/resize_observer/ResizeObserver.h"
+#include "core/resize_observer/ResizeObserverEntry.h"
 #include "modules/media_controls/MediaControlsMediaEventListener.h"
 #include "modules/media_controls/MediaControlsOrientationLockDelegate.h"
 #include "modules/media_controls/MediaControlsRotateToFullscreenDelegate.h"
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index 9eff470..f7fc7dd 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -76,6 +76,7 @@
 #include "core/html/HTMLMediaElement.h"
 #include "core/html/HTMLPlugInElement.h"
 #include "core/html/HTMLTextAreaElement.h"
+#include "core/html/PluginDocument.h"
 #include "core/input/ContextMenuAllowedScope.h"
 #include "core/input/EventHandler.h"
 #include "core/input/TouchActionUtil.h"
@@ -2840,8 +2841,12 @@
                                                        float zoom_factor) {
   if (frame->IsLocalRoot()) {
     LocalFrame* local_frame = ToLocalFrame(frame);
-    if (!local_frame->GetWebPluginContainer())
-      local_frame->SetPageZoomFactor(zoom_factor);
+    if (Document* document = local_frame->GetDocument()) {
+      if (!document->IsPluginDocument() ||
+          !ToPluginDocument(document)->GetPluginView()) {
+        local_frame->SetPageZoomFactor(zoom_factor);
+      }
+    }
   }
 
   for (Frame* child = frame->Tree().FirstChild(); child;
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit_mock.py
index 47579ea..5e481af 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit_mock.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit_mock.py
@@ -9,15 +9,19 @@
 
     def __init__(self, host,
                  position='refs/heads/master@{#123}',
-                 message='Fake commit message',
-                 patch='Fake patch contents',
-                 change_id='Iba5eba11'):
+                 change_id='Iba5eba11',
+                 author='Fake author',
+                 subject='Fake subject',
+                 body='Fake body',
+                 patch='Fake patch contents'):
         self.host = host
         self.position = position
         self.sha = hashlib.sha1(position).hexdigest()
-        self._message = message
-        self._patch = patch
         self._change_id = change_id
+        self._author = author
+        self._subject = subject
+        self._body = body
+        self._patch = patch
 
     @property
     def short_sha(self):
@@ -32,11 +36,17 @@
     def url(self):
         return 'https://fake-chromium-commit-viewer.org/+/%s' % self.short_sha
 
-    def message(self):
-        return self._message
+    def author(self):
+        return self._author
 
     def subject(self):
-        return self._message
+        return self._subject
+
+    def body(self):
+        return self._body + '\n\nChange-Id: ' + self.change_id()
+
+    def message(self):
+        return self.subject() + '\n\n' + self.body()
 
     def format_patch(self):
         return self._patch
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common_unittest.py
index 0bd1c15e5..270dde5 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common_unittest.py
@@ -52,36 +52,35 @@
             ['git', 'diff-tree', '--name-only', '--no-commit-id', '-r', 'add087a97844f4b9e307d9a216940582d96db306', '--',
              '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt'],
             ['git', 'format-patch', '-1', '--stdout', 'add087a97844f4b9e307d9a216940582d96db306', '--', 'some', 'files'],
-            ['git', 'footers', '--key', 'Change-Id', 'add087a97844f4b9e307d9a216940582d96db306'],
         ])
 
     def test_is_exportable(self):
-        commit = MockChromiumCommit(MockHost(), message='Message')
+        commit = MockChromiumCommit(MockHost())
         github = MockWPTGitHub(pull_requests=[])
         self.assertTrue(is_exportable(commit, MockLocalWPT(), github))
 
     def test_commit_with_noexport_is_not_exportable(self):
-        commit = MockChromiumCommit(MockHost(), message='Message\nNo-Export: true')
+        commit = MockChromiumCommit(MockHost(), body='Message\nNo-Export: true')
         github = MockWPTGitHub(pull_requests=[])
         self.assertFalse(is_exportable(commit, MockLocalWPT(), github))
 
         # The older NOEXPORT tag also makes it non-exportable.
-        old_commit = MockChromiumCommit(MockHost(), message='Message\nNOEXPORT=true')
+        old_commit = MockChromiumCommit(MockHost(), body='Message\nNOEXPORT=true')
         self.assertFalse(is_exportable(old_commit, MockLocalWPT(), github))
 
         # No-Export/NOEXPORT in a revert CL also makes it non-exportable.
-        revert = MockChromiumCommit(MockHost(), message='Revert of Message\n> No-Export: true')
+        revert = MockChromiumCommit(MockHost(), body='Revert of Message\n> No-Export: true')
         self.assertFalse(is_exportable(revert, MockLocalWPT(), github))
-        old_revert = MockChromiumCommit(MockHost(), message='Revert of Message\n> NOEXPORT=true')
+        old_revert = MockChromiumCommit(MockHost(), body='Revert of Message\n> NOEXPORT=true')
         self.assertFalse(is_exportable(old_revert, MockLocalWPT(), github))
 
     def test_commit_that_starts_with_import_is_not_exportable(self):
-        commit = MockChromiumCommit(MockHost(), message='Import message')
+        commit = MockChromiumCommit(MockHost(), subject='Import message')
         github = MockWPTGitHub(pull_requests=[])
         self.assertFalse(is_exportable(commit, MockLocalWPT(), github))
 
     def test_commit_that_has_open_pr_is_exportable(self):
-        commit = MockChromiumCommit(MockHost(), change_id='Change-Id: I00decade')
+        commit = MockChromiumCommit(MockHost(), change_id='I00decade')
         github = MockWPTGitHub(pull_requests=[
             PullRequest('PR1', 1, 'body\nChange-Id: I00c0ffee', 'closed', []),
             PullRequest('PR2', 2, 'body\nChange-Id: I00decade', 'open', []),
@@ -89,7 +88,7 @@
         self.assertTrue(is_exportable(commit, MockLocalWPT(), github))
 
     def test_commit_that_has_closed_pr_is_not_exportable(self):
-        commit = MockChromiumCommit(MockHost(), change_id='Change-Id: I00decade')
+        commit = MockChromiumCommit(MockHost(), change_id='I00decade')
         github = MockWPTGitHub(pull_requests=[
             PullRequest('PR1', 1, 'body\nChange-Id: I00c0ffee', 'closed', []),
             PullRequest('PR2', 2, 'body\nChange-Id: I00decade', 'closed', []),
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py
index 09b4193c..8569789 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py
@@ -40,7 +40,7 @@
 
         exportable_commits = self.get_exportable_commits()
         for exportable_commit in exportable_commits:
-            pull_request = self.corresponding_pull_request_for_commit(exportable_commit)
+            pull_request = self.wpt_github.pr_for_chromium_commit(exportable_commit)
 
             if pull_request:
                 if pull_request.state == 'open':
@@ -247,20 +247,3 @@
             ))
 
         return response_data
-
-    def corresponding_pull_request_for_commit(self, exportable_commit):
-        """Search pull requests for one that corresponds to exportable_commit.
-
-        Returns the pull_request if found, else returns None.
-        """
-        # Check for PRs created by open Gerrit CLs.
-        change_id = exportable_commit.change_id()
-        if change_id:
-            return self.wpt_github.pr_with_change_id(change_id)
-
-        # Check for PRs created by commits on master.
-        pull_request = self.wpt_github.pr_with_position(exportable_commit.position)
-        if pull_request:
-            return pull_request
-
-        return None
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py
index e4a5855..e966301 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py
@@ -8,11 +8,12 @@
 from webkitpy.common.host_mock import MockHost
 from webkitpy.common.system.executive_mock import MockExecutive, mock_git_commands
 from webkitpy.w3c.chromium_commit import ChromiumCommit
+from webkitpy.w3c.chromium_commit_mock import MockChromiumCommit
+from webkitpy.w3c.gerrit import GerritCL
+from webkitpy.w3c.gerrit_mock import MockGerritAPI
 from webkitpy.w3c.test_exporter import TestExporter
 from webkitpy.w3c.wpt_github import PullRequest
 from webkitpy.w3c.wpt_github_mock import MockWPTGitHub
-from webkitpy.w3c.gerrit import GerritCL
-from webkitpy.w3c.gerrit_mock import MockGerritAPI
 
 
 class TestExporterTest(unittest.TestCase):
@@ -39,9 +40,9 @@
         test_exporter.run()
 
         self.assertEqual(test_exporter.wpt_github.calls, [
-            'pr_with_position',
-            'pr_with_position',
-            'pr_with_position',
+            'pr_for_chromium_commit',
+            'pr_for_chromium_commit',
+            'pr_for_chromium_commit',
         ])
 
     def test_creates_pull_request_for_all_exportable_commits(self):
@@ -77,16 +78,16 @@
         test_exporter.run()
 
         self.assertEqual(test_exporter.wpt_github.calls, [
-            'pr_with_change_id',
-            'pr_with_change_id',
-            'pr_with_change_id',
-            'pr_with_change_id',
+            'pr_for_chromium_commit',
+            'pr_for_chromium_commit',
+            'pr_for_chromium_commit',
+            'pr_for_chromium_commit',
             'create_pr',
             'add_label "chromium-export"',
-            'pr_with_change_id',
+            'pr_for_chromium_commit',
             'create_pr',
             'add_label "chromium-export"',
-            'pr_with_change_id',
+            'pr_for_chromium_commit',
             'create_pr',
             'add_label "chromium-export"',
         ])
@@ -103,51 +104,52 @@
         # 4. #458478 has an in-flight PR associated with it and should be merged successfully.
         host = MockHost()
         host.executive = mock_git_commands({
-            'show': 'git show text\nCr-Commit-Position: refs/heads/master@{#458476}',
+            'show': 'git show text\nCr-Commit-Position: refs/heads/master@{#458476}\nChange-Id: I0476',
             'crrev-parse': 'c2087acb00eee7960339a0be34ea27d6b20e1131',
+
         })
         test_exporter = TestExporter(host, 'gh-username', 'gh-token', gerrit_user=None, gerrit_token=None)
         test_exporter.wpt_github = MockWPTGitHub(pull_requests=[
             PullRequest(
                 title='Open PR',
                 number=1234,
-                body='rutabaga\nCr-Commit-Position: refs/heads/master@{#458475}',
+                body='rutabaga\nCr-Commit-Position: refs/heads/master@{#458475}\nChange-Id: I0005',
                 state='open',
                 labels=['do not merge yet']
             ),
             PullRequest(
                 title='Merged PR',
                 number=2345,
-                body='rutabaga\nCr-Commit-Position: refs/heads/master@{#458477}',
+                body='rutabaga\nCr-Commit-Position: refs/heads/master@{#458477}\nChange-Id: Idead',
                 state='closed',
                 labels=[]
             ),
             PullRequest(
                 title='Open PR',
                 number=3456,
-                body='rutabaga\nCr-Commit-Position: refs/heads/master@{#458478}',
+                body='rutabaga\nCr-Commit-Position: refs/heads/master@{#458478}\nChange-Id: I0118',
                 state='open',
                 labels=[]  # It's important that this is empty.
             ),
         ], unsuccessful_merge_index=0)
         test_exporter.gerrit = MockGerritAPI(host, 'gerrit-username', 'gerrit-token')
         test_exporter.get_exportable_commits = lambda: [
-            ChromiumCommit(host, position='refs/heads/master@{#458475}'),
-            ChromiumCommit(host, position='refs/heads/master@{#458476}'),
-            ChromiumCommit(host, position='refs/heads/master@{#458477}'),
-            ChromiumCommit(host, position='refs/heads/master@{#458478}'),
+            MockChromiumCommit(host, position='refs/heads/master@{#458475}', change_id='I0005'),
+            MockChromiumCommit(host, position='refs/heads/master@{#458476}', change_id='I0476'),
+            MockChromiumCommit(host, position='refs/heads/master@{#458477}', change_id='Idead'),
+            MockChromiumCommit(host, position='refs/heads/master@{#458478}', change_id='I0118'),
         ]
         test_exporter.run()
         self.assertEqual(test_exporter.wpt_github.calls, [
-            'pr_with_position',
+            'pr_for_chromium_commit',
             'remove_label "do not merge yet"',
             'get_pr_branch',
             'merge_pull_request',
-            'pr_with_position',
+            'pr_for_chromium_commit',
             'create_pr',
             'add_label "chromium-export"',
-            'pr_with_position',
-            'pr_with_position',
+            'pr_for_chromium_commit',
+            'pr_for_chromium_commit',
             # Testing the lack of remove_label here. The exporter should not
             # try to remove the provisional label from PRs it has already
             # removed it from.
@@ -156,9 +158,7 @@
             'delete_remote_branch',
         ])
         self.assertEqual(test_exporter.wpt_github.pull_requests_created, [
-            ('chromium-export-c2087acb00',
-             'git show text\nCr-Commit-Position: refs/heads/master@{#458476}',
-             'git show text\nCr-Commit-Position: refs/heads/master@{#458476}'),
+            ('chromium-export-52c3178508', 'Fake subject', 'Fake body\n\nChange-Id: I0476'),
         ])
 
     def test_new_gerrit_cl(self):
@@ -291,7 +291,7 @@
         test_exporter.run()
 
         self.assertEqual(test_exporter.wpt_github.calls, [
-            'pr_with_change_id',
+            'pr_for_chromium_commit',
             'remove_label "do not merge yet"',
             'get_pr_branch',
             'merge_pull_request',
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
index b29e552..9c51743 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
@@ -26,7 +26,7 @@
         ])
         importer = TestImporter(host, wpt_github=wpt_github)
         importer.exportable_but_not_exported_commits = lambda _: [
-            MockChromiumCommit(host, change_id='Iba5eba11')
+            MockChromiumCommit(host, subject='Fake PR subject', change_id='Iba5eba11')
         ]
         importer.checkout_is_okay = lambda: True
         return_code = importer.main(['--credentials-json=/tmp/creds.json'])
@@ -35,7 +35,7 @@
             'INFO: Cloning GitHub w3c/web-platform-tests into /tmp/wpt\n',
             'INFO: There were exportable but not-yet-exported commits:\n',
             'INFO: Commit: https://fake-chromium-commit-viewer.org/+/14fd77e88e\n',
-            'INFO: Subject: Fake commit message\n',
+            'INFO: Subject: Fake PR subject\n',
             'INFO: PR: https://github.com/w3c/web-platform-tests/pull/5\n',
             'INFO: Modified files in wpt directory in this commit:\n',
             'INFO:   third_party/WebKit/LayoutTests/external/wpt/one.html\n',
@@ -50,7 +50,7 @@
         wpt_github = MockWPTGitHub(pull_requests=[])
         importer = TestImporter(host, wpt_github=wpt_github)
         importer.exportable_but_not_exported_commits = lambda _: [
-            MockChromiumCommit(host, position='refs/heads/master@{#431}')
+            MockChromiumCommit(host, subject='Fake PR subject', position='refs/heads/master@{#431}')
         ]
         importer.checkout_is_okay = lambda: True
         return_code = importer.main(['--credentials-json=/tmp/creds.json'])
@@ -59,7 +59,7 @@
             'INFO: Cloning GitHub w3c/web-platform-tests into /tmp/wpt\n',
             'INFO: There were exportable but not-yet-exported commits:\n',
             'INFO: Commit: https://fake-chromium-commit-viewer.org/+/fa2de685c0\n',
-            'INFO: Subject: Fake commit message\n',
+            'INFO: Subject: Fake PR subject\n',
             'WARNING: No pull request found.\n',
             'INFO: Modified files in wpt directory in this commit:\n',
             'INFO:   third_party/WebKit/LayoutTests/external/wpt/one.html\n',
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github_mock.py
index 7e8ff05..304a1d92 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github_mock.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github_mock.py
@@ -63,19 +63,25 @@
         return 'fake branch for PR {}'.format(number)
 
     def pr_for_chromium_commit(self, commit):
-        return self.pr_with_change_id(commit.change_id())
+        self.calls.append('pr_for_chromium_commit')
+        for pr in self.pull_requests:
+            if commit.change_id() in pr.body:
+                return pr
+        return None
 
     def pr_with_position(self, position):
         self.calls.append('pr_with_position')
         for pr in self.pull_requests:
             if position in pr.body:
                 return pr
+        return None
 
     def pr_with_change_id(self, change_id):
         self.calls.append('pr_with_change_id')
         for pr in self.pull_requests:
             if change_id in pr.body:
                 return pr
+        return None
 
     def extract_metadata(self, tag, commit_body):
         for line in commit_body.splitlines():
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github_unittest.py
index d30d7bdf..e4ef9d3 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github_unittest.py
@@ -6,7 +6,8 @@
 import unittest
 
 from webkitpy.common.host_mock import MockHost
-from webkitpy.w3c.wpt_github import WPTGitHub, MergeError, GitHubError
+from webkitpy.w3c.chromium_commit_mock import MockChromiumCommit
+from webkitpy.w3c.wpt_github import GitHubError, MergeError, PullRequest, WPTGitHub
 
 
 class WPTGitHubTest(unittest.TestCase):
@@ -49,3 +50,23 @@
 
         with self.assertRaises(GitHubError):
             self.wpt_github.delete_remote_branch('rutabaga')
+
+    def test_pr_for_chromium_commit_prefers_change_id(self):
+        self.wpt_github.all_pull_requests = lambda: [
+            PullRequest('PR1', 1, 'body\nChange-Id: I00c0ffee\nCr-Commit-Position: refs/heads/master@{#10}', 'open', []),
+            PullRequest('PR2', 2, 'body\nChange-Id: I00decade\nCr-Commit-Position: refs/heads/master@{#33}', 'open', []),
+        ]
+        chromium_commit = MockChromiumCommit(
+            MockHost(), change_id='I00decade', position='refs/heads/master@{#10}')
+        pull_request = self.wpt_github.pr_for_chromium_commit(chromium_commit)
+        self.assertEqual(pull_request.number, 2)
+
+    def test_pr_for_chromium_commit_falls_back_to_commit_position(self):
+        self.wpt_github.all_pull_requests = lambda: [
+            PullRequest('PR1', 1, 'body\nChange-Id: I00c0ffee\nCr-Commit-Position: refs/heads/master@{#10}', 'open', []),
+            PullRequest('PR2', 2, 'body\nChange-Id: I00decade\nCr-Commit-Position: refs/heads/master@{#33}', 'open', []),
+        ]
+        chromium_commit = MockChromiumCommit(
+            MockHost(), position='refs/heads/master@{#10}')
+        pull_request = self.wpt_github.pr_for_chromium_commit(chromium_commit)
+        self.assertEqual(pull_request.number, 1)
diff --git a/third_party/leveldatabase/env_chromium.cc b/third_party/leveldatabase/env_chromium.cc
index 4a6f9a3..6dbfc37 100644
--- a/third_party/leveldatabase/env_chromium.cc
+++ b/third_party/leveldatabase/env_chromium.cc
@@ -1197,11 +1197,16 @@
  public:
   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
                     base::trace_event::ProcessMemoryDump* pmd) override {
+    // Don't dump in background mode ("from the field") until whitelisted.
+    if (args.level_of_detail ==
+        base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND) {
+      return true;
+    }
+
     auto db_visitor = [](const base::trace_event::MemoryDumpArgs& args,
                          base::trace_event::ProcessMemoryDump* pmd,
                          TrackedDB* db) {
-      std::string db_dump_name = base::StringPrintf(
-          "leveldatabase/0x%" PRIXPTR, reinterpret_cast<uintptr_t>(db));
+      std::string db_dump_name = DBTracker::GetMemoryDumpName(db);
       auto* db_dump = pmd->CreateAllocatorDump(db_dump_name.c_str());
 
       uint64_t db_memory_usage = 0;
@@ -1249,11 +1254,19 @@
   return instance;
 }
 
+std::string DBTracker::GetMemoryDumpName(leveldb::DB* tracked_db) {
+  return base::StringPrintf("leveldatabase/0x%" PRIXPTR,
+                            reinterpret_cast<uintptr_t>(tracked_db));
+}
+
 leveldb::Status DBTracker::OpenDatabase(const leveldb::Options& options,
                                         const std::string& name,
                                         TrackedDB** dbptr) {
   leveldb::DB* db = nullptr;
   auto status = leveldb::DB::Open(options, name, &db);
+  // Enforce expectations: either we succeed, and get a valid object in |db|,
+  // or we fail, and |db| is still NULL.
+  CHECK((status.ok() && db) || (!status.ok() && !db));
   if (status.ok()) {
     // TrackedDBImpl ctor adds the instance to the tracker.
     *dbptr = new TrackedDBImpl(GetInstance(), name, db);
diff --git a/third_party/leveldatabase/env_chromium.h b/third_party/leveldatabase/env_chromium.h
index 690a032a..02a68c6 100644
--- a/third_party/leveldatabase/env_chromium.h
+++ b/third_party/leveldatabase/env_chromium.h
@@ -242,6 +242,13 @@
   // DBTracker singleton instance.
   static DBTracker* GetInstance();
 
+  // Returns name of memory-infra dump for |tracked_db|. Can be used to attach
+  // additional info to the database dump, or to properly attribute memory
+  // usage in memory dump providers that also dump |tracked_db|.
+  // Note that |tracked_db| should be a live database instance produced by
+  // OpenDatabase() method or leveldb_env::OpenDB() function.
+  static std::string GetMemoryDumpName(leveldb::DB* tracked_db);
+
   // Provides extra information about a tracked database.
   class TrackedDB : public leveldb::DB {
    public:
@@ -252,6 +259,8 @@
   // Opens a database and starts tracking it. As long as the opened database
   // is alive (i.e. its instance is not destroyed) the database is exposed to
   // memory-infra and is enumerated by VisitDatabases() method.
+  // This function is an implementation detail of leveldb_env::OpenDB(), and
+  // has similar guarantees regarding |dbptr| argument.
   leveldb::Status OpenDatabase(const leveldb::Options& options,
                                const std::string& name,
                                TrackedDB** dbptr);
@@ -285,7 +294,9 @@
 };
 
 // Opens a database and exposes it to Chrome's tracing (see DBTracker for
-// details). Note that |dbptr| is touched only when function succeeds.
+// details). The function guarantees that:
+//   1. |dbptr| is not touched on failure
+//   2. |dbptr| is not NULL on success
 leveldb::Status OpenDB(const leveldb::Options& options,
                        const std::string& name,
                        std::unique_ptr<leveldb::DB>* dbptr);
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index b5ff2172..12e96ee8 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -96,7 +96,7 @@
 
     'chromium.fyi': {
       'Afl Upload Linux ASan': 'release_afl_asan',
-      'Android Builder (dbg)': 'android_debug_static_bot',
+      'Android Builder (dbg)': 'android_debug_static_bot_vrdata',
       'Android Builder Goma Canary (dbg)': 'android_debug_bot',
       'Android deterministic': 'android_without_codecs_release_bot_minimal_symbols',
       'Android deterministic (dbg)': 'android_debug_bot',
@@ -782,6 +782,10 @@
       'android', 'debug_static_bot',
     ],
 
+    'android_debug_static_bot_vrdata': [
+      'android', 'debug_static_bot', 'include_vr_data',
+    ],
+
     'android_debug_static_bot_arm64': [
       'android', 'debug_static_bot', 'arm64',
     ],
@@ -1763,6 +1767,10 @@
       'mixins': ['disable_nacl'],
     },
 
+    'include_vr_data': {
+      'gn_args': 'include_vr_data=true',
+    },
+
     'internal_gles2_conform_tests': {
       'gn_args': 'internal_gles2_conform_tests=true',
     },
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index d0d8067..3fbafed 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -23109,6 +23109,8 @@
   <int value="-277144896" label="enable-viewport-meta"/>
   <int value="-275870837"
       label="OmniboxUIExperimentHideSuggestionUrlPath:enabled"/>
+  <int value="-275619817"
+      label="disable-proximity-auth-bluetooth-low-energy-discovery"/>
   <int value="-275164173" label="QuickUnlockPinSignin:enabled"/>
   <int value="-268357961" label="enable-feature-policy"/>
   <int value="-254887599" label="google-profile-info"/>
@@ -23376,8 +23378,6 @@
   <int value="649111851" label="MidiManagerCros:enabled"/>
   <int value="651421878" label="VideoRotateToFullscreen:enabled"/>
   <int value="652561231" label="CustomContextMenu:enabled"/>
-  <int value="683410401"
-      label="enable-proximity-auth-bluetooth-low-energy-discovery"/>
   <int value="684806628" label="TranslateLanguageByULP:disabled"/>
   <int value="685916283" label="enable-zip-archiver-on-file-manager"/>
   <int value="689489984" label="disable-zero-suggest"/>
@@ -32475,6 +32475,13 @@
   <int value="4" label="UNABLE_TO_RENAME_FAILURE"/>
 </enum>
 
+<enum name="SafeBrowsingWebSocketResult">
+  <int value="0" label="UNKNOWN"/>
+  <int value="1" label="SAFE"/>
+  <int value="2" label="BLOCKED"/>
+  <int value="3" label="ABANDONED"/>
+</enum>
+
 <enum name="SavePasswordPromptResponseType">
   <int value="0" label="NO_RESPONSE"/>
   <int value="1" label="REMEMBER_PASSWORD"/>
@@ -38507,6 +38514,17 @@
   <int value="59" label=".zip"/>
 </enum>
 
+<enum name="VirtualKeyboardControllerState">
+  <int value="0" label="UNKNOWN"/>
+  <int value="1" label="INITIAL"/>
+  <int value="2" label="LOADING_EXTENSION"/>
+  <int value="3" label="SHOWING"/>
+  <int value="4" label="SHOWN"/>
+  <int value="5" label="WILL_HIDE"/>
+  <int value="6" label="HIDING"/>
+  <int value="7" label="HIDDEN"/>
+</enum>
+
 <enum name="VirtualKeyboardControllerStateTransition">
   <int value="-7007" label="Invalid_HIDDEN_to_HIDDEN"/>
   <int value="-7006" label="Invalid_HIDDEN_to_HIDING"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 0969b6d..f0f604f 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -65120,6 +65120,25 @@
   </summary>
 </histogram>
 
+<histogram base="true" name="SafeBrowsing.WebSocket.Elapsed" units="ms">
+  <owner>ricea@chromium.org</owner>
+  <summary>
+    Time spent on SafeBrowsing lookup. Since this includes any time spent on the
+    interstitial page the average may not be useful.
+  </summary>
+</histogram>
+
+<histogram name="SafeBrowsing.WebSocket.Result"
+    enum="SafeBrowsingWebSocketResult">
+  <owner>ricea@chromium.org</owner>
+  <summary>
+    Results of a SafeBrowsing lookup for a WebSocket handshake. All lookups are
+    counted. Note: the &quot;ABANDONED&quot; bucket contains both connections
+    that were abandoned before the check completed and those that were cancelled
+    when the user navigated away from the SafeBrowsing interstitial.
+  </summary>
+</histogram>
+
 <histogram name="SB.BloomFilter" units="ms">
   <obsolete>
     Has not been generated for years (7/8/14).
@@ -84147,6 +84166,15 @@
   </summary>
 </histogram>
 
+<histogram name="VirtualKeyboard.LingeringIntermediateState"
+    enum="VirtualKeyboardControllerState">
+  <owner>oka@chromium.org</owner>
+  <summary>
+    Records whenever an intermediate keyboard state has been active for longer
+    than a fixed timeout.
+  </summary>
+</histogram>
+
 <histogram name="VoiceInteraction.IllegalContextRequest" enum="BooleanHit">
   <owner>muyuanli@chromium.org</owner>
   <summary>
@@ -97630,6 +97658,17 @@
   <affected-histogram name="SafeBrowsing.Pref.Scout.SetPref"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="SafeBrowsingWebSocketElapsed" separator=".">
+  <suffix name="Safe"
+      label="Passed SafeBrowsing check, or blocked and interstitial clicked
+             through"/>
+  <suffix name="Blocked" label="Failed SafeBrowsing check and blocked"/>
+  <suffix name="Abandoned"
+      label="Connection abandoned, or interstitial displayed and user did not
+             proceed to site"/>
+  <affected-histogram name="SafeBrowsing.WebSocket.Elapsed"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="SameVersionStartupCounts" separator=".">
   <suffix name="1" label="1st startup with same version"/>
   <suffix name="2" label="2nd startup with same version"/>
diff --git a/ui/android/java/src/org/chromium/ui/base/LocalizationUtils.java b/ui/android/java/src/org/chromium/ui/base/LocalizationUtils.java
index 17e816c..79d5ee4 100644
--- a/ui/android/java/src/org/chromium/ui/base/LocalizationUtils.java
+++ b/ui/android/java/src/org/chromium/ui/base/LocalizationUtils.java
@@ -9,6 +9,7 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ContextUtils;
+import org.chromium.base.LocaleUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
@@ -76,5 +77,9 @@
         return nativeGetFirstStrongCharacterDirection(string);
     }
 
+    public static String substituteLocalePlaceholder(String str) {
+        return str.replace("$LOCALE", LocaleUtils.getDefaultLocaleString().replace('-', '_'));
+    }
+
     private static native int nativeGetFirstStrongCharacterDirection(String string);
 }
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn
index 465478a..decacef 100644
--- a/ui/app_list/BUILD.gn
+++ b/ui/app_list/BUILD.gn
@@ -283,6 +283,7 @@
       "views/search_result_answer_card_view_unittest.cc",
       "views/search_result_list_view_unittest.cc",
       "views/search_result_page_view_unittest.cc",
+      "views/search_result_tile_item_list_view_unittest.cc",
       "views/speech_view_unittest.cc",
       "views/test/apps_grid_view_test_api.cc",
       "views/test/apps_grid_view_test_api.h",
diff --git a/ui/app_list/app_list_features.cc b/ui/app_list/app_list_features.cc
index 8efda32..a9c17bc 100644
--- a/ui/app_list/app_list_features.cc
+++ b/ui/app_list/app_list_features.cc
@@ -43,9 +43,8 @@
 }
 
 bool IsPlayStoreAppSearchEnabled() {
-  static const bool enabled =
-      base::FeatureList::IsEnabled(kEnablePlayStoreAppSearch);
-  return enabled;
+  // Not using local static variable to allow tests to change this value.
+  return base::FeatureList::IsEnabled(kEnablePlayStoreAppSearch);
 }
 
 int AnswerCardMaxWidth() {
diff --git a/ui/app_list/app_list_features.h b/ui/app_list/app_list_features.h
index 8be6a67..2cda419 100644
--- a/ui/app_list/app_list_features.h
+++ b/ui/app_list/app_list_features.h
@@ -28,6 +28,9 @@
 // Enables the fullscreen app list.
 APP_LIST_EXPORT extern const base::Feature kEnableFullscreenAppList;
 
+// Enables the Play Store app search.
+APP_LIST_EXPORT extern const base::Feature kEnablePlayStoreAppSearch;
+
 bool APP_LIST_EXPORT IsAnswerCardEnabled();
 bool APP_LIST_EXPORT IsAnswerCardDarkRunEnabled();
 bool APP_LIST_EXPORT IsFullscreenAppListEnabled();
diff --git a/ui/app_list/test/app_list_test_view_delegate.h b/ui/app_list/test/app_list_test_view_delegate.h
index d3d73afb..709403a5 100644
--- a/ui/app_list/test/app_list_test_view_delegate.h
+++ b/ui/app_list/test/app_list_test_view_delegate.h
@@ -31,7 +31,7 @@
 
   int dismiss_count() { return dismiss_count_; }
   int open_search_result_count() { return open_search_result_count_; }
-  std::map<size_t, int> open_search_result_counts() {
+  std::map<size_t, int>& open_search_result_counts() {
     return open_search_result_counts_;
   }
 
diff --git a/ui/app_list/views/search_result_answer_card_view_unittest.cc b/ui/app_list/views/search_result_answer_card_view_unittest.cc
index e116cf3..ff0101f 100644
--- a/ui/app_list/views/search_result_answer_card_view_unittest.cc
+++ b/ui/app_list/views/search_result_answer_card_view_unittest.cc
@@ -61,6 +61,7 @@
   }
 
   int GetOpenResultCountAndReset(int ranking) {
+    EXPECT_GT(view_delegate_.open_search_result_counts().count(ranking), 0u);
     int result = view_delegate_.open_search_result_counts()[ranking];
     view_delegate_.open_search_result_counts().clear();
     return result;
diff --git a/ui/app_list/views/search_result_list_view_unittest.cc b/ui/app_list/views/search_result_list_view_unittest.cc
index e3bd06b3..f94872e 100644
--- a/ui/app_list/views/search_result_list_view_unittest.cc
+++ b/ui/app_list/views/search_result_list_view_unittest.cc
@@ -78,6 +78,7 @@
   }
 
   int GetOpenResultCountAndReset(int ranking) {
+    EXPECT_GT(view_delegate_.open_search_result_counts().count(ranking), 0u);
     int result = view_delegate_.open_search_result_counts()[ranking];
     view_delegate_.open_search_result_counts().clear();
     return result;
diff --git a/ui/app_list/views/search_result_tile_item_list_view.cc b/ui/app_list/views/search_result_tile_item_list_view.cc
index ae0cba3..35dd2a1 100644
--- a/ui/app_list/views/search_result_tile_item_list_view.cc
+++ b/ui/app_list/views/search_result_tile_item_list_view.cc
@@ -169,7 +169,12 @@
 }
 
 bool SearchResultTileItemListView::OnKeyPressed(const ui::KeyEvent& event) {
-  if (selected_index() >= 0 && child_at(selected_index())->OnKeyPressed(event))
+  int selection_index = selected_index();
+  // Also count the separator when Play Store app search feature is enabled.
+  const int child_index = is_play_store_app_search_enabled_
+                              ? selection_index * 2 + 1
+                              : selection_index;
+  if (selection_index >= 0 && child_at(child_index)->OnKeyPressed(event))
     return true;
 
   int dir = 0;
@@ -204,7 +209,7 @@
   if (dir == 0)
     return false;
 
-  int selection_index = selected_index() + dir;
+  selection_index = selection_index + dir;
   if (IsValidSelectionIndex(selection_index)) {
     SetSelectedIndex(selection_index);
     return true;
diff --git a/ui/app_list/views/search_result_tile_item_list_view_unittest.cc b/ui/app_list/views/search_result_tile_item_list_view_unittest.cc
new file mode 100644
index 0000000..e70252d9
--- /dev/null
+++ b/ui/app_list/views/search_result_tile_item_list_view_unittest.cc
@@ -0,0 +1,172 @@
+// 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/app_list/views/search_result_tile_item_list_view.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/app_list/app_list_features.h"
+#include "ui/app_list/app_list_model.h"
+#include "ui/app_list/test/app_list_test_view_delegate.h"
+#include "ui/app_list/test/test_search_result.h"
+#include "ui/app_list/views/search_result_list_view_delegate.h"
+#include "ui/app_list/views/search_result_view.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/test/views_test_base.h"
+
+namespace app_list {
+
+namespace {
+constexpr int kNumSearchResultTiles = 8;
+// Constants when the Play Store app search feature is enabled.
+constexpr int kMaxNumSearchResultTiles = 6;
+constexpr int kInstalledApps = 4;
+constexpr int kPlayStoreApps = 2;
+}  // namespace
+
+class SearchResultTileItemListViewTest
+    : public views::ViewsTestBase,
+      public ::testing::WithParamInterface<bool> {
+ public:
+  SearchResultTileItemListViewTest() {}
+  ~SearchResultTileItemListViewTest() override {}
+
+ protected:
+  void CreateSearchResultTileItemListView() {
+    // Switches on/off the Play Store app search feature.
+    if (IsPlayStoreAppSearchEnabled()) {
+      scoped_feature_list_.InitAndEnableFeature(
+          app_list::features::kEnablePlayStoreAppSearch);
+    } else {
+      scoped_feature_list_.InitAndDisableFeature(
+          app_list::features::kEnablePlayStoreAppSearch);
+    }
+    EXPECT_EQ(IsPlayStoreAppSearchEnabled(),
+              features::IsPlayStoreAppSearchEnabled());
+
+    // Sets up the views.
+    textfield_ = base::MakeUnique<views::Textfield>();
+    view_ = base::MakeUnique<SearchResultTileItemListView>(textfield_.get(),
+                                                           &view_delegate_);
+    view_->SetResults(view_delegate_.GetModel()->results());
+  }
+
+  bool IsPlayStoreAppSearchEnabled() const { return GetParam(); }
+
+  SearchResultTileItemListView* view() { return view_.get(); }
+
+  AppListModel::SearchResults* GetResults() {
+    return view_delegate_.GetModel()->results();
+  }
+
+  void SetUpSearchResults() {
+    AppListModel::SearchResults* results = GetResults();
+
+    // Populate results for installed applications.
+    for (int i = 0; i < kInstalledApps; ++i) {
+      std::unique_ptr<TestSearchResult> result =
+          base::MakeUnique<TestSearchResult>();
+      result->set_display_type(SearchResult::DISPLAY_TILE);
+      result->set_result_type(SearchResult::RESULT_INSTALLED_APP);
+      result->set_title(
+          base::UTF8ToUTF16(base::StringPrintf("InstalledApp %d", i)));
+      results->Add(std::move(result));
+    }
+
+    // Populate results for Play Store search applications.
+    if (IsPlayStoreAppSearchEnabled()) {
+      for (int i = 0; i < kPlayStoreApps; ++i) {
+        std::unique_ptr<TestSearchResult> result =
+            base::MakeUnique<TestSearchResult>();
+        result->set_display_type(SearchResult::DISPLAY_TILE);
+        result->set_result_type(SearchResult::RESULT_PLAYSTORE_APP);
+        result->set_title(
+            base::UTF8ToUTF16(base::StringPrintf("PlayStoreApp %d", i)));
+        results->Add(std::move(result));
+      }
+    }
+
+    // Adding results calls SearchResultContainerView::ScheduleUpdate().
+    // It will post a delayed task to update the results and relayout.
+    RunPendingMessages();
+    view_->OnContainerSelected(false, false);
+  }
+
+  int GetOpenResultCount(int ranking) {
+    int result = view_delegate_.open_search_result_counts()[ranking];
+    return result;
+  }
+
+  void ResetOpenResultCount() {
+    view_delegate_.open_search_result_counts().clear();
+  }
+
+  int GetResultCount() const { return view_->num_results(); }
+
+  int GetSelectedIndex() const { return view_->selected_index(); }
+
+  void ResetSelectedIndex() const { view_->SetSelectedIndex(0); }
+
+  bool KeyPress(ui::KeyboardCode key_code) {
+    ui::KeyEvent event(ui::ET_KEY_PRESSED, key_code, ui::EF_NONE);
+    return view_->OnKeyPressed(event);
+  }
+
+ private:
+  test::AppListTestViewDelegate view_delegate_;
+  std::unique_ptr<SearchResultTileItemListView> view_;
+  std::unique_ptr<views::Textfield> textfield_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(SearchResultTileItemListViewTest);
+};
+
+TEST_P(SearchResultTileItemListViewTest, Basic) {
+  CreateSearchResultTileItemListView();
+  SetUpSearchResults();
+
+  const int results = GetResultCount();
+  const int expected_results = IsPlayStoreAppSearchEnabled()
+                                   ? kInstalledApps + kPlayStoreApps
+                                   : kInstalledApps;
+  EXPECT_EQ(expected_results, results);
+  // When the Play Store app search feature is enabled, for each results,
+  // we added a separator for result type grouping.
+  const int expected_child_count = IsPlayStoreAppSearchEnabled()
+                                       ? kMaxNumSearchResultTiles * 2
+                                       : kNumSearchResultTiles;
+  EXPECT_EQ(expected_child_count, view()->child_count());
+
+  // Tests item indexing by pressing TAB.
+  for (int i = 1; i < results; ++i) {
+    EXPECT_TRUE(KeyPress(ui::VKEY_TAB));
+    EXPECT_EQ(i, GetSelectedIndex());
+  }
+
+  // Extra TAB events won't be handled by the view.
+  EXPECT_FALSE(KeyPress(ui::VKEY_TAB));
+  EXPECT_EQ(results - 1, GetSelectedIndex());
+
+  // Tests app opening.
+  ResetSelectedIndex();
+  ResetOpenResultCount();
+  for (int i = 1; i < results; ++i) {
+    EXPECT_TRUE(KeyPress(ui::VKEY_TAB));
+    EXPECT_EQ(i, GetSelectedIndex());
+    for (int j = 0; j < i; j++)
+      EXPECT_TRUE(KeyPress(ui::VKEY_RETURN));
+    EXPECT_EQ(i, GetOpenResultCount(i));
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(, SearchResultTileItemListViewTest, testing::Bool());
+
+}  // namespace app_list
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc
index 5a6c21fb..fb095fc 100644
--- a/ui/keyboard/keyboard_controller.cc
+++ b/ui/keyboard/keyboard_controller.cc
@@ -47,6 +47,10 @@
 // The virtual keyboard show/hide animation duration.
 constexpr int kAnimationDurationMs = 100;
 
+// Reports an error histogram if the keyboard state is lingering in an
+// intermediate state for more than 5 seconds.
+constexpr int kReportLingeringStateDelayMs = 5000;
+
 // The opacity of virtual keyboard container when show animation starts or
 // hide animation finishes. This cannot be zero because we call Show() on the
 // keyboard window before setting the opacity back to 1.0. Since windows are not
@@ -220,6 +224,8 @@
       return "HIDDEN";
     case keyboard::KeyboardControllerState::INITIAL:
       return "INITIAL";
+    case keyboard::KeyboardControllerState::COUNT:
+      NOTREACHED();
   }
   NOTREACHED() << "Unknownstate: " << static_cast<int>(state);
   // Needed for windows build.
@@ -285,7 +291,8 @@
       keyboard_locked_(false),
       keyboard_mode_(FULL_WIDTH),
       state_(KeyboardControllerState::UNKNOWN),
-      weak_factory_(this) {
+      weak_factory_report_lingering_state_(this),
+      weak_factory_will_hide_(this) {
   ui_->GetInputMethod()->AddObserver(this);
   ui_->SetController(this);
   ChangeState(KeyboardControllerState::INITIAL);
@@ -401,7 +408,8 @@
     // Do nothing if keyboard is already hidden or being hidden.
     return;
   }
-  weak_factory_.InvalidateWeakPtrs();
+
+  weak_factory_will_hide_.InvalidateWeakPtrs();
   keyboard_visible_ = false;
   ToggleTouchEventLogging(true);
 
@@ -560,7 +568,8 @@
       base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
           FROM_HERE,
           base::Bind(&KeyboardController::HideKeyboard,
-                     weak_factory_.GetWeakPtr(), HIDE_REASON_AUTOMATIC),
+                     weak_factory_will_hide_.GetWeakPtr(),
+                     HIDE_REASON_AUTOMATIC),
           base::TimeDelta::FromMilliseconds(kHideKeyboardDelayMs));
       if (state_ == KeyboardControllerState::LOADING_EXTENSION) {
         show_on_resize_ = false;
@@ -577,7 +586,7 @@
       // Investigate why, and enable the DCHECK below.
       // DCHECK(state_ == KeyboardControllerState::WILL_HIDE) <<
       // StateToStr(state_);
-      weak_factory_.InvalidateWeakPtrs();
+      weak_factory_will_hide_.InvalidateWeakPtrs();
       keyboard_visible_ = true;
       ChangeState(KeyboardControllerState::SHOWN);
     }
@@ -653,7 +662,7 @@
   if (!WillHideKeyboard()) {
     keyboard::LogKeyboardControlEvent(keyboard::KEYBOARD_CONTROL_SHOW);
   } else {
-    weak_factory_.InvalidateWeakPtrs();
+    weak_factory_will_hide_.InvalidateWeakPtrs();
   }
 
   // If |container_| has hide animation, its visibility is set to false when
@@ -722,7 +731,7 @@
 }
 
 bool KeyboardController::WillHideKeyboard() const {
-  return weak_factory_.HasWeakPtrs();
+  return weak_factory_will_hide_.HasWeakPtrs();
 }
 
 void KeyboardController::ShowAnimationFinished() {
@@ -787,9 +796,35 @@
 
 void KeyboardController::ChangeState(KeyboardControllerState state) {
   CheckStateTransition(state_, state);
+  if (state_ == state)
+    return;
+
   state_ = state;
   for (KeyboardControllerObserver& observer : observer_list_)
     observer.OnStateChanged(state);
+
+  weak_factory_report_lingering_state_.InvalidateWeakPtrs();
+
+  switch (state_) {
+    case KeyboardControllerState::LOADING_EXTENSION:
+    case KeyboardControllerState::WILL_HIDE:
+    case KeyboardControllerState::HIDING:
+    case KeyboardControllerState::SHOWING:
+      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+          FROM_HERE,
+          base::Bind(&KeyboardController::ReportLingeringState,
+                     weak_factory_report_lingering_state_.GetWeakPtr()),
+          base::TimeDelta::FromMilliseconds(kReportLingeringStateDelayMs));
+      break;
+    default:
+      // Do nothing
+      break;
+  }
+}
+
+void KeyboardController::ReportLingeringState() {
+  UMA_HISTOGRAM_ENUMERATION("VirtualKeyboard.LingeringIntermediateState",
+                            state_, KeyboardControllerState::COUNT);
 }
 
 }  // namespace keyboard
diff --git a/ui/keyboard/keyboard_controller.h b/ui/keyboard/keyboard_controller.h
index c3d5d29f..c361b5d 100644
--- a/ui/keyboard/keyboard_controller.h
+++ b/ui/keyboard/keyboard_controller.h
@@ -47,7 +47,8 @@
 
 // Represents the current state of the keyboard managed by the controller.
 // Don't change the numeric value of the members because they are used in UMA
-// VirtualKeyboard.ControllerStateTransition.
+// - VirtualKeyboard.ControllerStateTransition.
+// - VirtualKeyboard.LingeringIntermediateState
 enum class KeyboardControllerState {
   UNKNOWN = 0,
   // Keyboard has never been shown.
@@ -66,6 +67,7 @@
   HIDING = 6,
   // Keyboard is hidden, but has shown at least once.
   HIDDEN = 7,
+  COUNT,
 };
 
 // Provides control of the virtual keyboard, including providing a container
@@ -208,9 +210,13 @@
   // Validates the state transition. Called from ChangeState.
   void CheckStateTransition(KeyboardControllerState prev,
                             KeyboardControllerState next);
+
   // Changes the current state with validating the transition.
   void ChangeState(KeyboardControllerState state);
 
+  // Reports error histogram in case lingering in an intermediate state.
+  void ReportLingeringState();
+
   std::unique_ptr<KeyboardUI> ui_;
   KeyboardLayoutDelegate* layout_delegate_;
   std::unique_ptr<aura::Window> container_;
@@ -236,7 +242,8 @@
 
   static KeyboardController* instance_;
 
-  base::WeakPtrFactory<KeyboardController> weak_factory_;
+  base::WeakPtrFactory<KeyboardController> weak_factory_report_lingering_state_;
+  base::WeakPtrFactory<KeyboardController> weak_factory_will_hide_;
 
   DISALLOW_COPY_AND_ASSIGN(KeyboardController);
 };