diff --git a/DEPS b/DEPS
index 54f5ae9..b5218cd 100644
--- a/DEPS
+++ b/DEPS
@@ -111,7 +111,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': '180125176f24283cfb0fdb62999949445ab4db5b',
+  'catapult_revision': '6f19655f67942d3b13000fdc157ddcf914186e7b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -198,7 +198,7 @@
   },
 
   'src/ios/third_party/ochamcrest/src': {
-      'url': Var('chromium_git') + '/external/github.com/hamcrest/OCHamcrest.git' + '@' + 'd7ee4ecfb6bd13c3c8d364682b6228ccd86e1e1a',
+      'url': Var('chromium_git') + '/external/github.com/hamcrest/OCHamcrest.git' + '@' + '92d9c14d13bb864255e65c09383564653896916b',
       'condition': 'checkout_ios',
   },
 
@@ -251,7 +251,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '66814c3bbbd2068dd34af9df2f677316bf081752',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '85c606aae820e29d6ccfa5589af365536eaf9ad1',
       'condition': 'checkout_linux',
   },
 
@@ -279,7 +279,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9f20d020855c8ee87ba64d53ef94051c06aab860',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '7de54ef0a25f546747ea9f2a536d5cb175abc566',
 
   # DevTools node modules. Used on Linux buildbots only.
   'src/third_party/devtools-node-modules': {
@@ -301,7 +301,7 @@
   },
 
   'src/third_party/ffmpeg':
-    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '62ff55193a061c21c039a2ba0b39641136912c2e',
+    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '3098b6a24547c66d20ffd8448f6a719f41f87b95',
 
   'src/third_party/findbugs': {
       'url': Var('chromium_git') + '/chromium/deps/findbugs.git' + '@' + '57f05238d3ac77ea0a194813d3065dd780c6e566',
@@ -425,7 +425,7 @@
   },
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  'fe7b869104806752a26a262dc60923639d9a384f',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  'caa116c9be96508c18d533dedc95b2df4f8e3812',
 
   'src/third_party/libwebm/source':
     Var('chromium_git') + '/webm/libwebm.git' + '@' + '4956b2dec65352af32dc71bab553acb631c64177',
diff --git a/android_webview/browser/aw_metrics_log_uploader.cc b/android_webview/browser/aw_metrics_log_uploader.cc
index c79eeb1..bb2c213 100644
--- a/android_webview/browser/aw_metrics_log_uploader.cc
+++ b/android_webview/browser/aw_metrics_log_uploader.cc
@@ -19,8 +19,10 @@
 
 AwMetricsLogUploader::~AwMetricsLogUploader() {}
 
-void AwMetricsLogUploader::UploadLog(const std::string& compressed_log_data,
-                                     const std::string& log_hash) {
+void AwMetricsLogUploader::UploadLog(
+    const std::string& compressed_log_data,
+    const std::string& log_hash,
+    const metrics::ReportingInfo& reporting_info) {
   // WebView uses the platform logging mechanism instead of the normal UMA
   // server. The platform mechanism does its own compression, so undo the
   // previous compression.
diff --git a/android_webview/browser/aw_metrics_log_uploader.h b/android_webview/browser/aw_metrics_log_uploader.h
index 91dabde..0f54732 100644
--- a/android_webview/browser/aw_metrics_log_uploader.h
+++ b/android_webview/browser/aw_metrics_log_uploader.h
@@ -22,7 +22,8 @@
 
   // ::metrics::MetricsLogUploader:
   void UploadLog(const std::string& compressed_log_data,
-                 const std::string& log_hash) override;
+                 const std::string& log_hash,
+                 const metrics::ReportingInfo& reporting_info) override;
 
  private:
   const metrics::MetricsLogUploader::UploadCallback on_upload_complete_;
diff --git a/android_webview/java/src/org/chromium/android_webview/AwSafeBrowsingConfigHelper.java b/android_webview/java/src/org/chromium/android_webview/AwSafeBrowsingConfigHelper.java
index 6bacd361..4edd089 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwSafeBrowsingConfigHelper.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwSafeBrowsingConfigHelper.java
@@ -31,6 +31,8 @@
     public static void maybeInitSafeBrowsingFromSettings(final Context appContext) {
         AwContentsStatics.setSafeBrowsingEnabledByManifest(
                 CommandLine.getInstance().hasSwitch(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
+                || CommandLine.getInstance().hasSwitch(
+                           AwSwitches.WEBVIEW_SAFEBROWSING_BLOCK_ALL_RESOURCES)
                 || appHasOptedIn(appContext));
         // If GMS is available, we will figure out if the user has opted-in to Safe Browsing and set
         // the correct value for sSafeBrowsingUserOptIn.
diff --git a/android_webview/java/src/org/chromium/android_webview/AwSwitches.java b/android_webview/java/src/org/chromium/android_webview/AwSwitches.java
index 77b37c4..48c76d2 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwSwitches.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwSwitches.java
@@ -18,6 +18,12 @@
     public static final String WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT =
             "webview-enable-safebrowsing-support";
 
+    // Enables SafeBrowsing and causes WebView to treat all resources as malicious. Use care: this
+    // will block all resources from loading.
+    // No native switch.
+    public static final String WEBVIEW_SAFEBROWSING_BLOCK_ALL_RESOURCES =
+            "webview-safebrowsing-block-all-resources";
+
     // Enables variations AB testing experiments in webview.
     // Native switch kEnableWebViewVariations.
     public static final String ENABLE_WEBVIEW_VARIATIONS = "enable-webview-variations";
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 65beaf4..029570b 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -508,6 +508,8 @@
     "system/palette/palette_tray.h",
     "system/palette/palette_utils.cc",
     "system/palette/palette_utils.h",
+    "system/palette/palette_welcome_bubble.cc",
+    "system/palette/palette_welcome_bubble.h",
     "system/palette/tools/capture_region_mode.cc",
     "system/palette/tools/capture_region_mode.h",
     "system/palette/tools/capture_screen_action.cc",
@@ -1332,6 +1334,7 @@
     "system/palette/mock_palette_tool_delegate.h",
     "system/palette/palette_tool_manager_unittest.cc",
     "system/palette/palette_tray_unittest.cc",
+    "system/palette/palette_welcome_bubble_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/ash_strings.grd b/ash/ash_strings.grd
index b0d0290..135d0b8 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -463,6 +463,12 @@
       <message name="IDS_ASH_STYLUS_TOOLS_TITLE" desc="The title of the stylus tools dialog in the ash shelf.">
         Stylus tools
       </message>
+      <message name="IDS_ASH_STYLUS_WARM_WELCOME_BUBBLE_TITLE" desc="The title of the bubble that pops up the first time a user uses a stylus.">
+        These are your stylus tools
+      </message>
+      <message name="IDS_ASH_STYLUS_WARM_WELCOME_BUBBLE_DESCRIPTION" desc="The description of the bubble that pops up the first time a user uses a stylus. Describes what tools exist in the palette tray.">
+        Tap the stylus button on the shelf to take a note, screenshot, use the assistant, laser pointer, or magnifying glass.
+      </message>
       <message name="IDS_ASH_PALETTE_SETTINGS" desc="The label on the setting button used to open palette setting page.">
         Stylus settings
       </message>
diff --git a/ash/public/cpp/ash_pref_names.cc b/ash/public/cpp/ash_pref_names.cc
index ec855427..78a9c51 100644
--- a/ash/public/cpp/ash_pref_names.cc
+++ b/ash/public/cpp/ash_pref_names.cc
@@ -69,6 +69,9 @@
 
 // A boolean pref which stores whether a stylus has been seen before.
 const char kHasSeenStylus[] = "ash.has_seen_stylus";
+// A boolean pref which stores whether a the palette warm welcome bubble
+// (displayed when a user first uses a stylus) has been shown before.
+const char kShownPaletteWelcomeBubble[] = "ash.shown_palette_welcome_bubble";
 
 // A boolean pref storing the enabled status of the NightLight feature.
 const char kNightLightEnabled[] = "ash.night_light.enabled";
diff --git a/ash/public/cpp/ash_pref_names.h b/ash/public/cpp/ash_pref_names.h
index dac71eb2..d36930a5 100644
--- a/ash/public/cpp/ash_pref_names.h
+++ b/ash/public/cpp/ash_pref_names.h
@@ -31,6 +31,7 @@
 ASH_PUBLIC_EXPORT extern const char kShouldAlwaysShowAccessibilityMenu[];
 
 ASH_PUBLIC_EXPORT extern const char kHasSeenStylus[];
+ASH_PUBLIC_EXPORT extern const char kShownPaletteWelcomeBubble[];
 
 ASH_PUBLIC_EXPORT extern const char kNightLightEnabled[];
 ASH_PUBLIC_EXPORT extern const char kNightLightTemperature[];
diff --git a/ash/shell.cc b/ash/shell.cc
index 863a9a8..bd40417 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -81,6 +81,7 @@
 #include "ash/system/network/vpn_list.h"
 #include "ash/system/night_light/night_light_controller.h"
 #include "ash/system/palette/palette_tray.h"
+#include "ash/system/palette/palette_welcome_bubble.h"
 #include "ash/system/power/peripheral_battery_notifier.h"
 #include "ash/system/power/power_button_controller.h"
 #include "ash/system/power/power_event_observer.h"
@@ -344,13 +345,14 @@
 // static
 void Shell::RegisterProfilePrefs(PrefRegistrySimple* registry, bool for_test) {
   AccessibilityController::RegisterProfilePrefs(registry, for_test);
-  LogoutButtonTray::RegisterProfilePrefs(registry);
-  NightLightController::RegisterProfilePrefs(registry);
-  ShelfController::RegisterProfilePrefs(registry);
-  TrayCapsLock::RegisterProfilePrefs(registry, for_test);
   BluetoothPowerController::RegisterProfilePrefs(registry);
   LockScreenController::RegisterProfilePrefs(registry, for_test);
+  LogoutButtonTray::RegisterProfilePrefs(registry);
+  NightLightController::RegisterProfilePrefs(registry);
+  PaletteWelcomeBubble::RegisterProfilePrefs(registry);
+  ShelfController::RegisterProfilePrefs(registry);
   TouchDevicesController::RegisterProfilePrefs(registry);
+  TrayCapsLock::RegisterProfilePrefs(registry, for_test);
 }
 
 views::NonClientFrameView* Shell::CreateDefaultNonClientFrameView(
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc
index 2ec0790..3437da1 100644
--- a/ash/system/palette/palette_tray.cc
+++ b/ash/system/palette/palette_tray.cc
@@ -19,6 +19,7 @@
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/palette/palette_tool_manager.h"
 #include "ash/system/palette/palette_utils.h"
+#include "ash/system/palette/palette_welcome_bubble.h"
 #include "ash/system/tray/system_menu_button.h"
 #include "ash/system/tray/system_tray_controller.h"
 #include "ash/system/tray/tray_bubble_wrapper.h"
@@ -144,7 +145,7 @@
 // StylusWatcher is used to monitor for stylus events, since we only want to
 // make the palette tray visible for devices without internal styluses once they
 // start using the stylus.
-class PaletteTray::StylusWatcher : views::PointerWatcher {
+class PaletteTray::StylusWatcher : public views::PointerWatcher {
  public:
   explicit StylusWatcher(PrefService* pref_service)
       : local_state_pref_service_(pref_service) {
@@ -174,6 +175,7 @@
 PaletteTray::PaletteTray(Shelf* shelf)
     : TrayBackgroundView(shelf),
       palette_tool_manager_(new PaletteToolManager(this)),
+      welcome_bubble_(std::make_unique<PaletteWelcomeBubble>(this)),
       scoped_session_observer_(this),
       weak_factory_(this) {
   PaletteTool::RegisterToolInstances(palette_tool_manager_.get());
@@ -290,6 +292,11 @@
     } else if (stylus_state == ui::StylusState::INSERTED && bubble_) {
       HidePalette();
     }
+  } else if (stylus_state == ui::StylusState::REMOVED) {
+    // Show the palette welcome bubble if the auto open palette setting is not
+    // turned on, if the bubble has not been shown before (|welcome_bubble_|
+    // will be nullptr if the bubble has been shown before).
+    welcome_bubble_->ShowIfNeeded();
   }
 
   // Disable any active modes if the stylus has been inserted.
diff --git a/ash/system/palette/palette_tray.h b/ash/system/palette/palette_tray.h
index 88d0eddc..05d7302a 100644
--- a/ash/system/palette/palette_tray.h
+++ b/ash/system/palette/palette_tray.h
@@ -32,6 +32,7 @@
 namespace ash {
 
 class PaletteToolManager;
+class PaletteWelcomeBubble;
 class TrayBubbleWrapper;
 
 // The PaletteTray shows the palette in the bottom area of the screen. This
@@ -45,6 +46,7 @@
                                public ui::InputDeviceEventObserver {
  public:
   // For testing.
+  // TODO(crbug.com/774166): Move this to class to its own file.
   class TestApi {
    public:
     explicit TestApi(PaletteTray* palette_tray);
@@ -54,6 +56,10 @@
       return palette_tray_->palette_tool_manager_.get();
     }
 
+    PaletteWelcomeBubble* GetWelcomeBubble() {
+      return palette_tray_->welcome_bubble_.get();
+    }
+
     TrayBubbleWrapper* GetTrayBubbleWrapper() {
       return palette_tray_->bubble_.get();
     }
@@ -135,6 +141,7 @@
   bool DeactivateActiveTool();
 
   std::unique_ptr<PaletteToolManager> palette_tool_manager_;
+  std::unique_ptr<PaletteWelcomeBubble> welcome_bubble_;
   std::unique_ptr<TrayBubbleWrapper> bubble_;
   std::unique_ptr<StylusWatcher> watcher_;
 
diff --git a/ash/system/palette/palette_tray_unittest.cc b/ash/system/palette/palette_tray_unittest.cc
index e8edf38..2d92220 100644
--- a/ash/system/palette/palette_tray_unittest.cc
+++ b/ash/system/palette/palette_tray_unittest.cc
@@ -13,10 +13,12 @@
 #include "ash/public/cpp/config.h"
 #include "ash/public/cpp/stylus_utils.h"
 #include "ash/public/cpp/voice_interaction_state.h"
+#include "ash/session/session_controller.h"
 #include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/shell_test_api.h"
 #include "ash/system/palette/palette_utils.h"
+#include "ash/system/palette/palette_welcome_bubble.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"
@@ -30,8 +32,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/session_manager/session_manager_types.h"
 #include "ui/events/base_event_utils.h"
-#include "ui/events/devices/device_data_manager.h"
-#include "ui/events/devices/touchscreen_device.h"
 #include "ui/events/event.h"
 #include "ui/events/test/device_data_manager_test_api.h"
 #include "ui/events/test/event_generator.h"
@@ -43,6 +43,22 @@
   PaletteTrayTest() {}
   ~PaletteTrayTest() override {}
 
+  // 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);
+  }
+
+  // Fake a stylus ejection. Note: this will fail in mus or mash because
+  // DeviceDataManager is not created. See crbug.com/734812.
+  void EjectStylus() {
+    ui::test::DeviceDataManagerTestAPI devices_test_api;
+    devices_test_api.NotifyObserversStylusStateChanged(
+        ui::StylusState::REMOVED);
+  }
+
+  // AshTestBase:
   void SetUp() override {
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kAshEnablePaletteOnAllDisplays);
@@ -64,19 +80,16 @@
     palette_tray_->Initialize();
   }
 
-  // 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:
   TestPaletteDelegate* test_palette_delegate() {
     return static_cast<TestPaletteDelegate*>(Shell::Get()->palette_delegate());
   }
 
-  PrefService* pref_service() {
+  PrefService* active_user_pref_service() {
+    return Shell::Get()->session_controller()->GetActivePrefService();
+  }
+
+  PrefService* local_state_pref_service() {
     return Shell::Get()->GetLocalStatePrefService();
   }
 
@@ -106,7 +119,7 @@
 // should become visible after seeing a stylus event.
 TEST_F(PaletteTrayTest, PaletteTrayVisibleAfterStylusSeen) {
   ASSERT_FALSE(palette_tray_->visible());
-  ASSERT_FALSE(pref_service()->GetBoolean(prefs::kHasSeenStylus));
+  ASSERT_FALSE(local_state_pref_service()->GetBoolean(prefs::kHasSeenStylus));
   ASSERT_TRUE(test_api_->IsStylusWatcherActive());
 
   // Send a stylus event.
@@ -125,7 +138,7 @@
 // visible.
 TEST_F(PaletteTrayTest, StylusSeenPrefInitiallySet) {
   ASSERT_FALSE(palette_tray_->visible());
-  pref_service()->SetBoolean(prefs::kHasSeenStylus, true);
+  local_state_pref_service()->SetBoolean(prefs::kHasSeenStylus, true);
 
   EXPECT_TRUE(palette_tray_->visible());
   EXPECT_FALSE(test_api_->IsStylusWatcherActive());
@@ -551,4 +564,42 @@
   EXPECT_FALSE(manager->IsToolActive(PaletteToolId::LASER_POINTER));
 }
 
+// Verify the palette welcome bubble is shown the first time the stylus is
+// removed.
+TEST_F(PaletteTrayTestWithInternalStylus, WelcomeBubbleShownOnEject) {
+  test_palette_delegate()->set_should_show_palette(true);
+  ASSERT_FALSE(active_user_pref_service()->GetBoolean(
+      prefs::kShownPaletteWelcomeBubble));
+  EXPECT_FALSE(test_api_->GetWelcomeBubble()->BubbleShown());
+
+  EjectStylus();
+  EXPECT_TRUE(test_api_->GetWelcomeBubble()->BubbleShown());
+}
+
+// Verify if the pref which tracks if the welcome bubble has been shown before
+// is true, the welcome bubble is not shown when the stylus is removed.
+TEST_F(PaletteTrayTestWithInternalStylus, WelcomeBubbleNotShownIfShownBefore) {
+  test_palette_delegate()->set_should_show_palette(true);
+  active_user_pref_service()->SetBoolean(prefs::kShownPaletteWelcomeBubble,
+                                         true);
+  EXPECT_FALSE(test_api_->GetWelcomeBubble()->BubbleShown());
+
+  EjectStylus();
+  EXPECT_FALSE(test_api_->GetWelcomeBubble()->BubbleShown());
+}
+
+// Verify that the bubble does not get shown if the auto open palette setting is
+// true.
+TEST_F(PaletteTrayTestWithInternalStylus,
+       WelcomeBubbleNotShownIfAutoOpenPaletteTrue) {
+  test_palette_delegate()->set_should_show_palette(true);
+  test_palette_delegate()->set_should_auto_open_palette(true);
+  active_user_pref_service()->SetBoolean(prefs::kShownPaletteWelcomeBubble,
+                                         false);
+  EXPECT_FALSE(test_api_->GetWelcomeBubble()->BubbleShown());
+
+  EjectStylus();
+  EXPECT_FALSE(test_api_->GetWelcomeBubble()->BubbleShown());
+}
+
 }  // namespace ash
diff --git a/ash/system/palette/palette_welcome_bubble.cc b/ash/system/palette/palette_welcome_bubble.cc
new file mode 100644
index 0000000..5b9bf97d
--- /dev/null
+++ b/ash/system/palette/palette_welcome_bubble.cc
@@ -0,0 +1,178 @@
+// 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_welcome_bubble.h"
+
+#include "ash/public/cpp/ash_pref_names.h"
+#include "ash/public/cpp/shell_window_ids.h"
+#include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/session/session_controller.h"
+#include "ash/shell.h"
+#include "ash/shell_port.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "ash/system/palette/palette_tray.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "ui/aura/window.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
+
+namespace ash {
+
+// View which contains two text (one title) and a close button for closing the
+// bubble. Controlled by PaletteWelcomeBubble and anchored to a PaletteTray.
+class PaletteWelcomeBubble::WelcomeBubbleView
+    : public views::BubbleDialogDelegateView,
+      public views::ButtonListener {
+ public:
+  WelcomeBubbleView(views::View* anchor, views::BubbleBorder::Arrow arrow)
+      : views::BubbleDialogDelegateView(anchor, arrow) {
+    set_close_on_deactivate(true);
+    set_can_activate(false);
+    set_accept_events(true);
+    set_parent_window(
+        anchor_widget()->GetNativeWindow()->GetRootWindow()->GetChildById(
+            kShellWindowId_SettingBubbleContainer));
+    SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical));
+
+    // Add the header which contains the title and close button.
+    auto* header = new views::View();
+    auto* box_layout = new views::BoxLayout(views::BoxLayout::kHorizontal);
+    header->SetLayoutManager(box_layout);
+    AddChildView(header);
+
+    // Add the title, which is bolded.
+    auto* title = new views::Label(
+        l10n_util::GetStringUTF16(IDS_ASH_STYLUS_WARM_WELCOME_BUBBLE_TITLE));
+    title->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+    title->SetFontList(views::Label::GetDefaultFontList().Derive(
+        0, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::BOLD));
+    header->AddChildView(title);
+    box_layout->SetFlexForView(title, 1);
+
+    // Add a button to close the bubble.
+    close_button_ = new views::ImageButton(this);
+    close_button_->SetImage(
+        views::Button::STATE_NORMAL,
+        gfx::CreateVectorIcon(kWindowControlCloseIcon, SK_ColorBLACK));
+    header->AddChildView(close_button_);
+
+    auto* content = new views::Label(l10n_util::GetStringUTF16(
+        IDS_ASH_STYLUS_WARM_WELCOME_BUBBLE_DESCRIPTION));
+    content->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+    AddChildView(content);
+
+    views::BubbleDialogDelegateView::CreateBubble(this);
+  }
+
+  ~WelcomeBubbleView() override = default;
+
+  views::ImageButton* close_button() { return close_button_; }
+
+  // ui::BubbleDialogDelegateView:
+  int GetDialogButtons() const override { return ui::DIALOG_BUTTON_NONE; }
+
+  // views::ButtonListener:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override {
+    if (sender == close_button_)
+      GetWidget()->Close();
+  }
+
+  // views::View:
+  gfx::Size CalculatePreferredSize() const override {
+    return BubbleDialogDelegateView::CalculatePreferredSize();
+  }
+
+ private:
+  views::ImageButton* close_button_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(WelcomeBubbleView);
+};
+
+PaletteWelcomeBubble::PaletteWelcomeBubble(PaletteTray* tray) : tray_(tray) {
+  Shell::Get()->session_controller()->AddObserver(this);
+}
+
+PaletteWelcomeBubble::~PaletteWelcomeBubble() {
+  if (bubble_view_) {
+    bubble_view_->GetWidget()->RemoveObserver(this);
+    ShellPort::Get()->RemovePointerWatcher(this);
+  }
+  Shell::Get()->session_controller()->RemoveObserver(this);
+}
+
+// static
+void PaletteWelcomeBubble::RegisterProfilePrefs(PrefRegistrySimple* registry) {
+  registry->RegisterBooleanPref(prefs::kShownPaletteWelcomeBubble, false);
+}
+
+void PaletteWelcomeBubble::OnWidgetClosing(views::Widget* widget) {
+  widget->RemoveObserver(this);
+  bubble_view_ = nullptr;
+  active_user_pref_service_->SetBoolean(prefs::kShownPaletteWelcomeBubble,
+                                        true);
+  ShellPort::Get()->RemovePointerWatcher(this);
+}
+
+void PaletteWelcomeBubble::OnPointerEventObserved(
+    const ui::PointerEvent& event,
+    const gfx::Point& location_in_screen,
+    gfx::NativeView target) {
+  if (bubble_view_ &&
+      !bubble_view_->GetBoundsInScreen().Contains(location_in_screen)) {
+    bubble_view_->GetWidget()->Close();
+  }
+}
+
+void PaletteWelcomeBubble::OnActiveUserPrefServiceChanged(
+    PrefService* pref_service) {
+  active_user_pref_service_ = pref_service;
+}
+
+void PaletteWelcomeBubble::ShowIfNeeded() {
+  DCHECK(active_user_pref_service_);
+  if (!active_user_pref_service_->GetBoolean(
+          prefs::kShownPaletteWelcomeBubble) &&
+      !BubbleShown()) {
+    Show();
+  }
+}
+
+views::ImageButton* PaletteWelcomeBubble::GetCloseButtonForTest() {
+  if (bubble_view_)
+    return bubble_view_->close_button();
+
+  return nullptr;
+}
+
+base::Optional<gfx::Rect> PaletteWelcomeBubble::GetBubbleBoundsForTest() {
+  if (bubble_view_)
+    return base::make_optional(bubble_view_->GetBoundsInScreen());
+
+  return base::nullopt;
+}
+
+void PaletteWelcomeBubble::Show() {
+  if (!bubble_view_) {
+    DCHECK(tray_);
+    bubble_view_ =
+        new WelcomeBubbleView(tray_, views::BubbleBorder::BOTTOM_RIGHT);
+  }
+  bubble_view_->GetWidget()->Show();
+  bubble_view_->GetWidget()->AddObserver(this);
+  ShellPort::Get()->AddPointerWatcher(this,
+                                      views::PointerWatcherEventTypes::BASIC);
+}
+
+void PaletteWelcomeBubble::Hide() {
+  if (bubble_view_)
+    bubble_view_->GetWidget()->Close();
+}
+
+}  // namespace ash
diff --git a/ash/system/palette/palette_welcome_bubble.h b/ash/system/palette/palette_welcome_bubble.h
new file mode 100644
index 0000000..db62a12b
--- /dev/null
+++ b/ash/system/palette/palette_welcome_bubble.h
@@ -0,0 +1,80 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_SYSTEM_PALETTE_PALETTE_WELCOME_BUBBLE_H_
+#define ASH_SYSTEM_PALETTE_PALETTE_WELCOME_BUBBLE_H_
+
+#include "ash/ash_export.h"
+#include "ash/session/session_observer.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "ui/views/pointer_watcher.h"
+#include "ui/views/widget/widget_observer.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace views {
+class ImageButton;
+class Widget;
+}  // namespace views
+
+namespace ash {
+class PaletteTray;
+
+// The PaletteWelcomeBubble handles displaying a warm welcome bubble letting
+// users know about the PaletteTray the first time a stylus is ejected, or if an
+// external stylus is detected.
+class ASH_EXPORT PaletteWelcomeBubble : public SessionObserver,
+                                        public views::PointerWatcher,
+                                        public views::WidgetObserver {
+ public:
+  explicit PaletteWelcomeBubble(PaletteTray* tray);
+  ~PaletteWelcomeBubble() override;
+
+  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+  // Show the welcome bubble iff it has not been shown before.
+  void ShowIfNeeded();
+
+  bool BubbleShown() { return bubble_view_ != nullptr; }
+
+  // SessionObserver:
+  void OnActiveUserPrefServiceChanged(PrefService* pref_service) override;
+
+  // views::WidgetObserver:
+  void OnWidgetClosing(views::Widget* widget) override;
+
+  // views::PointerWatcher:
+  void OnPointerEventObserved(const ui::PointerEvent& event,
+                              const gfx::Point& location_in_screen,
+                              gfx::NativeView target) override;
+
+  // Returns the close button on the bubble if it exists.
+  views::ImageButton* GetCloseButtonForTest();
+
+  // Returns the bounds of the bubble view if it exists.
+  base::Optional<gfx::Rect> GetBubbleBoundsForTest();
+
+ private:
+  friend class PaletteWelcomeBubbleTest;
+  class WelcomeBubbleView;
+
+  void Show();
+  void Hide();
+
+  // The PaletteTray this bubble is associated with. Serves as the anchor for
+  // the bubble. Not owned.
+  PaletteTray* tray_ = nullptr;
+
+  PrefService* active_user_pref_service_ = nullptr;  // Not owned.
+
+  WelcomeBubbleView* bubble_view_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(PaletteWelcomeBubble);
+};
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_PALETTE_PALETTE_WELCOME_BUBBLE_H_
diff --git a/ash/system/palette/palette_welcome_bubble_unittest.cc b/ash/system/palette/palette_welcome_bubble_unittest.cc
new file mode 100644
index 0000000..b24506d
--- /dev/null
+++ b/ash/system/palette/palette_welcome_bubble_unittest.cc
@@ -0,0 +1,149 @@
+// 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_welcome_bubble.h"
+
+#include "ash/public/cpp/ash_pref_names.h"
+#include "ash/session/session_controller.h"
+#include "ash/session/test_session_controller_client.h"
+#include "ash/shell.h"
+#include "ash/system/palette/palette_tray.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 "components/prefs/pref_service.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/views/controls/button/image_button.h"
+
+namespace ash {
+
+namespace {
+
+constexpr char kUser1Email[] = "user1@palettewelcome.com";
+constexpr char kUser2Email[] = "user2@palettewelcome.com";
+
+}  // namespace
+
+class PaletteWelcomeBubbleTest : public AshTestBase {
+ public:
+  PaletteWelcomeBubbleTest() = default;
+  ~PaletteWelcomeBubbleTest() override = default;
+
+  PrefService* user1_pref_service() {
+    return Shell::Get()->session_controller()->GetUserPrefServiceForUser(
+        AccountId::FromUserEmail(kUser1Email));
+  }
+
+  PrefService* user2_pref_service() {
+    return Shell::Get()->session_controller()->GetUserPrefServiceForUser(
+        AccountId::FromUserEmail(kUser2Email));
+  }
+
+  void ShowBubble() { welcome_bubble_->Show(); }
+  void HideBubble() { welcome_bubble_->Hide(); }
+
+  // AshTestBase:
+  void SetUp() override {
+    AshTestBase::SetUp();
+
+    welcome_bubble_ = std::make_unique<PaletteWelcomeBubble>(
+        StatusAreaWidgetTestHelper::GetStatusAreaWidget()->palette_tray());
+    GetSessionControllerClient()->AddUserSession(kUser1Email);
+    GetSessionControllerClient()->AddUserSession(kUser2Email);
+    GetSessionControllerClient()->SwitchActiveUser(
+        AccountId::FromUserEmail(kUser1Email));
+  }
+
+  void TearDown() override {
+    welcome_bubble_.reset();
+    AshTestBase::TearDown();
+  }
+
+ protected:
+  std::unique_ptr<PaletteWelcomeBubble> welcome_bubble_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PaletteWelcomeBubbleTest);
+};
+
+// Test the basic Show/Hide functions work.
+TEST_F(PaletteWelcomeBubbleTest, Basic) {
+  EXPECT_FALSE(welcome_bubble_->BubbleShown());
+
+  ShowBubble();
+  EXPECT_TRUE(welcome_bubble_->BubbleShown());
+
+  HideBubble();
+  EXPECT_FALSE(welcome_bubble_->BubbleShown());
+
+  // Verify that the pref changes after the bubble is hidden.
+  EXPECT_TRUE(
+      user1_pref_service()->GetBoolean(prefs::kShownPaletteWelcomeBubble));
+}
+
+// Verify if the bubble has been show before, it will not be shown again.
+TEST_F(PaletteWelcomeBubbleTest, ShowIfNeeded) {
+  user1_pref_service()->SetBoolean(prefs::kShownPaletteWelcomeBubble, true);
+
+  welcome_bubble_->ShowIfNeeded();
+  EXPECT_FALSE(welcome_bubble_->BubbleShown());
+}
+
+// Verify that tapping the close button on the welcome bubble closes the bubble.
+TEST_F(PaletteWelcomeBubbleTest, CloseButton) {
+  ShowBubble();
+  ASSERT_TRUE(welcome_bubble_->BubbleShown());
+  ASSERT_TRUE(welcome_bubble_->GetCloseButtonForTest());
+
+  GetEventGenerator().set_current_location(
+      welcome_bubble_->GetCloseButtonForTest()
+          ->GetBoundsInScreen()
+          .CenterPoint());
+  GetEventGenerator().ClickLeftButton();
+  EXPECT_FALSE(welcome_bubble_->BubbleShown());
+}
+
+// Verify that tapping on the screen outside of the welcome bubble closes the
+// bubble.
+TEST_F(PaletteWelcomeBubbleTest, TapOutsideOfBubble) {
+  ShowBubble();
+  ASSERT_TRUE(welcome_bubble_->BubbleShown());
+  ASSERT_TRUE(welcome_bubble_->GetBubbleBoundsForTest().has_value());
+
+  // The bubble remains open if a tap occurs on the bubble.
+  GetEventGenerator().set_current_location(
+      welcome_bubble_->GetBubbleBoundsForTest()->CenterPoint());
+  GetEventGenerator().ClickLeftButton();
+  EXPECT_TRUE(welcome_bubble_->BubbleShown());
+
+  // Tap anywhere outside the bubble.
+  ASSERT_FALSE(
+      welcome_bubble_->GetBubbleBoundsForTest()->Contains(gfx::Point()));
+  GetEventGenerator().set_current_location(gfx::Point());
+  GetEventGenerator().ClickLeftButton();
+  EXPECT_FALSE(welcome_bubble_->BubbleShown());
+}
+
+// Verify that a second user sees the bubble even after a first user has seen it
+// already.
+TEST_F(PaletteWelcomeBubbleTest, BubbleShownForSecondUser) {
+  // Show the bubble for the first user, and verify that the pref is set when
+  // the bubble is hidden.
+  ShowBubble();
+  EXPECT_TRUE(welcome_bubble_->BubbleShown());
+  HideBubble();
+  ASSERT_TRUE(
+      user1_pref_service()->GetBoolean(prefs::kShownPaletteWelcomeBubble));
+
+  // Switch to the second user, and verify that the bubble will get shown.
+  GetSessionControllerClient()->SwitchActiveUser(
+      AccountId::FromUserEmail(kUser2Email));
+  EXPECT_FALSE(
+      user2_pref_service()->GetBoolean(prefs::kShownPaletteWelcomeBubble));
+  welcome_bubble_->ShowIfNeeded();
+  EXPECT_TRUE(welcome_bubble_->BubbleShown());
+}
+
+}  // namespace ash
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 78c04dc..a1dda89 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -294,6 +294,7 @@
     "environment.cc",
     "environment.h",
     "event_types.h",
+    "export_template.h",
     "feature_list.cc",
     "feature_list.h",
     "file_descriptor_posix.h",
@@ -467,7 +468,6 @@
     "memory/discardable_shared_memory.h",
     "memory/free_deleter.h",
     "memory/linked_ptr.h",
-    "memory/manual_constructor.h",
     "memory/memory_coordinator_client.cc",
     "memory/memory_coordinator_client.h",
     "memory/memory_coordinator_client_registry.cc",
@@ -1119,6 +1119,7 @@
   public_deps = [
     ":base_static",
     ":build_date",
+    ":cfi_flags",
     ":debugging_flags",
     "//base/numerics:base_numerics",
   ]
@@ -1670,6 +1671,18 @@
   }
 }
 
+# Build flags for Control Flow Integrity
+# https://www.chromium.org/developers/testing/control-flow-integrity
+buildflag_header("cfi_flags") {
+  header = "cfi_flags.h"
+  flags = [
+    # TODO(pcc): remove CFI_CAST_CHECK, see https://crbug.com/626794.
+    "CFI_CAST_CHECK=$is_cfi && $use_cfi_cast",
+    "CFI_ENFORCEMENT_TRAP=$is_cfi && !$use_cfi_diag",
+    "CFI_ENFORCEMENT_DIAGNOSTIC=$is_cfi && $use_cfi_diag && !$use_cfi_recover",
+  ]
+}
+
 buildflag_header("debugging_flags") {
   header = "debugging_flags.h"
   header_dir = "base/debug"
@@ -2415,15 +2428,6 @@
       # data += [ "$root_out_dir/base_unittests.dSYM/" ]
     }
   }
-
-  if (use_cfi_cast) {
-    # TODO(krasin): remove CFI_CAST_CHECK, see https://crbug.com/626794.
-    defines += [ "CFI_CAST_CHECK" ]
-  }
-
-  if (use_cfi_diag && !use_cfi_recover) {
-    defines += [ "CFI_ENFORCEMENT_DIAGNOSTIC" ]
-  }
 }
 
 action("build_date") {
diff --git a/base/containers/small_map.h b/base/containers/small_map.h
index 7ffd6d4a..495332f 100644
--- a/base/containers/small_map.h
+++ b/base/containers/small_map.h
@@ -14,7 +14,6 @@
 
 #include "base/containers/hash_tables.h"
 #include "base/logging.h"
-#include "base/memory/manual_constructor.h"
 
 namespace base {
 
@@ -67,13 +66,12 @@
 //            be used by default. If the wrapped map type has a strict weak
 //            ordering "key_compare" (std::map does), that will be used to
 //            implement equality by default.
-// MapInit: A functor that takes a ManualConstructor<NormalMap>* and uses it to
-//          initialize the map. This functor will be called at most once per
-//          small_map, when the map exceeds the threshold of kArraySize and we
-//          are about to copy values from the array to the map. The functor
-//          *must* call one of the Init() methods provided by
-//          ManualConstructor, since after it runs we assume that the NormalMap
-//          has been initialized.
+// MapInit: A functor that takes a NormalMap* and uses it to initialize the map.
+//          This functor will be called at most once per small_map, when the map
+//          exceeds the threshold of kArraySize and we are about to copy values
+//          from the array to the map. The functor *must* initialize the
+//          NormalMap* argument with placement new, since after it runs we
+//          assume that the NormalMap has been initialized.
 //
 // example:
 //   base::small_map<std::map<string, int>> days;
diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc
index 597c81d..03df9db9 100644
--- a/base/debug/stack_trace_posix.cc
+++ b/base/debug/stack_trace_posix.cc
@@ -38,6 +38,7 @@
 #include "base/debug/proc_maps_linux.h"
 #endif
 
+#include "base/cfi_flags.h"
 #include "base/debug/debugger.h"
 #include "base/logging.h"
 #include "base/macros.h"
@@ -311,7 +312,7 @@
   }
   PrintToStderr("\n");
 
-#if defined(CFI_ENFORCEMENT_TRAP)
+#if BUILDFLAG(CFI_ENFORCEMENT_TRAP)
   if (signal == SIGILL && info->si_code == ILL_ILLOPN) {
     PrintToStderr(
         "CFI: Most likely a control flow integrity violation; for more "
@@ -319,7 +320,7 @@
     PrintToStderr(
         "https://www.chromium.org/developers/testing/control-flow-integrity\n");
   }
-#endif
+#endif  // BUILDFLAG(CFI_ENFORCEMENT_TRAP)
 
   debug::StackTrace().Print();
 
diff --git a/ipc/export_template.h b/base/export_template.h
similarity index 98%
rename from ipc/export_template.h
rename to base/export_template.h
index e743e19..aac8b7c 100644
--- a/ipc/export_template.h
+++ b/base/export_template.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IPC_EXPORT_TEMPLATE_H_
-#define IPC_EXPORT_TEMPLATE_H_
+#ifndef BASE_EXPORT_TEMPLATE_H_
+#define BASE_EXPORT_TEMPLATE_H_
 
 // Synopsis
 //
@@ -160,4 +160,4 @@
 #undef EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT
 #undef EXPORT_TEMPLATE_TEST_MSVC_HACK_MSVC_HACK
 
-#endif  // IPC_EXPORT_TEMPLATE_H_
+#endif  // BASE_EXPORT_TEMPLATE_H_
diff --git a/base/memory/manual_constructor.h b/base/memory/manual_constructor.h
deleted file mode 100644
index e968d04..0000000
--- a/base/memory/manual_constructor.h
+++ /dev/null
@@ -1,73 +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.
-
-// ManualConstructor statically-allocates space in which to store some
-// object, but does not initialize it.  You can then call the constructor
-// and destructor for the object yourself as you see fit.  This is useful
-// for memory management optimizations, where you want to initialize and
-// destroy an object multiple times but only allocate it once.
-//
-// (When I say ManualConstructor statically allocates space, I mean that
-// the ManualConstructor object itself is forced to be the right size.)
-//
-// For example usage, check out base/containers/small_map.h.
-
-#ifndef BASE_MEMORY_MANUAL_CONSTRUCTOR_H_
-#define BASE_MEMORY_MANUAL_CONSTRUCTOR_H_
-
-#include <stddef.h>
-
-#include "base/compiler_specific.h"
-#include "base/memory/aligned_memory.h"
-
-namespace base {
-
-template <typename Type>
-class ManualConstructor {
- public:
-  // No constructor or destructor because one of the most useful uses of
-  // this class is as part of a union, and members of a union cannot have
-  // constructors or destructors.  And, anyway, the whole point of this
-  // class is to bypass these.
-
-  // Support users creating arrays of ManualConstructor<>s.  This ensures that
-  // the array itself has the correct alignment.
-  static void* operator new[](size_t size) {
-    return AlignedAlloc(size, alignof(Type));
-  }
-  static void operator delete[](void* mem) {
-    AlignedFree(mem);
-  }
-
-  inline Type* get() { return reinterpret_cast<Type*>(space_); }
-  inline const Type* get() const  {
-    return reinterpret_cast<const Type*>(space_);
-  }
-
-  inline Type* operator->() { return get(); }
-  inline const Type* operator->() const { return get(); }
-
-  inline Type& operator*() { return *get(); }
-  inline const Type& operator*() const { return *get(); }
-
-  template <typename... Ts>
-  inline void Init(Ts&&... params) {
-    new (space_) Type(std::forward<Ts>(params)...);
-  }
-
-  inline void InitFromMove(ManualConstructor<Type>&& o) {
-    Init(std::move(*o));
-  }
-
-  inline void Destroy() {
-    get()->~Type();
-  }
-
- private:
-  alignas(Type) char space_[sizeof(Type)];
-};
-
-}  // namespace base
-
-#endif  // BASE_MEMORY_MANUAL_CONSTRUCTOR_H_
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index 839d8b7..919c94e 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -62,6 +62,9 @@
 namespace leveldb {
 class LevelDBMojoProxy;
 }
+namespace media {
+class BlockingUrlProtocol;
+}
 namespace mojo {
 class SyncCallRestrictions;
 namespace edk {
@@ -213,6 +216,7 @@
   FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest,
                            ScopedAllowBaseSyncPrimitivesWithBlockingDisallowed);
   friend class leveldb::LevelDBMojoProxy;
+  friend class media::BlockingUrlProtocol;
   friend class net::OCSPScopedAllowBaseSyncPrimitives;
 
   ScopedAllowBaseSyncPrimitives() EMPTY_BODY_IF_DCHECK_IS_OFF;
diff --git a/base/tools_sanity_unittest.cc b/base/tools_sanity_unittest.cc
index 550845c..af2081d3 100644
--- a/base/tools_sanity_unittest.cc
+++ b/base/tools_sanity_unittest.cc
@@ -9,6 +9,7 @@
 #include <stddef.h>
 
 #include "base/atomicops.h"
+#include "base/cfi_flags.h"
 #include "base/debug/asan_invalid_access.h"
 #include "base/debug/profiler.h"
 #include "base/message_loop/message_loop.h"
@@ -342,7 +343,7 @@
   EXPECT_EQ(kMagicValue, shared);
 }
 
-#if defined(CFI_ENFORCEMENT_TRAP)
+#if BUILDFLAG(CFI_ENFORCEMENT_TRAP)
 #if defined(OS_WIN)
 #define CFI_ERROR_MSG "EXCEPTION_ILLEGAL_INSTRUCTION"
 #elif defined(OS_ANDROID)
@@ -352,9 +353,9 @@
 #else
 #define CFI_ERROR_MSG "ILL_ILLOPN"
 #endif
-#elif defined(CFI_ENFORCEMENT_DIAGNOSTIC)
+#elif BUILDFLAG(CFI_ENFORCEMENT_DIAGNOSTIC)
 #define CFI_ERROR_MSG "runtime error: control flow integrity check"
-#endif // CFI_ENFORCEMENT_TRAP || CFI_ENFORCEMENT_DIAGNOSTIC
+#endif  // BUILDFLAG(CFI_ENFORCEMENT_TRAP || CFI_ENFORCEMENT_DIAGNOSTIC)
 
 #if defined(CFI_ERROR_MSG)
 class A {
@@ -400,7 +401,7 @@
 }
 
 // TODO(pcc): remove CFI_CAST_CHECK, see https://crbug.com/626794.
-#if defined(CFI_CAST_CHECK)
+#if BUILDFLAG(CFI_CAST_CHECK)
 TEST(ToolsSanityTest, BadDerivedCast) {
   A a;
   EXPECT_DEATH((void)(B*)&a, CFI_ERROR_MSG);
@@ -418,8 +419,8 @@
   A a;
   EXPECT_DEATH((void)(B*)&a, CFI_ERROR_MSG);
 }
-#endif // CFI_CAST_CHECK
+#endif  // BUILDFLAG(CFI_CAST_CHECK)
 
-#endif // CFI_ERROR_MSG
+#endif  // CFI_ERROR_MSG
 
 }  // namespace base
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 6d705aa0..038522b 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -138,6 +138,7 @@
   is_clang =
       current_os == "mac" || current_os == "ios" || current_os == "chromeos" ||
       current_os == "fuchsia" || current_os == "android" ||
+      (current_os == "win" && host_os != "win") ||
       (current_os == "linux" && current_cpu != "s390x" &&
        current_cpu != "s390" && current_cpu != "ppc64" &&
        current_cpu != "ppc" && current_cpu != "mips" && current_cpu != "mips64")
@@ -245,7 +246,9 @@
   _default_toolchain = host_toolchain
 } else if (target_os == "win") {
   # On Windows we use the same toolchain for host and target by default.
-  assert(target_os == host_os, "Win cross-compiles only work on win hosts.")
+  # Beware, win cross builds mostly don't work yet, see docs/win_cross.md
+  # TODO(thakis): Allow on Mac as well soon.
+  assert(host_os != "mac", "https://crbug.com/774209")
   if (is_clang) {
     _default_toolchain = "//build/toolchain/win:win_clang_$target_cpu"
   } else {
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn
index 7a2990d..26807c06 100644
--- a/build/config/sanitizers/BUILD.gn
+++ b/build/config/sanitizers/BUILD.gn
@@ -378,8 +378,6 @@
       if (use_cfi_recover) {
         cflags += [ "-fsanitize-recover=cfi" ]
       }
-    } else {
-      defines = [ "CFI_ENFORCEMENT_TRAP" ]
     }
   }
 }
diff --git a/build/toolchain/goma.gni b/build/toolchain/goma.gni
index d7c2036f..e9cb9d1 100644
--- a/build/toolchain/goma.gni
+++ b/build/toolchain/goma.gni
@@ -17,3 +17,6 @@
     goma_dir = getenv("HOME") + "/goma"
   }
 }
+
+assert(!(is_win && host_os != "win") || !use_goma,
+       "goma does not yet work in win cross builds, b/64390790")
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 319f75ac..eedfc6d 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -214,7 +214,6 @@
     "//components/payments/mojom:mojom_parser_java",
     "//components/policy/android:policy_java",
     "//components/safe_browsing/android:safe_browsing_java",
-    "//components/safe_json/android:safe_json_java",
     "//components/signin/core/browser/android:java",
     "//components/spellcheck/browser/android:java",
     "//components/sync/android:sync_java",
@@ -232,6 +231,7 @@
     "//mojo/public/java:system_java",
     "//net/android:net_java",
     "//printing:printing_java",
+    "//services/data_decoder/public/cpp/android:safe_json_java",
     "//services/service_manager/public/interfaces:interfaces_java",
     "//services/service_manager/public/java:service_manager_java",
     "//services/shape_detection:shape_detection_java",
diff --git a/chrome/android/java/DEPS b/chrome/android/java/DEPS
index 6242546..3d789d0 100644
--- a/chrome/android/java/DEPS
+++ b/chrome/android/java/DEPS
@@ -12,7 +12,6 @@
   "+components/navigation_interception",
   "+components/offline_items_collection/core/android/java",
   "+components/payments/content/android/java/src/org/chromium/components/payments",
-  "+components/safe_json/android/java",
   "+components/sync/android/java/src/org/chromium/components/sync",
   "+components/web_contents_delegate_android",
   "+components/web_restrictions",
diff --git a/chrome/android/java/res/layout/download_manager_ui_space_widget.xml b/chrome/android/java/res/layout/download_manager_ui_space_widget.xml
index 1c2a7407..87c8f9e 100644
--- a/chrome/android/java/res/layout/download_manager_ui_space_widget.xml
+++ b/chrome/android/java/res/layout/download_manager_ui_space_widget.xml
@@ -34,9 +34,9 @@
             android:layout_height="2dp"
             android:layout_marginTop="8dp"
             android:layout_marginBottom="8dp"
-            chrome:colorBackground="@color/google_grey_500"
-            chrome:colorProgress="@color/google_grey_300"
-            chrome:colorSecondaryProgress="@color/google_blue_700" />
+            chrome:colorBackground="@color/google_grey_300"
+            chrome:colorProgress="@color/google_blue_500_alpha_38_opaque"
+            chrome:colorSecondaryProgress="@color/google_blue_500" />
 
         <TextView
             android:id="@+id/size_free_and_other_apps"
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index 98681000..fb1f0131 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -204,5 +204,6 @@
     <color name="media_viewer_bg">#000000</color>
     <color name="image_viewer_bg">#0e0e0e</color>
     <color name="modern_toolbar_bg">#E6FFFFFF</color>
+    <color name="google_blue_500_alpha_38_opaque">#B7D1FB</color>
 
 </resources>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 5981ee6..882ac57 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -515,7 +515,9 @@
                     if (!DataReductionPromoScreen.launchDataReductionPromo(
                                 this, currentModel.isIncognito())) {
                         if (FeatureUtilities.shouldShowChromeHomePromoForStartup()) {
-                            new ChromeHomePromoDialog(this).show();
+                            new ChromeHomePromoDialog(
+                                    this, ChromeHomePromoDialog.ShowReason.STARTUP)
+                                    .show();
                         } else if (getBottomSheet() != null) {
                             getBottomSheet().showHelpBubbleIfNecessary();
                         }
@@ -1614,7 +1616,9 @@
                         if (getBottomSheet() != null
                                 && ChromeFeatureList.isEnabled(
                                            ChromeFeatureList.CHROME_HOME_PROMO)) {
-                            new ChromeHomePromoDialog(ChromeTabbedActivity.this).show();
+                            new ChromeHomePromoDialog(ChromeTabbedActivity.this,
+                                    ChromeHomePromoDialog.ShowReason.MENU)
+                                    .show();
                             return;
                         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java
index 7eb85a1..3aa4da0a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java
@@ -17,6 +17,7 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
+import org.chromium.base.StrictModeContext;
 import org.chromium.chrome.browser.UrlConstants;
 
 import java.io.File;
@@ -263,7 +264,9 @@
                 (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
         Uri contentUri = null;
         try {
-            contentUri = manager.getUriForDownloadedFile(downloadId);
+            try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
+                contentUri = manager.getUriForDownloadedFile(downloadId);
+            }
         } catch (SecurityException e) {
             Log.e(TAG, "unable to get content URI from DownloadManager");
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
index ed4261a..f28a95c6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -32,7 +32,6 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.UrlConstants;
@@ -53,6 +52,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
 import org.chromium.chrome.browser.util.ConversionUtils;
+import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.components.feature_engagement.EventConstants;
 import org.chromium.components.feature_engagement.Tracker;
@@ -69,6 +69,7 @@
 import java.io.File;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 import java.text.NumberFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -126,17 +127,16 @@
     public static boolean showDownloadManager(@Nullable Activity activity, @Nullable Tab tab) {
         // Figure out what tab was last being viewed by the user.
         if (activity == null) activity = ApplicationStatus.getLastTrackedFocusedActivity();
+
+        if (openDownloadsManagerInBottomSheet(activity)) return true;
+
         if (tab == null && activity instanceof ChromeTabbedActivity) {
             tab = ((ChromeTabbedActivity) activity).getActivityTab();
         }
 
         Context appContext = ContextUtils.getApplicationContext();
-        if (activity instanceof ChromeActivity
-                && ((ChromeActivity) activity).getBottomSheet() != null) {
-            ((ChromeActivity) activity)
-                    .getBottomSheetContentController()
-                    .showContentAndOpenSheet(R.id.action_downloads);
-        } else if (DeviceFormFactor.isTablet()) {
+
+        if (DeviceFormFactor.isTablet()) {
             // Download Home shows up as a tab on tablets.
             LoadUrlParams params = new LoadUrlParams(UrlConstants.DOWNLOADS_URL);
             if (tab == null || !tab.isInitialized()) {
@@ -184,6 +184,42 @@
     }
 
     /**
+     * @param activity The activity the download manager should be displayed in if applicable or
+     *                 the last tracked focused activity.
+     * @return Whether the downloads manager was opened in the Chrome Home bottom sheet.
+     */
+    private static boolean openDownloadsManagerInBottomSheet(Activity activity) {
+        if (!FeatureUtilities.isChromeHomeEnabled()) return false;
+
+        Context appContext = ContextUtils.getApplicationContext();
+
+        ChromeTabbedActivity tabbedActivity = null;
+        if (activity instanceof ChromeTabbedActivity) {
+            tabbedActivity = (ChromeTabbedActivity) activity;
+        } else {
+            // Iterate through all activities looking for an instance of ChromeTabbedActivity.
+            List<WeakReference<Activity>> list = ApplicationStatus.getRunningActivities();
+            for (WeakReference<Activity> ref : list) {
+                Activity currentActivity = ref.get();
+                if (currentActivity instanceof ChromeTabbedActivity) {
+                    tabbedActivity = (ChromeTabbedActivity) currentActivity;
+                }
+            }
+        }
+
+        if (tabbedActivity == null) return false;
+
+        tabbedActivity.getBottomSheetContentController().showContentAndOpenSheet(
+                R.id.action_downloads);
+
+        // Bring the ChromeTabbedActivity to the front.
+        Intent intent = new Intent(appContext, tabbedActivity.getClass());
+        intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
+        activity.startActivity(intent);
+        return true;
+    }
+
+    /**
      * @return Whether or not the Intent corresponds to a DownloadActivity that should show off the
      *         record downloads.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java
index f8f43692..87973c3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java
@@ -9,9 +9,6 @@
 import android.os.Environment;
 import android.os.StatFs;
 import android.support.v7.widget.RecyclerView;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.style.ForegroundColorSpan;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -196,21 +193,19 @@
         String spaceFree = DownloadUtils.getStringForBytes(context, FREE_STRINGS, mFreeBytes);
         String spaceUsedByOtherApps =
                 DownloadUtils.getStringForBytes(context, OTHER_STRINGS, bytesUsedByOtherApps);
-        SpannableString spannable = new SpannableString(
+        mSpaceFreeAndOtherAppsTextView.setText(
                 context.getResources().getString(R.string.download_manager_ui_space_free_and_other,
                         spaceFree, spaceUsedByOtherApps));
-        ForegroundColorSpan colorSpan = new ForegroundColorSpan(
-                ApiCompatibilityUtils.getColor(context.getResources(), R.color.black_alpha_54));
-        spannable.setSpan(colorSpan, 0, spaceFree.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-        mSpaceFreeAndOtherAppsTextView.setText(spannable);
 
         // Set a minimum size for the download size so that it shows up in the progress bar.
-        long onePercentOfSystem = fileSystemBytes == 0 ? 0 : fileSystemBytes / 100;
-        long fudgedBytesUsedByDownloads = Math.max(bytesUsedByDownloads, onePercentOfSystem);
+        long threePercentOfSystem = fileSystemBytes == 0 ? 0 : fileSystemBytes / 100 * 3;
+        long fudgedBytesUsedByDownloads = Math.max(bytesUsedByDownloads, threePercentOfSystem);
+        long fudgedBytesUsedByOtherApps = Math.max(bytesUsedByOtherApps, threePercentOfSystem);
 
         // Indicate how much space has been used as a progress bar.  The percentage used by
         // downloads is shown by the non-overlapped area of the primary and secondary progressbar.
-        int percentageUsedTotal = computePercentage(bytesUsedTotal, fileSystemBytes);
+        int percentageUsedTotal = computePercentage(
+                fudgedBytesUsedByDownloads + fudgedBytesUsedByOtherApps, fileSystemBytes);
         int percentageDownloaded = computePercentage(fudgedBytesUsedByDownloads, fileSystemBytes);
         mSpaceBar.setProgress(percentageUsedTotal);
         mSpaceBar.setSecondaryProgress(percentageDownloaded);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index 7cbce18..2a54e3a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -420,7 +420,7 @@
         NoUnderlineClickableSpan link = new NoUnderlineClickableSpan() {
             @Override
             public void onClick(View view) {
-                new ChromeHomePromoDialog(mActivity).show();
+                new ChromeHomePromoDialog(mActivity, ChromeHomePromoDialog.ShowReason.NTP).show();
             }
         };
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncUserDataWiper.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncUserDataWiper.java
index 0315af2..00f01fa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncUserDataWiper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncUserDataWiper.java
@@ -4,10 +4,12 @@
 
 package org.chromium.chrome.browser.sync;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.Promise;
 import org.chromium.chrome.browser.bookmarks.BookmarkModel;
 import org.chromium.chrome.browser.browsing_data.BrowsingDataType;
 import org.chromium.chrome.browser.browsing_data.TimePeriod;
+import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmarksShim;
 import org.chromium.chrome.browser.preferences.privacy.BrowsingDataBridge;
 import org.chromium.chrome.browser.preferences.privacy.BrowsingDataBridge.OnClearBrowsingDataListener;
 
@@ -30,6 +32,9 @@
     public static Promise<Void> wipeSyncUserData() {
         final Promise<Void> promise = new Promise<>();
 
+        // Partner bookmarks need to be loaded explicitly so that BookmarkModel can be loaded.
+        PartnerBookmarksShim.kickOffReading(ContextUtils.getApplicationContext());
+
         final BookmarkModel model = new BookmarkModel();
         model.runAfterBookmarkModelLoaded(new Runnable() {
             @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
index ea0bbfb..a4fb7a99 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -25,6 +25,7 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.firstrun.FirstRunUtils;
@@ -299,6 +300,8 @@
                 if (ChromePreferenceManager.getInstance().isChromeHomeUserPreferenceSet()) {
                     isUserPreferenceSet = true;
                     sChromeHomeEnabled = prefManager.isChromeHomeUserEnabled();
+                    RecordHistogram.recordBooleanHistogram(
+                            "Android.ChromeHome.UserPreference.Enabled", sChromeHomeEnabled);
                 } else {
                     sChromeHomeEnabled = prefManager.isChromeHomeEnabled();
                 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/ChromeHomePromoDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/ChromeHomePromoDialog.java
index d297768b..2895d00 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/ChromeHomePromoDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/ChromeHomePromoDialog.java
@@ -7,6 +7,7 @@
 import android.app.Activity;
 import android.content.DialogInterface;
 import android.os.Bundle;
+import android.support.annotation.IntDef;
 import android.support.v7.widget.SwitchCompat;
 import android.view.View;
 import android.widget.CompoundButton;
@@ -14,6 +15,7 @@
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.StrictModeContext;
 import org.chromium.base.SysUtils;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeFeatureList;
@@ -24,6 +26,8 @@
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.widget.PromoDialog;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 
 /**
@@ -31,6 +35,32 @@
  * activity to bring a user in or out of the feature.
  */
 public class ChromeHomePromoDialog extends PromoDialog {
+    /** Reasons that the promo was shown. */
+    @IntDef({ShowReason.NTP, ShowReason.MENU, ShowReason.STARTUP, ShowReason.BOUNDARY})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ShowReason {
+        int NTP = 0;
+        int MENU = 1;
+        int STARTUP = 2;
+        int BOUNDARY = 3;
+    }
+
+    /** States the promo was closed in. */
+    @IntDef({PromoResult.ENABLED, PromoResult.DISABLED, PromoResult.REMAINED_ENABLED,
+            PromoResult.REMAINED_DISABLED, PromoResult.BOUNDARY})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface PromoResult {
+        int ENABLED = 0;
+        int DISABLED = 1;
+        int REMAINED_ENABLED = 2;
+        int REMAINED_DISABLED = 3;
+        int BOUNDARY = 4;
+    }
+
+    /** The reason the promo was shown. */
+    @ShowReason
+    private final int mShowReason;
+
     /** Whether or not the switch in the promo is enabled or disabled. */
     private boolean mSwitchStateShouldEnable;
 
@@ -40,10 +70,15 @@
     /**
      * Default constructor.
      * @param activity The {@link Activity} showing the promo.
+     * @param showReason The reason that the promo was shown.
      */
-    public ChromeHomePromoDialog(Activity activity) {
+    public ChromeHomePromoDialog(Activity activity, @ShowReason int showReason) {
         super(activity);
         setOnDismissListener(this);
+        mShowReason = showReason;
+
+        RecordHistogram.recordEnumeratedHistogram("Android.ChromeHome.Promo.ShowReason", showReason,
+                ChromeHomePromoDialog.ShowReason.BOUNDARY);
     }
 
     @Override
@@ -142,6 +177,30 @@
         boolean userSetting = mUserMadeSelection ? mSwitchStateShouldEnable
                                                  : FeatureUtilities.isChromeHomeEnabled();
 
+        String histogramName = null;
+        switch (mShowReason) {
+            case ShowReason.MENU:
+                histogramName = "Android.ChromeHome.Promo.Result.Menu";
+                break;
+            case ShowReason.NTP:
+                histogramName = "Android.ChromeHome.Promo.Result.NTP";
+                break;
+            case ShowReason.STARTUP:
+                histogramName = "Android.ChromeHome.Promo.Result.Startup";
+                break;
+            default:
+                assert false;
+        }
+
+        @PromoResult
+        int state;
+        if (FeatureUtilities.isChromeHomeEnabled()) {
+            state = userSetting ? PromoResult.REMAINED_ENABLED : PromoResult.DISABLED;
+        } else {
+            state = userSetting ? PromoResult.ENABLED : PromoResult.REMAINED_DISABLED;
+        }
+        RecordHistogram.recordEnumeratedHistogram(histogramName, state, PromoResult.BOUNDARY);
+
         boolean restartRequired = userSetting != FeatureUtilities.isChromeHomeEnabled();
         FeatureUtilities.switchChromeHomeUserSetting(userSetting);
 
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 81201be..1c478ee 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -110,12 +110,6 @@
 #include "components/metrics/leak_detector/leak_detector.h"
 #endif
 
-#if BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
-#include "mash/common/config.h"                                   // nogncheck
-#include "services/ui/public/interfaces/constants.mojom.h"        // nogncheck
-
-#endif  // BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
-
 #if defined(OS_ANDROID)
 #include "base/android/java_exception_reporter.h"
 #include "chrome/browser/android/crash/pure_java_exception_handler.h"
@@ -1120,22 +1114,3 @@
   }
   return service_manager::ProcessType::kDefault;
 }
-
-bool ChromeMainDelegate::ShouldTerminateServiceManagerOnInstanceQuit(
-    const service_manager::Identity& identity,
-    int* exit_code) {
-#if BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
-  if (identity.name() == mash::common::GetWindowManagerServiceName() ||
-      identity.name() == ui::mojom::kServiceName ||
-      identity.name() == content::mojom::kPackagedServicesServiceName) {
-    // Quit the main process if an important child (e.g. window manager) dies.
-    // On Chrome OS the OS-level session_manager will restart the main process.
-    *exit_code = 1;
-    LOG(ERROR) << "Main process exiting because service " << identity.name()
-               << " quit unexpectedly.";
-    return true;
-  }
-#endif  // BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
-
-  return false;
-}
diff --git a/chrome/app/chrome_main_delegate.h b/chrome/app/chrome_main_delegate.h
index 3bfe602..5510677 100644
--- a/chrome/app/chrome_main_delegate.h
+++ b/chrome/app/chrome_main_delegate.h
@@ -52,9 +52,6 @@
 #endif
   bool ShouldEnableProfilerRecording() override;
   service_manager::ProcessType OverrideProcessType() override;
-  bool ShouldTerminateServiceManagerOnInstanceQuit(
-      const service_manager::Identity& identity,
-      int* exit_code) override;
 
   content::ContentBrowserClient* CreateContentBrowserClient() override;
   content::ContentGpuClient* CreateContentGpuClient() override;
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index acf5d47..d0911772 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -10945,17 +10945,6 @@
         Completion available: <ph name="COMPLETION_TEXT">$1</ph>
       </message>
     </if>
-    <if expr="enable_vr">
-      <message name="IDS_VR_SHELL_EXIT_PROMPT_DESCRIPTION" desc="Text on the exit prompt that shows up when the user tries to use a feature that is not supported in VR">
-        This feature is not supported in VR
-      </message>
-      <message name="IDS_VR_SHELL_EXIT_PROMPT_DESCRIPTION_SITE_INFO" desc="Text on the exit prompt that shows up when the user clicks on URL bar security icon in VR">
-        Site information is not available in VR
-      </message>
-      <message name="IDS_VR_SHELL_EXIT_PROMPT_EXIT_VR_BUTTON" desc="Text on the exit button of the exit prompt that shows up when the user clicks on URL bar security icon in VR">
-        EXIT VR
-      </message>
-    </if>
 
     <!-- Ad Blocking UI strings. -->
     <message name="IDS_ALWAYS_ALLOW_ADS" desc="Explanation associated with a toggle to allow ads after ads have been blocked on the page. To be used on pages where the ad blocking UI is governed by a persistent permissions-based whitelist.">
@@ -11099,19 +11088,37 @@
       <message name="IDS_SCREEN_CAPTURE_NOTIFICATION_TEXT_2" desc="Text to be shown as a notification when screen capture is in progress.">
         Sharing screen
       </message>
-      <message name="IDS_VR_UNDER_DEVELOPMENT_NOTICE" desc="Text to be shown below the URL bar to announce that this is under development.">
-        This is an early release. Some features, like search and text entry, are not yet available.
-      </message>
-      <message name="IDS_VR_POWERED_BY_CHROME_MESSAGE" desc="A message indicating that the current page is running in Chrome.">
-        Powered by Chrome
-      </message>
     </if>
 
-    <!-- VR specific strings -->
+    <!-- Strings that are only used when VR devices are supported -->
+      <!-- TODO(ddorwin): Use consistent naming schemes for VR strings. -->
     <if expr="enable_vr">
       <message name="IDS_PRESS_APP_TO_EXIT" desc="Text displayed in a transient bubble to tell users how to return from cinema mode (where the page displayed in a cinema like environment) or presentation mode (where the WebVR page occupies the entire screen) to normal mode.">
         Press App button to exit
       </message>
+
+      <!-- VR browser -->
+      <!-- TODO(https://crbug.com/731802): Only build these when the VR browser is supported. -->
+      <message name="IDS_VR_SHELL_EXIT_PROMPT_DESCRIPTION" desc="Text on the exit prompt that shows up when the user tries to use a feature that is not supported in VR">
+        This feature is not supported in VR
+      </message>
+      <message name="IDS_VR_SHELL_EXIT_PROMPT_DESCRIPTION_SITE_INFO" desc="Text on the exit prompt that shows up when the user clicks on URL bar security icon in VR">
+        Site information is not available in VR
+      </message>
+      <message name="IDS_VR_SHELL_EXIT_PROMPT_EXIT_VR_BUTTON" desc="Text on the exit button of the exit prompt that shows up when the user clicks on URL bar security icon in VR">
+        EXIT VR
+      </message>
+      <message name="IDS_PAGE_INFO_VR_BROWSER_UNSUPPORTED_MODE" desc="This text is displayed as a large toast to inform the user that they cannot currently browse in VR and they will soon exit VR mode.">
+        This page contains features not yet supported in VR. Exiting...
+      </message>
+      <message name="IDS_VR_UNDER_DEVELOPMENT_NOTICE" desc="Text to be shown below the URL bar to announce that this is under development.">
+        This is an early release. Some features, like search and text entry, are not yet available.
+      </message>
+
+      <!-- TODO(https://crbug.com/774199): Make this <if expr="is_android"> -->
+      <message name="IDS_VR_POWERED_BY_CHROME_MESSAGE" desc="A message indicating that the current page is running in Chrome.">
+        Powered by Chrome
+      </message>
     </if>
   </messages>
  </release>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 3bb9e57..73f0b2c1 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1217,6 +1217,10 @@
     "renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm",
     "renderer_preferences_util.cc",
     "renderer_preferences_util.h",
+    "resource_coordinator/browser_child_process_watcher.cc",
+    "resource_coordinator/browser_child_process_watcher.h",
+    "resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc",
+    "resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h",
     "resource_coordinator/resource_coordinator_render_process_probe.cc",
     "resource_coordinator/resource_coordinator_render_process_probe.h",
     "resource_coordinator/resource_coordinator_web_contents_observer.cc",
@@ -1634,7 +1638,6 @@
     "//components/rappor:rappor_recorder",
     "//components/renderer_context_menu",
     "//components/resources",
-    "//components/safe_json",
     "//components/search",
     "//components/search_engines",
     "//components/search_provider_logos",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 97b6ad6..8ce2fba7 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -149,6 +149,7 @@
   "+third_party/WebKit/public/web/WebMediaPlayerAction.h",
   "+third_party/WebKit/public/web/WebPluginAction.h",
   "+third_party/WebKit/public/web/WebTextDirection.h",
+  "+third_party/WebKit/public/web/WebTriggeringEventInfo.h",
   "+third_party/WebKit/public/web/window_features.mojom.h",
 
   # Unlike other WebKit directories WebKit/common is for the files that
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 998fe3b..6fba5d6 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3327,12 +3327,6 @@
      flag_descriptions::kAsyncImageDecodingDescription, kOsAll,
      MULTI_VALUE_TYPE(kAsyncImageDecodingChoices)},
 
-    {"capture-thumbnail-on-navigating-away",
-     flag_descriptions::kCaptureThumbnailOnNavigatingAwayName,
-     flag_descriptions::kCaptureThumbnailOnNavigatingAwayDescription,
-     kOsDesktop,
-     FEATURE_VALUE_TYPE(features::kCaptureThumbnailOnNavigatingAway)},
-
 #if defined(OS_CHROMEOS)
     {"disable-lock-screen-apps", flag_descriptions::kDisableLockScreenAppsName,
      flag_descriptions::kDisableLockScreenAppsDescription, kOsCrOS,
diff --git a/chrome/browser/android/digital_asset_links/digital_asset_links_handler.cc b/chrome/browser/android/digital_asset_links/digital_asset_links_handler.cc
index 92c823d6..92a8285 100644
--- a/chrome/browser/android/digital_asset_links/digital_asset_links_handler.cc
+++ b/chrome/browser/android/digital_asset_links/digital_asset_links_handler.cc
@@ -8,7 +8,6 @@
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
-#include "components/safe_json/safe_json_parser.h"
 #include "net/base/load_flags.h"
 #include "net/base/url_util.h"
 #include "net/http/http_response_headers.h"
@@ -16,6 +15,7 @@
 #include "net/http/http_util.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request_status.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 
 namespace {
 const char kDigitalAssetLinksBaseURL[] =
@@ -70,7 +70,8 @@
   std::string response_body;
   source->GetResponseAsString(&response_body);
 
-  safe_json::SafeJsonParser::Parse(
+  data_decoder::SafeJsonParser::Parse(
+      /* connector=*/nullptr,  // Connector is unused on Android.
       response_body,
       base::Bind(&DigitalAssetLinksHandler::OnJSONParseSucceeded,
                  weak_ptr_factory_.GetWeakPtr()),
diff --git a/chrome/browser/android/digital_asset_links/digital_asset_links_handler_unittest.cc b/chrome/browser/android/digital_asset_links/digital_asset_links_handler_unittest.cc
index 33727128..9a87eef 100644
--- a/chrome/browser/android/digital_asset_links/digital_asset_links_handler_unittest.cc
+++ b/chrome/browser/android/digital_asset_links/digital_asset_links_handler_unittest.cc
@@ -10,13 +10,13 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/values.h"
-#include "components/safe_json/testing_json_parser.h"
 #include "content/public/test/test_browser_thread.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_status_code.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
+#include "services/data_decoder/public/cpp/testing_json_parser.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace digital_asset_links {
@@ -74,7 +74,7 @@
 
  private:
   base::MessageLoop message_loop_;
-  safe_json::TestingJsonParser::ScopedFactoryOverride factory_override_;
+  data_decoder::TestingJsonParser::ScopedFactoryOverride factory_override_;
   content::TestBrowserThread io_thread_;
   net::TestURLFetcherFactory url_fetcher_factory_;
 
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 5d798a19..cc0bc99 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -63,6 +63,7 @@
 #include "content/public/common/child_process_host.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/result_codes.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/download_test_observer.h"
@@ -3527,6 +3528,38 @@
   watcher.Wait();
 }
 
+// Makes sure that a webview will display correctly after reloading it after a
+// crash.
+IN_PROC_BROWSER_TEST_P(WebViewTest, ReloadAfterCrash) {
+  if (!base::FeatureList::IsEnabled(::features::kGuestViewCrossProcessFrames))
+    return;
+
+  // Load guest and wait for it to appear.
+  LoadAppWithGuest("web_view/simple");
+  EXPECT_TRUE(GetGuestWebContents()->GetMainFrame()->GetView());
+  WaitForChildFrameSurfaceReady(GetGuestWebContents()->GetMainFrame());
+
+  // Kill guest.
+  auto* rph = GetGuestWebContents()->GetMainFrame()->GetProcess();
+  content::RenderProcessHostWatcher crash_observer(
+      rph, content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+  EXPECT_TRUE(rph->Shutdown(content::RESULT_CODE_KILLED, false));
+  crash_observer.Wait();
+  EXPECT_FALSE(GetGuestWebContents()->GetMainFrame()->GetView());
+
+  // Reload guest and make sure it appears.
+  content::TestNavigationObserver load_observer(GetGuestWebContents());
+  EXPECT_TRUE(ExecuteScript(GetEmbedderWebContents(),
+                            "document.querySelector('webview').reload()"));
+  load_observer.Wait();
+  EXPECT_TRUE(GetGuestWebContents()->GetMainFrame()->GetView());
+
+  // When the frame passed has a RenderWidgetHostViewChildFrame,
+  // WaitForChildFrameSurfaceReady will only return when the guest is embedded
+  // within the root surface.
+  WaitForChildFrameSurfaceReady(GetGuestWebContents()->GetMainFrame());
+}
+
 IN_PROC_BROWSER_TEST_P(WebViewAccessibilityTest, LoadWebViewAccessibility) {
   LoadAppWithGuest("web_view/focus_accessibility");
   content::WebContents* web_contents = GetFirstAppWindowWebContents();
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 4d8b991..b8010a4 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -104,7 +104,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/rappor/public/rappor_utils.h"
 #include "components/rappor/rappor_service_impl.h"
-#include "components/safe_json/safe_json_parser.h"
 #include "components/signin/core/common/profile_management_switches.h"
 #include "components/subresource_filter/content/browser/content_ruleset_service.h"
 #include "components/subresource_filter/core/browser/ruleset_service.h"
diff --git a/chrome/browser/browser_process_impl_unittest.cc b/chrome/browser/browser_process_impl_unittest.cc
index 5299c8f..66810e4b 100644
--- a/chrome/browser/browser_process_impl_unittest.cc
+++ b/chrome/browser/browser_process_impl_unittest.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_service_manager_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if defined(OS_WIN)
@@ -54,6 +55,10 @@
   // managed separately.
   void StartSecondaryThreads() {
     base::TaskScheduler::GetInstance()->StartWithDefaultParams();
+    // TestServiceManagerContext creation requires the task scheduler to be
+    // started.
+    service_manager_context_ =
+        std::make_unique<content::TestServiceManagerContext>();
     io_thread_->StartIOThread();
   }
 
@@ -61,6 +66,8 @@
   // The UI thread needs to be alive while BrowserProcessImpl is alive, and is
   // managed separately.
   void DestroySecondaryThreads() {
+    // TestServiceManagerContext must be destroyed before the IO thread.
+    service_manager_context_.reset();
     // Spin the runloop to allow posted tasks to be processed.
     base::RunLoop().RunUntilIdle();
     io_thread_.reset();
@@ -83,6 +90,7 @@
 #endif
   std::unique_ptr<content::TestBrowserThread> io_thread_;
   base::CommandLine command_line_;
+  std::unique_ptr<content::TestServiceManagerContext> service_manager_context_;
   std::unique_ptr<BrowserProcessImpl> browser_process_impl_;
 };
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 64bf982..3886f1b 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -79,6 +79,7 @@
 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
 #include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
 #include "chrome/browser/resource_coordinator/background_tab_navigation_throttle.h"
+#include "chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h"
 #include "chrome/browser/safe_browsing/certificate_reporting_service.h"
 #include "chrome/browser/safe_browsing/certificate_reporting_service_factory.h"
 #include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
@@ -322,13 +323,6 @@
 #include "chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.h"
 #endif
 
-#if defined(USE_AURA)
-#include "services/service_manager/runner/common/client_util.h"
-#include "services/ui/public/cpp/gpu/gpu.h"
-#include "ui/aura/mus/window_tree_client.h"
-#include "ui/views/mus/mus_client.h"
-#endif
-
 #if defined(USE_X11)
 #include "chrome/browser/chrome_browser_main_extra_parts_x11.h"
 #endif
@@ -925,6 +919,8 @@
   main_parts->AddParts(new ChromeBrowserMainExtraPartsX11());
 #endif
 
+  main_parts->AddParts(new ChromeBrowserMainExtraPartsResourceCoordinator);
+
   main_parts->AddParts(new ChromeBrowserMainExtraPartsProfiling);
 
   chrome::AddMetricsExtraParts(main_parts);
@@ -1854,7 +1850,7 @@
     base::CommandLine* command_line) {
 #if BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
   // Mash services do their own resource loading.
-  if (IsMashServiceName(identity.name())) {
+  if (mash_service_registry::IsMashServiceName(identity.name())) {
     // This switch is used purely for debugging to make it easier to know what
     // service a process is running.
     command_line->AppendSwitchASCII("mash-service-name", identity.name());
@@ -2688,15 +2684,6 @@
   return NULL;
 }
 
-gpu::GpuChannelEstablishFactory*
-ChromeContentBrowserClient::GetGpuChannelEstablishFactory() {
-#if defined(USE_AURA)
-  if (views::MusClient::Exists())
-    return views::MusClient::Get()->window_tree_client()->gpu();
-#endif
-  return nullptr;
-}
-
 bool ChromeContentBrowserClient::AllowPepperSocketAPI(
     content::BrowserContext* browser_context,
     const GURL& url,
@@ -3115,10 +3102,18 @@
 
 #if BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kMash))
-    RegisterOutOfProcessServicesForMash(services);
+    mash_service_registry::RegisterOutOfProcessServices(services);
 #endif
 }
 
+bool ChromeContentBrowserClient::ShouldTerminateOnServiceQuit(
+    const service_manager::Identity& id) {
+#if BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
+  return mash_service_registry::ShouldTerminateOnServiceQuit(id.name());
+#endif
+  return false;
+}
+
 std::unique_ptr<base::Value>
 ChromeContentBrowserClient::GetServiceManifestOverlay(base::StringPiece name) {
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index f33a3d7..375e69c 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -244,7 +244,6 @@
   void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override;
   content::BrowserPpapiHost* GetExternalBrowserPpapiHost(
       int plugin_process_id) override;
-  gpu::GpuChannelEstablishFactory* GetGpuChannelEstablishFactory() override;
   bool AllowPepperSocketAPI(
       content::BrowserContext* browser_context,
       const GURL& url,
@@ -312,6 +311,8 @@
   void RegisterInProcessServices(StaticServiceMap* services) override;
   void RegisterOutOfProcessServices(
       OutOfProcessServiceMap* services) override;
+  bool ShouldTerminateOnServiceQuit(
+      const service_manager::Identity& id) override;
   std::unique_ptr<base::Value> GetServiceManifestOverlay(
       base::StringPiece name) override;
   std::vector<content::ContentBrowserClient::ServiceManifestInfo>
diff --git a/chrome/browser/chrome_content_browser_client_unittest.cc b/chrome/browser/chrome_content_browser_client_unittest.cc
index b0acc96..6249451 100644
--- a/chrome/browser/chrome_content_browser_client_unittest.cc
+++ b/chrome/browser/chrome_content_browser_client_unittest.cc
@@ -48,6 +48,12 @@
 #include "chrome/test/base/search_test_utils.h"
 #endif
 
+#if defined(OS_CHROMEOS)
+#include "ash/public/interfaces/constants.mojom.h"
+#include "content/public/common/service_names.mojom.h"
+#include "services/ui/public/interfaces/constants.mojom.h"
+#endif
+
 using content::BrowsingDataFilterBuilder;
 using testing::_;
 using ChromeContentBrowserClientTest = testing::Test;
@@ -406,3 +412,33 @@
   EXPECT_EQ("", client.GetMetricSuffixForURL(
                     GURL("https://www.google.com/search?notaquery=nope")));
 }
+
+#if defined(OS_CHROMEOS)
+
+// This behavior only matters on Chrome OS, which is why this isn't wrapped in
+// ENABLE_MASH_PACKAGED_SERVICES (which is used for Linux Ozone).
+TEST(ChromeContentBrowserClientTest, ShouldTerminateOnServiceQuit) {
+  const struct {
+    std::string service_name;
+    bool expect_terminate;
+  } kTestCases[] = {
+      // Don't terminate for invalid service names.
+      {"", false},
+      {"unknown-name", false},
+      // Don't terminate for some well-known browser services.
+      {content::mojom::kBrowserServiceName, false},
+      {content::mojom::kGpuServiceName, false},
+      {content::mojom::kRendererServiceName, false},
+      // Do terminate for some mash-specific cases.
+      {ui::mojom::kServiceName, true},
+      {ash::mojom::kServiceName, true},
+  };
+  ChromeContentBrowserClient client;
+  for (const auto& test : kTestCases) {
+    service_manager::Identity id(test.service_name);
+    EXPECT_EQ(test.expect_terminate, client.ShouldTerminateOnServiceQuit(id))
+        << "for service name " << test.service_name;
+  }
+}
+
+#endif  // defined(OS_CHROMEOS)
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index a7a7e3910..402079b 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -109,7 +109,6 @@
     "//components/renderer_context_menu",
     "//components/safe_browsing:csd_proto",
     "//components/safe_browsing/db:metadata_proto",
-    "//components/safe_json",
     "//components/session_manager/core",
     "//components/signin/core/browser",
     "//components/ssl_config",
@@ -150,6 +149,7 @@
     "//mojo/common",
     "//net",
     "//ppapi/proxy:ipc",  # For PpapiMsg_LoadPlugin
+    "//services/data_decoder/public/cpp",
     "//services/device/public/interfaces",
     "//services/preferences/public/interfaces",
     "//services/service_manager/public/cpp",
diff --git a/chrome/browser/chromeos/arc/arc_util.cc b/chrome/browser/chromeos/arc/arc_util.cc
index 82cd1ad5..e3da123 100644
--- a/chrome/browser/chromeos/arc/arc_util.cc
+++ b/chrome/browser/chromeos/arc/arc_util.cc
@@ -32,7 +32,6 @@
 #include "components/user_manager/known_user.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
-#include "google_apis/google_api_keys.h"
 
 namespace arc {
 
@@ -41,9 +40,6 @@
 constexpr char kLsbReleaseArcVersionKey[] = "CHROMEOS_ARC_ANDROID_SDK_VERSION";
 constexpr char kAndroidMSdkVersion[] = "23";
 
-// Used as client id on bot tests.
-constexpr char kDummyClientId[] = "dummytoken";
-
 // Contains set of profiles for which decline reson was already reported.
 base::LazyInstance<std::set<base::FilePath>>::DestructorAtExit
     g_profile_declined_set = LAZY_INSTANCE_INITIALIZER;
@@ -237,15 +233,6 @@
     return false;
   }
 
-  if ((!google_apis::IsGoogleChromeAPIKeyUsed() &&
-       google_apis::GetOAuth2ClientID(google_apis::CLIENT_MAIN) !=
-           kDummyClientId) ||
-      google_apis::IsClientIdOverridden()) {
-    VLOG_IF(1, IsReportingFirstTimeForProfile(profile))
-        << "ARC is not supported for non-google client.";
-    return false;
-  }
-
   return true;
 }
 
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
index 21d9f24e2..1f6c92fb 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
@@ -32,8 +32,9 @@
 #include "components/policy/core/common/policy_namespace.h"
 #include "components/policy/policy_constants.h"
 #include "components/prefs/pref_service.h"
-#include "components/safe_json/safe_json_parser.h"
+#include "content/public/common/service_manager_connection.h"
 #include "crypto/sha2.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 
 namespace arc {
 
@@ -378,7 +379,8 @@
   // the callee interface.
   auto repeating_callback =
       base::AdaptCallbackForRepeating(std::move(callback));
-  safe_json::SafeJsonParser::Parse(
+  data_decoder::SafeJsonParser::Parse(
+      content::ServiceManagerConnection::GetForProcess()->GetConnector(),
       request,
       base::Bind(&ArcPolicyBridge::OnReportComplianceParseSuccess,
                  weak_ptr_factory_.GetWeakPtr(), repeating_callback),
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc b/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
index c3e98198..95c6f5d 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
@@ -21,8 +21,9 @@
 #include "components/policy/core/common/policy_namespace.h"
 #include "components/policy/core/common/policy_types.h"
 #include "components/policy/policy_constants.h"
-#include "components/safe_json/testing_json_parser.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_service_manager_context.h"
+#include "services/data_decoder/public/cpp/testing_json_parser.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -156,8 +157,9 @@
   Profile* profile() { return profile_; }
 
  private:
-  safe_json::TestingJsonParser::ScopedFactoryOverride factory_override_;
   content::TestBrowserThreadBundle thread_bundle_;
+  data_decoder::TestingJsonParser::ScopedFactoryOverride factory_override_;
+  content::TestServiceManagerContext service_manager_context_;
   std::unique_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_;
   std::unique_ptr<TestingProfileManager> testing_profile_manager_;
   base::RunLoop run_loop_;
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
index 4596a77..de22ae4 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
@@ -150,6 +150,7 @@
       wizard_completed_timeout_(kWizardCompletedTimeout),
       binding_(this) {
   arc_bridge_service_->voice_interaction_arc_home()->AddObserver(this);
+  ArcSessionManager::Get()->AddObserver(this);
 }
 
 ArcVoiceInteractionArcHomeService::~ArcVoiceInteractionArcHomeService() =
@@ -158,6 +159,16 @@
 void ArcVoiceInteractionArcHomeService::Shutdown() {
   ResetTimeouts();
   arc_bridge_service_->voice_interaction_arc_home()->RemoveObserver(this);
+  ArcSessionManager::Get()->RemoveObserver(this);
+}
+
+void ArcVoiceInteractionArcHomeService::OnArcPlayStoreEnabledChanged(
+    bool enabled) {
+  if (!pending_pai_lock_)
+    return;
+
+  pending_pai_lock_ = false;
+  LockPai();
 }
 
 void ArcVoiceInteractionArcHomeService::LockPai() {
@@ -166,6 +177,10 @@
       arc::ArcSessionManager::Get()->pai_starter();
   if (!pai_starter) {
     DLOG(ERROR) << "There is no PAI starter.";
+    // We could be starting before ARC session is started when user initiated
+    // voice interaction first before ARC is enabled. We will remember this
+    // and wait for ARC session started to try locking again.
+    pending_pai_lock_ = true;
     return;
   }
   pai_starter->AcquireLock();
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.h b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.h
index 5268df5..952be2a 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.h
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.h
@@ -34,7 +34,8 @@
     : public KeyedService,
       public mojom::VoiceInteractionArcHomeHost,
       public InstanceHolder<mojom::VoiceInteractionArcHomeInstance>::Observer,
-      public ArcAppListPrefs::Observer {
+      public ArcAppListPrefs::Observer,
+      public ArcSessionManager::Observer {
  public:
   // Returns singleton instance for the given BrowserContext,
   // or nullptr if the browser |context| is not allowed to use ARC.
@@ -88,6 +89,9 @@
                      const std::string& intent) override;
   void OnTaskDestroyed(int32_t task_id) override;
 
+  // ArcSessionManager::Observer:
+  void OnArcPlayStoreEnabledChanged(bool enabled) override;
+
   // Locks/Unlocks Play Auto Install.
   void LockPai();
   void UnlockPai();
@@ -113,6 +117,9 @@
 
   mojo::Binding<mojom::VoiceInteractionArcHomeHost> binding_;
 
+  // Whether there is a pending request to lock PAI before it's available.
+  bool pending_pai_lock_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(ArcVoiceInteractionArcHomeService);
 };
 
diff --git a/chrome/browser/chromeos/input_method/input_method_engine.cc b/chrome/browser/chromeos/input_method/input_method_engine.cc
index c797585..d9d00a5 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine.cc
@@ -112,16 +112,11 @@
     return false;
   }
 
+  window_visible_ = visible;
   IMECandidateWindowHandlerInterface* cw_handler =
       ui::IMEBridge::Get()->GetCandidateWindowHandler();
-
-  if (cw_handler) {
-    if (window_visible_ != visible)
-      cw_handler->OnCandidateWindowVisibilityChanged(visible);
-
-    cw_handler->UpdateLookupTable(*candidate_window_, visible);
-  }
-  window_visible_ = visible;
+  if (cw_handler)
+    cw_handler->UpdateLookupTable(*candidate_window_, window_visible_);
   return true;
 }
 
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc b/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc
index 2fd050a..569b0a41 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc
@@ -17,10 +17,8 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/input_method/input_method_engine_base.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/mus/input_method_mus.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.h"
-#include "ui/base/ime/chromeos/mock_ime_candidate_window_handler.h"
 #include "ui/base/ime/ime_bridge.h"
 #include "ui/base/ime/ime_engine_handler_interface.h"
 #include "ui/base/ime/mock_ime_input_context_handler.h"
@@ -150,16 +148,9 @@
     mock_ime_input_context_handler_.reset(new ui::MockIMEInputContextHandler());
     ui::IMEBridge::Get()->SetInputContextHandler(
         mock_ime_input_context_handler_.get());
-
-    mock_ime_candidate_window_handler_.reset(
-        new chromeos::MockIMECandidateWindowHandler());
-    ui::IMEBridge::Get()->SetCandidateWindowHandler(
-        mock_ime_candidate_window_handler_.get());
   }
-
   ~InputMethodEngineTest() override {
     ui::IMEBridge::Get()->SetInputContextHandler(NULL);
-    ui::IMEBridge::Get()->SetCandidateWindowHandler(NULL);
     engine_.reset();
     Shutdown();
   }
@@ -191,8 +182,6 @@
 
   std::unique_ptr<ui::MockIMEInputContextHandler>
       mock_ime_input_context_handler_;
-  std::unique_ptr<chromeos::MockIMECandidateWindowHandler>
-      mock_ime_candidate_window_handler_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(InputMethodEngineTest);
@@ -330,16 +319,5 @@
   EXPECT_EQ(ONCOMPOSITIONBOUNDSCHANGED, observer_->GetCallsBitmapAndReset());
 }
 
-TEST_F(InputMethodEngineTest, ChangeCandidateWindowVisiblility) {
-  CreateEngine(true);
-  FocusIn(ui::TEXT_INPUT_TYPE_TEXT);
-  engine_->Enable(kTestImeComponentId);
-  std::string error;
-  bool is_candidate_window_visible = true;
-  engine_->SetCandidateWindowVisible(is_candidate_window_visible, &error);
-  EXPECT_EQ(is_candidate_window_visible,
-            mock_ime_candidate_window_handler_->is_candidate_window_visible());
-}
-
 }  // namespace input_method
 }  // namespace chromeos
diff --git a/chrome/browser/component_updater/sth_set_component_installer_unittest.cc b/chrome/browser/component_updater/sth_set_component_installer_unittest.cc
index 5af13717..0172fb1 100644
--- a/chrome/browser/component_updater/sth_set_component_installer_unittest.cc
+++ b/chrome/browser/component_updater/sth_set_component_installer_unittest.cc
@@ -17,11 +17,11 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "base/version.h"
-#include "components/safe_json/testing_json_parser.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/cert/signed_tree_head.h"
 #include "net/cert/sth_observer.h"
 #include "net/test/ct_test_util.h"
+#include "services/data_decoder/public/cpp/testing_json_parser.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
@@ -85,7 +85,7 @@
   // |policy_| should be destroyed before the |observer_| as it holds a pointer
   // to it.
   std::unique_ptr<STHSetComponentInstallerPolicy> policy_;
-  safe_json::TestingJsonParser::ScopedFactoryOverride factory_override_;
+  data_decoder::TestingJsonParser::ScopedFactoryOverride factory_override_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(STHSetComponentInstallerTest);
diff --git a/chrome/browser/component_updater/supervised_user_whitelist_installer.cc b/chrome/browser/component_updater/supervised_user_whitelist_installer.cc
index 02f3d932..232cbbbd 100644
--- a/chrome/browser/component_updater/supervised_user_whitelist_installer.cc
+++ b/chrome/browser/component_updater/supervised_user_whitelist_installer.cc
@@ -41,9 +41,9 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
-#include "components/safe_json/json_sanitizer.h"
-#include "components/update_client/update_client_errors.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/data_decoder/public/cpp/json_sanitizer.h"
 
 namespace component_updater {
 
@@ -175,7 +175,8 @@
     return;
   }
 
-  safe_json::JsonSanitizer::Sanitize(
+  data_decoder::JsonSanitizer::Sanitize(
+      content::ServiceManagerConnection::GetForProcess()->GetConnector(),
       unsafe_json,
       base::Bind(&OnWhitelistSanitizationResult, crx_id, task_runner, callback),
       base::Bind(&OnWhitelistSanitizationError, whitelist_path));
diff --git a/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc b/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc
index c01c7a0..8317486 100644
--- a/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc
+++ b/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc
@@ -21,7 +21,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_path_override.h"
-#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/component_updater/supervised_user_whitelist_installer.h"
@@ -34,11 +33,13 @@
 #include "components/component_updater/component_updater_service.h"
 #include "components/crx_file/id_util.h"
 #include "components/prefs/testing_pref_service.h"
-#include "components/safe_json/testing_json_parser.h"
 #include "components/update_client/crx_update_item.h"
 #include "components/update_client/update_client.h"
 #include "components/update_client/utils.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_service_manager_context.h"
+#include "content/public/test/test_utils.h"
+#include "services/data_decoder/public/cpp/testing_json_parser.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -281,7 +282,7 @@
   void RegisterExistingComponents() {
     local_state_.Set(prefs::kRegisteredSupervisedUserWhitelists, pref_);
     installer_->RegisterComponents();
-    scoped_task_environment_.RunUntilIdle();
+    content::RunAllTasksUntilIdle();
     base::RunLoop().RunUntilIdle();
   }
 
@@ -294,11 +295,12 @@
     EXPECT_EQ(version, component->version.GetString());
   }
 
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  content::TestBrowserThreadBundle thread_bundle_;
   TestingProfileManager testing_profile_manager_;
   base::ScopedPathOverride user_data_dir_override_;
-  safe_json::TestingJsonParser::ScopedFactoryOverride json_parser_override_;
+  data_decoder::TestingJsonParser::ScopedFactoryOverride json_parser_override_;
   TestingPrefServiceSimple local_state_;
+  content::TestServiceManagerContext service_manager_context_;
   std::unique_ptr<SupervisedUserWhitelistInstaller> installer_;
   base::FilePath whitelist_base_directory_;
   base::FilePath whitelist_directory_;
@@ -370,7 +372,7 @@
           },
           &observer));
 
-  scoped_task_environment_.RunUntilIdle();
+  content::RunAllTasksUntilIdle();
 
   observer.Wait();
   EXPECT_EQ(whitelist_path_.value(), observer.whitelist_path().value());
@@ -428,7 +430,7 @@
   {
     base::RunLoop run_loop;
     installer_->UnregisterWhitelist(kClientId, kCrxId);
-    scoped_task_environment_.RunUntilIdle();
+    content::RunAllTasksUntilIdle();
     run_loop.RunUntilIdle();
   }
   EXPECT_TRUE(component_update_service_.registered_component());
@@ -442,7 +444,7 @@
     // This does the same thing in our case as calling UnregisterWhitelist(),
     // but it exercises a different code path.
     profile_attributes_storage()->RemoveProfile(GetProfilePath(kOtherClientId));
-    scoped_task_environment_.RunUntilIdle();
+    content::RunAllTasksUntilIdle();
     run_loop.RunUntilIdle();
   }
   EXPECT_FALSE(component_update_service_.registered_component());
diff --git a/chrome/browser/devtools/global_confirm_info_bar_browsertest.cc b/chrome/browser/devtools/global_confirm_info_bar_browsertest.cc
index 6b87c86..386e39a 100644
--- a/chrome/browser/devtools/global_confirm_info_bar_browsertest.cc
+++ b/chrome/browser/devtools/global_confirm_info_bar_browsertest.cc
@@ -9,7 +9,6 @@
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/browser.h"
@@ -17,6 +16,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/infobars/core/infobar.h"
 #include "components/infobars/core/infobars_switches.h"
+#include "content/public/test/test_utils.h"
 
 namespace {
 
@@ -147,14 +147,8 @@
     EXPECT_EQ(0u, GetInfoBarServiceFromTabIndex(i)->infobar_count());
 }
 
-// https://crbug.com/764079
-#if defined(OS_LINUX) || defined(OS_MACOSX)
-#define MAYBE_InfoBarsDisabled DISABLED_InfoBarsDisabled
-#else
-#define MAYBE_InfoBarsDisabled InfoBarsDisabled
-#endif
 IN_PROC_BROWSER_TEST_F(GlobalConfirmInfoBarWithInfoBarDisabledTest,
-                       MAYBE_InfoBarsDisabled) {
+                       InfoBarsDisabled) {
   ASSERT_EQ(1, browser()->tab_strip_model()->count());
 
   auto delegate = base::MakeUnique<TestConfirmInfoBarDelegate>();
@@ -162,7 +156,7 @@
       GlobalConfirmInfoBar::Show(std::move(delegate));
 
   // In this case, the deletion is done asynchronously.
-  base::RunLoop().RunUntilIdle();
+  content::RunAllPendingInMessageLoop();
 
   ASSERT_FALSE(global_confirm_info_bar);
 }
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index af266e74..e2d2c0f 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -847,7 +847,6 @@
     "//components/resources",
     "//components/safe_browsing/common:safe_browsing_prefs",
     "//components/safe_browsing/db:database_manager",
-    "//components/safe_json",
     "//components/search_engines",
     "//components/sessions",
     "//components/signin/core/browser",
@@ -883,6 +882,7 @@
     "//ppapi/features",
     "//printing/features",
     "//rlz/features",
+    "//services/data_decoder/public/cpp",
     "//services/identity/public/interfaces",
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/interfaces",
diff --git a/chrome/browser/extensions/DEPS b/chrome/browser/extensions/DEPS
index 4dd7e5e..09e7040 100644
--- a/chrome/browser/extensions/DEPS
+++ b/chrome/browser/extensions/DEPS
@@ -13,7 +13,4 @@
 
   # For access to testing command line switches.
   "+ppapi/shared_impl",
-
-  # For safe_json
-  "+components/safe_json",
 ]
diff --git a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
index 038ee70..6e80a0f 100644
--- a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
+++ b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
@@ -25,11 +25,11 @@
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/web_application_info.h"
 #include "components/favicon/core/favicon_service.h"
-#include "components/safe_json/safe_json_parser.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/utility_process_host.h"
 #include "content/public/browser/utility_process_host_client.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/service_manager_connection.h"
 #include "extensions/browser/api/management/management_api.h"
 #include "extensions/browser/api/management/management_api_constants.h"
 #include "extensions/browser/extension_prefs.h"
@@ -37,6 +37,7 @@
 #include "extensions/browser/extension_system.h"
 #include "extensions/common/disable_reason.h"
 #include "extensions/common/extension.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 
 namespace {
 
@@ -200,7 +201,8 @@
     GetPermissionWarningsByManifestFunctionDelegate(
         extensions::ManagementGetPermissionWarningsByManifestFunction* function,
         const std::string& manifest_str) const {
-  safe_json::SafeJsonParser::Parse(
+  data_decoder::SafeJsonParser::Parse(
+      content::ServiceManagerConnection::GetForProcess()->GetConnector(),
       manifest_str,
       base::Bind(
           &extensions::ManagementGetPermissionWarningsByManifestFunction::
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index b51b5d9..b60a4a6 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -163,6 +163,8 @@
 }
 
 CrxInstaller::~CrxInstaller() {
+  DCHECK(!service_weak_ || service_weak_->browser_terminating() ||
+         installer_callback_.is_null());
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // Ensure |client_| and |install_checker_| data members are destroyed on the
   // UI thread. The |client_| dialog has a weak reference as |this| is its
@@ -183,9 +185,9 @@
 
   source_file_ = source_file.path;
 
-  scoped_refptr<SandboxedUnpacker> unpacker(new SandboxedUnpacker(
+  auto unpacker = base::MakeRefCounted<SandboxedUnpacker>(
       install_source_, creation_flags_, install_directory_,
-      installer_task_runner_.get(), this));
+      installer_task_runner_.get(), this);
 
   if (!installer_task_runner_->PostTask(
           FROM_HERE, base::BindOnce(&SandboxedUnpacker::StartWithCrx, unpacker,
@@ -194,6 +196,29 @@
   }
 }
 
+void CrxInstaller::InstallUnpackedCrx(const std::string& extension_id,
+                                      const std::string& public_key,
+                                      const base::FilePath& unpacked_dir) {
+  ExtensionService* service = service_weak_.get();
+  if (!service || service->browser_terminating())
+    return;
+
+  NotifyCrxInstallBegin();
+
+  source_file_ = unpacked_dir;
+
+  auto unpacker = base::MakeRefCounted<SandboxedUnpacker>(
+      install_source_, creation_flags_, install_directory_,
+      installer_task_runner_.get(), this);
+
+  if (!installer_task_runner_->PostTask(
+          FROM_HERE,
+          base::BindOnce(&SandboxedUnpacker::StartWithDirectory, unpacker,
+                         extension_id, public_key, unpacked_dir))) {
+    NOTREACHED();
+  }
+}
+
 void CrxInstaller::InstallUserScript(const base::FilePath& source_file,
                                      const GURL& download_url) {
   DCHECK(!download_url.is_empty());
@@ -440,11 +465,11 @@
   dnr_ruleset_checksum_ = dnr_ruleset_checksum;
 
   if (!install_icon.empty())
-    install_icon_.reset(new SkBitmap(install_icon));
+    install_icon_ = std::make_unique<SkBitmap>(install_icon);
 
   if (original_manifest) {
-    original_manifest_.reset(
-        new Manifest(Manifest::INVALID_LOCATION, std::move(original_manifest)));
+    original_manifest_ = std::make_unique<Manifest>(
+        Manifest::INVALID_LOCATION, std::move(original_manifest));
   }
 
   // We don't have to delete the unpack dir explicity since it is a child of
@@ -860,6 +885,13 @@
 
   if (success)
     ConfirmReEnable();
+
+  if (!installer_callback_.is_null() &&
+      !BrowserThread::GetTaskRunnerForThread(BrowserThread::UI)
+           ->PostTask(FROM_HERE, base::BindOnce(std::move(installer_callback_),
+                                                success))) {
+    NOTREACHED();
+  }
 }
 
 void CrxInstaller::CleanupTempFiles() {
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index e76a62c0..9f807616 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -21,6 +21,7 @@
 #include "chrome/browser/extensions/webstore_installer.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "components/sync/model/string_ordinal.h"
+#include "extensions/browser/extension_system.h"
 #include "extensions/browser/install_flag.h"
 #include "extensions/browser/preload_check.h"
 #include "extensions/browser/sandboxed_unpacker.h"
@@ -71,6 +72,9 @@
 // and won't safely be able to clean up UI thread notification listeners.
 class CrxInstaller : public SandboxedUnpackerClient {
  public:
+  // A callback to be executed when the install finishes.
+  using InstallerResultCallback = ExtensionSystem::InstallUpdateCallback;
+
   // Used in histograms; do not change order.
   enum OffStoreInstallAllowReason {
     OffStoreInstallDisallowed,
@@ -101,6 +105,13 @@
   void InstallCrx(const base::FilePath& source_file);
   void InstallCrxFile(const CRXFileInfo& source_file);
 
+  // Install the unpacked crx in |unpacked_dir|.
+  // If |delete_source_| is true, |unpacked_dir| will be removed at the end of
+  // the installation.
+  void InstallUnpackedCrx(const std::string& extension_id,
+                          const std::string& public_key,
+                          const base::FilePath& unpacked_dir);
+
   // Convert the specified user script into an extension and install it.
   void InstallUserScript(const base::FilePath& source_file,
                          const GURL& download_url);
@@ -201,6 +212,10 @@
     set_install_flag(kInstallFlagDoNotSync, val);
   }
 
+  void set_installer_callback(InstallerResultCallback callback) {
+    installer_callback_ = std::move(callback);
+  }
+
   bool did_handle_successfully() const { return did_handle_successfully_; }
 
   Profile* profile() { return profile_; }
@@ -455,6 +470,9 @@
   // Runs the above checks.
   std::unique_ptr<PreloadCheckGroup> check_group_;
 
+  // Invoked when the install is completed.
+  InstallerResultCallback installer_callback_;
+
   DISALLOW_COPY_AND_ASSIGN(CrxInstaller);
 };
 
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
index 848b2ee..801da55 100644
--- a/chrome/browser/extensions/crx_installer_browsertest.cc
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -10,6 +10,7 @@
 
 #include "base/at_exit.h"
 #include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
@@ -219,7 +220,7 @@
       bool strict_manifest_checks) {
     std::unique_ptr<WebstoreInstaller::Approval> result;
 
-    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    base::ScopedAllowBlockingForTesting allow_io;
     base::FilePath ext_path = test_data_dir_.AppendASCII(manifest_dir);
     std::string error;
     std::unique_ptr<base::DictionaryValue> parsed_manifest(
@@ -234,6 +235,7 @@
 
   void RunCrxInstaller(const WebstoreInstaller::Approval* approval,
                        std::unique_ptr<ExtensionInstallPrompt> prompt,
+                       CrxInstaller::InstallerResultCallback callback,
                        const base::FilePath& crx_path) {
     ExtensionService* service = extensions::ExtensionSystem::Get(
         browser()->profile())->extension_service();
@@ -241,14 +243,35 @@
         CrxInstaller::Create(service, std::move(prompt), approval));
     installer->set_allow_silent_install(true);
     installer->set_is_gallery_install(true);
+    installer->set_installer_callback(std::move(callback));
     installer->InstallCrx(crx_path);
     content::RunMessageLoop();
   }
 
+  void RunCrxInstallerFromUnpackedDirectory(
+      std::unique_ptr<ExtensionInstallPrompt> prompt,
+      CrxInstaller::InstallerResultCallback callback,
+      const std::string& extension_id,
+      const std::string& public_key,
+      const base::FilePath& crx_directory) {
+    ExtensionService* service =
+        extensions::ExtensionSystem::Get(browser()->profile())
+            ->extension_service();
+    scoped_refptr<CrxInstaller> installer(
+        CrxInstaller::Create(service, std::move(prompt)));
+    installer->set_allow_silent_install(true);
+    installer->set_is_gallery_install(true);
+    installer->set_installer_callback(std::move(callback));
+    installer->set_delete_source(true);
+    installer->InstallUnpackedCrx(extension_id, public_key, crx_directory);
+    content::RunMessageLoop();
+  }
+
   // Installs a crx from |crx_relpath| (a path relative to the extension test
   // data dir) with expected id |id|.
   void InstallWithPrompt(const char* ext_relpath,
                          const std::string& id,
+                         CrxInstaller::InstallerResultCallback callback,
                          MockPromptProxy* mock_install_prompt) {
     base::FilePath ext_path = test_data_dir_.AppendASCII(ext_relpath);
 
@@ -259,19 +282,22 @@
     base::FilePath crx_path = PackExtension(ext_path);
     EXPECT_FALSE(crx_path.empty());
     RunCrxInstaller(approval.get(), mock_install_prompt->CreatePrompt(),
-                    crx_path);
+                    std::move(callback), crx_path);
 
     EXPECT_TRUE(mock_install_prompt->did_succeed());
   }
 
   // Installs an extension and checks that it has scopes granted IFF
   // |record_oauth2_grant| is true.
-  void CheckHasEmptyScopesAfterInstall(const std::string& ext_relpath,
-                                       bool record_oauth2_grant) {
+  void CheckHasEmptyScopesAfterInstall(
+      const std::string& ext_relpath,
+      CrxInstaller::InstallerResultCallback callback,
+      bool record_oauth2_grant) {
     std::unique_ptr<MockPromptProxy> mock_prompt =
         CreateMockPromptProxyForBrowser(browser());
 
-    InstallWithPrompt("browsertest/scopes", std::string(), mock_prompt.get());
+    InstallWithPrompt("browsertest/scopes", std::string(), std::move(callback),
+                      mock_prompt.get());
 
     std::unique_ptr<const PermissionSet> permissions =
         ExtensionPrefs::Get(browser()->profile())
@@ -344,7 +370,7 @@
 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, BlockedFileTypes) {
   const Extension* extension =
       InstallExtension(test_data_dir_.AppendASCII("blocked_file_types.crx"), 1);
-  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  base::ScopedAllowBlockingForTesting allow_io;
   EXPECT_TRUE(base::PathExists(extension->path().AppendASCII("test.html")));
   EXPECT_TRUE(base::PathExists(extension->path().AppendASCII("test.nexe")));
   EXPECT_FALSE(base::PathExists(extension->path().AppendASCII("test1.EXE")));
@@ -356,7 +382,7 @@
       test_data_dir_.AppendASCII("theme_with_extension.crx"), 1);
   ASSERT_TRUE(extension);
   const base::FilePath& path = extension->path();
-  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  base::ScopedAllowBlockingForTesting allow_io;
   EXPECT_TRUE(
       base::PathExists(path.AppendASCII("images/theme_frame_camo.PNG")));
   EXPECT_TRUE(
@@ -415,19 +441,35 @@
 // true.
 #if defined(OS_WIN)
 #define MAYBE_GrantScopes DISABLED_GrantScopes
+#define MAYBE_GrantScopes_WithCallback DISABLED_GrantScopes_WithCallback
 #else
 #define MAYBE_GrantScopes GrantScopes
+#define MAYBE_GrantScopes_WithCallback GrantScopes_WithCallback
 #endif
 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,
                        MAYBE_GrantScopes) {
-  EXPECT_NO_FATAL_FAILURE(CheckHasEmptyScopesAfterInstall("browsertest/scopes",
-                                                          true));
+  EXPECT_NO_FATAL_FAILURE(CheckHasEmptyScopesAfterInstall(
+      "browsertest/scopes", CrxInstaller::InstallerResultCallback(), true));
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,
+                       MAYBE_GrantScopes_WithCallback) {
+  EXPECT_NO_FATAL_FAILURE(CheckHasEmptyScopesAfterInstall(
+      "browsertest/scopes",
+      base::BindOnce([](bool success) { EXPECT_TRUE(success); }), true));
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,
                        DoNotGrantScopes) {
-  EXPECT_NO_FATAL_FAILURE(CheckHasEmptyScopesAfterInstall("browsertest/scopes",
-                                                          false));
+  EXPECT_NO_FATAL_FAILURE(CheckHasEmptyScopesAfterInstall(
+      "browsertest/scopes", CrxInstaller::InstallerResultCallback(), false));
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTestWithExperimentalApis,
+                       DoNotGrantScopes_WithCallback) {
+  EXPECT_NO_FATAL_FAILURE(CheckHasEmptyScopesAfterInstall(
+      "browsertest/scopes",
+      base::BindOnce([](bool success) { EXPECT_TRUE(success); }), false));
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, AllowOffStore) {
@@ -572,11 +614,126 @@
       GetApproval("crx_installer/v2_no_permission_change/", id, false);
 
   RunCrxInstaller(approval.get(), mock_prompt->CreatePrompt(),
+                  CrxInstaller::InstallerResultCallback(),
                   test_data_dir_.AppendASCII("crx_installer/v1.crx"));
 
   EXPECT_TRUE(mock_prompt->did_succeed());
 }
 
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
+                       NonStrictManifestCheck_WithCallback) {
+  std::unique_ptr<MockPromptProxy> mock_prompt =
+      CreateMockPromptProxyForBrowser(browser());
+
+  // We want to simulate the case where the webstore sends a more recent
+  // version of the manifest, but the downloaded .crx file is old since
+  // the newly published version hasn't fully propagated to all the download
+  // servers yet. So load the v2 manifest, but then install the v1 crx file.
+  const std::string id = "lhnaeclnpobnlbjbgogdanmhadigfnjp";
+  std::unique_ptr<WebstoreInstaller::Approval> approval =
+      GetApproval("crx_installer/v2_no_permission_change/", id, false);
+
+  RunCrxInstaller(approval.get(), mock_prompt->CreatePrompt(),
+                  base::BindOnce([](bool success) { EXPECT_TRUE(success); }),
+                  test_data_dir_.AppendASCII("crx_installer/v1.crx"));
+
+  EXPECT_TRUE(mock_prompt->did_succeed());
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
+                       InstallUnpackedCrx_FolderDoesNotExist) {
+  base::ScopedAllowBlockingForTesting allow_io;
+  std::unique_ptr<MockPromptProxy> mock_prompt =
+      CreateMockPromptProxyForBrowser(browser());
+
+  base::ScopedTempDir temp_dir;
+  EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  const base::FilePath folder = temp_dir.GetPath().AppendASCII("abcdef");
+  EXPECT_FALSE(base::PathExists(folder));
+
+  const std::string public_key = "123456";
+  RunCrxInstallerFromUnpackedDirectory(
+      mock_prompt->CreatePrompt(),
+      base::BindOnce([](bool success) { EXPECT_FALSE(success); }),
+      std::string(), public_key, folder);
+
+  EXPECT_FALSE(mock_prompt->did_succeed());
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
+                       InstallUnpackedCrx_EmptyFolder) {
+  base::ScopedAllowBlockingForTesting allow_io;
+  std::unique_ptr<MockPromptProxy> mock_prompt =
+      CreateMockPromptProxyForBrowser(browser());
+
+  base::ScopedTempDir temp_dir;
+  EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
+  EXPECT_TRUE(base::PathExists(temp_dir.GetPath()));
+
+  const std::string public_key = "123456";
+  RunCrxInstallerFromUnpackedDirectory(
+      mock_prompt->CreatePrompt(),
+      base::BindOnce([](bool success) { EXPECT_FALSE(success); }),
+      std::string(), public_key, temp_dir.GetPath());
+
+  EXPECT_FALSE(mock_prompt->did_succeed());
+  EXPECT_FALSE(base::PathExists(temp_dir.GetPath()));
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
+                       InstallUnpackedCrx_InvalidPublicKey) {
+  base::ScopedAllowBlockingForTesting allow_io;
+  std::unique_ptr<MockPromptProxy> mock_prompt =
+      CreateMockPromptProxyForBrowser(browser());
+
+  base::ScopedTempDir temp_dir;
+  EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
+  EXPECT_TRUE(base::PathExists(temp_dir.GetPath()));
+
+  const base::FilePath unpacked_path =
+      test_data_dir_.AppendASCII("good_unpacked");
+  EXPECT_TRUE(base::PathExists(unpacked_path));
+  EXPECT_TRUE(base::CopyDirectory(unpacked_path, temp_dir.GetPath(), false));
+
+  const std::string public_key = "123456";
+  RunCrxInstallerFromUnpackedDirectory(
+      mock_prompt->CreatePrompt(),
+      base::BindOnce([](bool success) { EXPECT_FALSE(success); }),
+      std::string(), public_key, temp_dir.GetPath());
+
+  EXPECT_FALSE(mock_prompt->did_succeed());
+  EXPECT_FALSE(base::PathExists(temp_dir.GetPath()));
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, InstallUnpackedCrx_Success) {
+  base::ScopedAllowBlockingForTesting allow_io;
+  std::unique_ptr<MockPromptProxy> mock_prompt =
+      CreateMockPromptProxyForBrowser(browser());
+
+  base::ScopedTempDir temp_dir;
+  EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
+  EXPECT_TRUE(base::PathExists(temp_dir.GetPath()));
+
+  const base::FilePath unpacked_path =
+      test_data_dir_.AppendASCII("good_unpacked");
+  EXPECT_TRUE(base::PathExists(unpacked_path));
+  EXPECT_TRUE(base::CopyDirectory(unpacked_path, temp_dir.GetPath(), false));
+
+  const std::string public_key =
+      "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
+      "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
+      "kDuI7caxEGUucpP7GJRRHnm8Sx+"
+      "y0ury28n8jbN0PnInKKWcxpIXXmNQyC19HBuO3QIeUq9Dqc+7YFQIDAQAB";
+  RunCrxInstallerFromUnpackedDirectory(
+      mock_prompt->CreatePrompt(),
+      base::BindOnce([](bool success) { EXPECT_TRUE(success); }), std::string(),
+      public_key, temp_dir.GetPath());
+
+  EXPECT_TRUE(mock_prompt->did_succeed());
+  EXPECT_FALSE(base::PathExists(temp_dir.GetPath()));
+}
+
 #if defined(OS_CHROMEOS)
 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, KioskOnlyTest) {
   // kiosk_only is whitelisted from non-chromeos.
@@ -607,7 +764,7 @@
       crx_path, 1, extensions::Manifest::EXTERNAL_PREF);
   base::FilePath extension_path = extension->path();
   EXPECT_TRUE(cache_dir.GetPath().IsParent(extension_path));
-  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  base::ScopedAllowBlockingForTesting allow_io;
   EXPECT_TRUE(base::PathExists(extension_path));
 
   std::string extension_id = extension->id();
diff --git a/chrome/browser/extensions/webstore_data_fetcher.cc b/chrome/browser/extensions/webstore_data_fetcher.cc
index b078dd5..7411412 100644
--- a/chrome/browser/extensions/webstore_data_fetcher.cc
+++ b/chrome/browser/extensions/webstore_data_fetcher.cc
@@ -9,12 +9,13 @@
 #include "base/bind.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/webstore_data_fetcher_delegate.h"
-#include "components/safe_json/safe_json_parser.h"
+#include "content/public/common/service_manager_connection.h"
 #include "extensions/common/extension_urls.h"
 #include "net/base/load_flags.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 
 namespace {
 
@@ -129,7 +130,8 @@
   fetcher->GetResponseAsString(&webstore_json_data);
 
   // The parser will call us back via one of the callbacks.
-  safe_json::SafeJsonParser::Parse(
+  data_decoder::SafeJsonParser::Parse(
+      content::ServiceManagerConnection::GetForProcess()->GetConnector(),
       webstore_json_data,
       base::Bind(&WebstoreDataFetcher::OnJsonParseSuccess, AsWeakPtr()),
       base::Bind(&WebstoreDataFetcher::OnJsonParseFailure, AsWeakPtr()));
diff --git a/chrome/browser/extensions/webstore_install_helper.cc b/chrome/browser/extensions/webstore_install_helper.cc
index c3792ac..8689510 100644
--- a/chrome/browser/extensions/webstore_install_helper.cc
+++ b/chrome/browser/extensions/webstore_install_helper.cc
@@ -7,11 +7,12 @@
 #include "base/bind.h"
 #include "base/values.h"
 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
-#include "components/safe_json/safe_json_parser.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/common/service_manager_connection.h"
 #include "net/base/load_flags.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 
 using content::BrowserThread;
 
@@ -44,7 +45,8 @@
 void WebstoreInstallHelper::Start() {
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  safe_json::SafeJsonParser::Parse(
+  data_decoder::SafeJsonParser::Parse(
+      content::ServiceManagerConnection::GetForProcess()->GetConnector(),
       manifest_, base::Bind(&WebstoreInstallHelper::OnJSONParseSucceeded, this),
       base::Bind(&WebstoreInstallHelper::OnJSONParseFailed, this));
 
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 38f31ac..2f548a60 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -89,13 +89,6 @@
     "eligibility requirements for showing app banners, such as having a "
     "manifest, are met.";
 
-const char kCaptureThumbnailOnNavigatingAwayName[] =
-    "Capture page thumbnail on navigating away";
-const char kCaptureThumbnailOnNavigatingAwayDescription[] =
-    "Capture a page thumbnail (for use on the New Tab page) when navigating "
-    "away from the current page, in addition to other times a thumbnail may be "
-    "captured.";
-
 const char kCastStreamingHwEncodingName[] =
     "Cast Streaming hardware video encoding";
 const char kCastStreamingHwEncodingDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index be689a1..2647220 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -81,9 +81,6 @@
 extern const char kBypassAppBannerEngagementChecksName[];
 extern const char kBypassAppBannerEngagementChecksDescription[];
 
-extern const char kCaptureThumbnailOnNavigatingAwayName[];
-extern const char kCaptureThumbnailOnNavigatingAwayDescription[];
-
 extern const char kCastStreamingHwEncodingName[];
 extern const char kCastStreamingHwEncodingDescription[];
 
diff --git a/chrome/browser/mash_service_registry.cc b/chrome/browser/mash_service_registry.cc
index 7e9861a..356b374 100644
--- a/chrome/browser/mash_service_registry.cc
+++ b/chrome/browser/mash_service_registry.cc
@@ -18,6 +18,7 @@
 #include "components/font_service/public/interfaces/constants.mojom.h"
 #endif  // defined(OS_LINUX) && !defined(OS_ANDROID)
 
+namespace mash_service_registry {
 namespace {
 
 struct Service {
@@ -40,7 +41,7 @@
 
 }  // namespace
 
-void RegisterOutOfProcessServicesForMash(
+void RegisterOutOfProcessServices(
     content::ContentBrowserClient::OutOfProcessServiceMap* services) {
   for (size_t i = 0; i < arraysize(kServices); ++i) {
     (*services)[kServices[i].name] =
@@ -55,3 +56,18 @@
   }
   return false;
 }
+
+bool ShouldTerminateOnServiceQuit(const std::string& name) {
+  // Some services going down are treated as catastrophic failures, usually
+  // because both the browser and the service cache data about each other's
+  // state that is not rebuilt when the service restarts.
+  if (name == ui::mojom::kServiceName)
+    return true;
+#if defined(OS_CHROMEOS)
+  if (name == ash::mojom::kServiceName)
+    return true;
+#endif
+  return false;
+}
+
+}  // namespace mash_service_registry
diff --git a/chrome/browser/mash_service_registry.h b/chrome/browser/mash_service_registry.h
index 7fc58de..76e72f1 100644
--- a/chrome/browser/mash_service_registry.h
+++ b/chrome/browser/mash_service_registry.h
@@ -9,11 +9,18 @@
 
 #include "content/public/browser/content_browser_client.h"
 
+namespace mash_service_registry {
+
 // Starts one of Mash's embedded services.
-void RegisterOutOfProcessServicesForMash(
+void RegisterOutOfProcessServices(
     content::ContentBrowserClient::OutOfProcessServiceMap* services);
 
 // Returns true if |name| identifies a mash related service.
 bool IsMashServiceName(const std::string& name);
 
+// Returns true if the browser should exit when service |name| quits.
+bool ShouldTerminateOnServiceQuit(const std::string& name);
+
+}  // namespace mash_service_registry
+
 #endif  // CHROME_BROWSER_MASH_SERVICE_REGISTRY_H_
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.cc b/chrome/browser/metrics/process_memory_metrics_emitter.cc
index f7bfa4a..34b8af1 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter.cc
@@ -7,7 +7,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/trace_event/memory_dump_request_args.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/metrics/renderer_uptime_tracker.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/service_manager_connection.h"
@@ -33,7 +32,8 @@
 
 void EmitBrowserMemoryMetrics(const ProcessMemoryDumpPtr& pmd,
                               ukm::SourceId ukm_source_id,
-                              ukm::UkmRecorder* ukm_recorder) {
+                              ukm::UkmRecorder* ukm_recorder,
+                              const base::Optional<base::TimeDelta>& uptime) {
   ukm::builders::Memory_Experimental builder(ukm_source_id);
   builder.SetProcessType(static_cast<int64_t>(
       memory_instrumentation::mojom::ProcessType::BROWSER));
@@ -52,6 +52,8 @@
   UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Browser.PrivateMemoryFootprint",
                                 pmd->os_dump->private_footprint_kb / 1024);
   builder.SetPrivateMemoryFootprint(pmd->os_dump->private_footprint_kb / 1024);
+  if (uptime)
+    builder.SetUptime(uptime.value().InSeconds());
   builder.Record(ukm_recorder);
 }
 
@@ -79,7 +81,8 @@
     const ProcessMemoryDumpPtr& pmd,
     const resource_coordinator::mojom::PageInfoPtr& page_info,
     ukm::UkmRecorder* ukm_recorder,
-    int number_of_extensions) {
+    int number_of_extensions,
+    const base::Optional<base::TimeDelta>& uptime) {
   // UMA
   if (number_of_extensions == 0) {
     RENDERER_MEMORY_UMA_HISTOGRAMS("Renderer");
@@ -100,6 +103,7 @@
   builder.SetBlinkGC(pmd->chrome_dump->blink_gc_total_kb / 1024);
   builder.SetV8(pmd->chrome_dump->v8_total_kb / 1024);
   builder.SetNumberOfExtensions(number_of_extensions);
+
   if (!page_info.is_null()) {
     builder.SetIsVisible(page_info->is_visible);
     builder.SetTimeSinceLastVisibilityChange(
@@ -108,16 +112,16 @@
         page_info->time_since_last_navigation.InSeconds());
   }
 
-  base::TimeDelta uptime =
-      metrics::RendererUptimeTracker::Get()->GetProcessUptime(pmd->pid);
-  builder.SetUptime(uptime.InSeconds());
+  if (uptime)
+    builder.SetUptime(uptime.value().InSeconds());
 
   builder.Record(ukm_recorder);
 }
 
 void EmitGpuMemoryMetrics(const ProcessMemoryDumpPtr& pmd,
                           ukm::SourceId ukm_source_id,
-                          ukm::UkmRecorder* ukm_recorder) {
+                          ukm::UkmRecorder* ukm_recorder,
+                          const base::Optional<base::TimeDelta>& uptime) {
   ukm::builders::Memory_Experimental builder(ukm_source_id);
   builder.SetProcessType(
       static_cast<int64_t>(memory_instrumentation::mojom::ProcessType::GPU));
@@ -141,6 +145,8 @@
   UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Gpu.PrivateMemoryFootprint",
                                 pmd->os_dump->private_footprint_kb / 1024);
   builder.SetPrivateMemoryFootprint(pmd->os_dump->private_footprint_kb / 1024);
+  if (uptime)
+    builder.SetUptime(uptime.value().InSeconds());
   builder.Record(ukm_recorder);
 }
 
@@ -254,6 +260,17 @@
   return number_of_extensions;
 }
 
+base::Optional<base::TimeDelta> ProcessMemoryMetricsEmitter::GetProcessUptime(
+    const base::Time& now,
+    base::ProcessId pid) {
+  auto process_info = process_infos_.find(pid);
+  if (process_info != process_infos_.end()) {
+    if (process_info->second->launch_time)
+      return now - process_info->second->launch_time.value();
+  }
+  return base::Optional<base::TimeDelta>();
+}
+
 void ProcessMemoryMetricsEmitter::CollateResults() {
   if (memory_dump_in_progress_ || get_process_urls_in_progress_)
     return;
@@ -261,12 +278,14 @@
     return;
 
   uint32_t private_footprint_total_kb = 0;
+  base::Time now = base::Time::Now();
   for (const ProcessMemoryDumpPtr& pmd : global_dump_->process_dumps) {
     private_footprint_total_kb += pmd->os_dump->private_footprint_kb;
     switch (pmd->process_type) {
       case memory_instrumentation::mojom::ProcessType::BROWSER: {
         EmitBrowserMemoryMetrics(pmd, ukm::UkmRecorder::GetNewSourceID(),
-                                 GetUkmRecorder());
+                                 GetUkmRecorder(),
+                                 GetProcessUptime(now, pmd->pid));
         break;
       }
       case memory_instrumentation::mojom::ProcessType::RENDERER: {
@@ -281,14 +300,16 @@
             page_info = std::move(process_info->page_infos[0]);
           }
         }
+
         int number_of_extensions = GetNumberOfExtensions(pmd->pid);
         EmitRendererMemoryMetrics(pmd, page_info, GetUkmRecorder(),
-                                  number_of_extensions);
+                                  number_of_extensions,
+                                  GetProcessUptime(now, pmd->pid));
         break;
       }
       case memory_instrumentation::mojom::ProcessType::GPU: {
         EmitGpuMemoryMetrics(pmd, ukm::UkmRecorder::GetNewSourceID(),
-                             GetUkmRecorder());
+                             GetUkmRecorder(), GetProcessUptime(now, pmd->pid));
         break;
       }
       case memory_instrumentation::mojom::ProcessType::UTILITY:
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.h b/chrome/browser/metrics/process_memory_metrics_emitter.h
index dd34380..d322c601 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter.h
+++ b/chrome/browser/metrics/process_memory_metrics_emitter.h
@@ -9,7 +9,9 @@
 #include <vector>
 
 #include "base/memory/ref_counted.h"
+#include "base/optional.h"
 #include "base/process/process_handle.h"
+#include "base/time/time.h"
 #include "services/resource_coordinator/public/interfaces/coordination_unit_introspector.mojom.h"
 #include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
 
@@ -60,6 +62,12 @@
   // It excludes hosted apps extensions.
   virtual int GetNumberOfExtensions(base::ProcessId pid);
 
+  // Virtual for testing. Returns the process uptime of the given process. Does
+  // not return a value when the process startup time is not set.
+  virtual base::Optional<base::TimeDelta> GetProcessUptime(
+      const base::Time& now,
+      base::ProcessId pid);
+
  private:
   friend class base::RefCountedThreadSafe<ProcessMemoryMetricsEmitter>;
 
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc b/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc
index b137096..84ff732 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc
@@ -291,7 +291,7 @@
         has_renderer_source = true;
         CheckUkmRendererSource(source_id, metric_count);
       } else if (ProcessHasTypeForSource(source_id, ProcessType::GPU)) {
-        // Not checked yet.
+        CheckUkmGPUSource(source_id, 1);
       } else {
         // This must be Total2.
         has_total_source = true;
@@ -318,10 +318,9 @@
     CheckMemoryMetricWithName(source_id, UkmEntry::kPartitionAllocName, true,
                               metric_count);
     CheckMemoryMetricWithName(source_id, UkmEntry::kV8Name, true, metric_count);
-    CheckMemoryMetricWithName(source_id, UkmEntry::kUptimeName, true,
-                              metric_count);
     CheckMemoryMetricWithName(source_id, UkmEntry::kNumberOfExtensionsName,
                               true, metric_count);
+    CheckTimeMetricWithName(source_id, UkmEntry::kUptimeName, metric_count);
   }
 
   void CheckUkmBrowserSource(ukm::SourceId source_id,
@@ -334,6 +333,12 @@
 #endif
     CheckMemoryMetricWithName(source_id, UkmEntry::kPrivateMemoryFootprintName,
                               false, metric_count);
+
+    CheckTimeMetricWithName(source_id, UkmEntry::kUptimeName, metric_count);
+  }
+
+  void CheckUkmGPUSource(ukm::SourceId source_id, size_t metric_count = 1u) {
+    CheckTimeMetricWithName(source_id, UkmEntry::kUptimeName, metric_count);
   }
 
   bool ProcessHasTypeForSource(ukm::SourceId source_id,
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc b/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc
index c157487b..81a142c7 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc
@@ -23,34 +23,6 @@
 
 namespace {
 
-class ScopedMockRendererUptimeTracker : public metrics::RendererUptimeTracker {
- public:
-  ScopedMockRendererUptimeTracker() {
-    previous_tracker_ =
-        RendererUptimeTracker::SetMockRendererUptimeTracker(this);
-  }
-
-  ~ScopedMockRendererUptimeTracker() override {
-    RendererUptimeTracker* tracker =
-        RendererUptimeTracker::SetMockRendererUptimeTracker(previous_tracker_);
-    DCHECK_EQ(this, tracker);
-  }
-
-  void SetProcessUptime(int pid, base::TimeDelta uptime) {
-    renderer_uptime_[pid] = uptime;
-  }
-
-  base::TimeDelta GetProcessUptime(int pid) override {
-    auto uptime = renderer_uptime_.find(pid);
-    CHECK(uptime != renderer_uptime_.end());
-    return uptime->second;
-  }
-
- private:
-  std::map<int, base::TimeDelta> renderer_uptime_;
-  RendererUptimeTracker* previous_tracker_;
-};
-
 // Provide fake to surface ReceivedMemoryDump and ReceivedProcessInfos to public
 // visibility.
 class ProcessMemoryMetricsEmitterFake : public ProcessMemoryMetricsEmitter {
@@ -86,6 +58,17 @@
     }
   }
 
+  base::Optional<base::TimeDelta> GetProcessUptime(
+      const base::Time& now,
+      base::ProcessId pid) override {
+    switch (pid) {
+      case 401:
+        return base::TimeDelta::FromSeconds(21);
+      default:
+        return base::TimeDelta::FromSeconds(42);
+    }
+  }
+
  private:
   ~ProcessMemoryMetricsEmitterFake() override {}
 
@@ -135,13 +118,13 @@
           {"Resident", 10},
           {"Malloc", 20},
           {"PrivateMemoryFootprint", 30},
+          {"Uptime", 42},
       },
       base::KEEP_FIRST_OF_DUPES);
 }
 
 void PopulateRendererMetrics(GlobalMemoryDumpPtr& global_dump,
                              base::flat_map<const char*, int64_t>& metrics_mb,
-                             ScopedMockRendererUptimeTracker* uptime_tracker,
                              base::ProcessId pid) {
   ProcessMemoryDumpPtr pmd(
       memory_instrumentation::mojom::ProcessMemoryDump::New());
@@ -152,8 +135,6 @@
       metrics_mb["PartitionAlloc"] * 1024;
   pmd->chrome_dump->blink_gc_total_kb = metrics_mb["BlinkGC"] * 1024;
   pmd->chrome_dump->v8_total_kb = metrics_mb["V8"] * 1024;
-  uptime_tracker->SetProcessUptime(
-      pid, base::TimeDelta::FromSeconds(metrics_mb["Uptime"]));
   OSMemDumpPtr os_dump =
       GetFakeOSMemDump(metrics_mb["Resident"] * 1024,
                        metrics_mb["PrivateMemoryFootprint"] * 1024);
@@ -172,7 +153,7 @@
        {"BlinkGC", 150},
        {"V8", 160},
        {"NumberOfExtensions", 0},
-       {"Uptime", 10}},
+       {"Uptime", 42}},
       base::KEEP_FIRST_OF_DUPES);
 }
 
@@ -206,20 +187,20 @@
           {"Malloc", 220},
           {"PrivateMemoryFootprint", 230},
           {"CommandBuffer", 240},
+          {"Uptime", 42},
       },
       base::KEEP_FIRST_OF_DUPES);
 }
 
 void PopulateMetrics(GlobalMemoryDumpPtr& global_dump,
                      ProcessType ptype,
-                     base::flat_map<const char*, int64_t>& metrics_mb,
-                     ScopedMockRendererUptimeTracker* uptime_tracker) {
+                     base::flat_map<const char*, int64_t>& metrics_mb) {
   switch (ptype) {
     case ProcessType::BROWSER:
       PopulateBrowserMetrics(global_dump, metrics_mb);
       return;
     case ProcessType::RENDERER:
-      PopulateRendererMetrics(global_dump, metrics_mb, uptime_tracker, 101);
+      PopulateRendererMetrics(global_dump, metrics_mb, 101);
       return;
     case ProcessType::GPU:
       PopulateGpuMetrics(global_dump, metrics_mb);
@@ -337,7 +318,6 @@
   }
 
   ukm::TestAutoSetUkmRecorder test_ukm_recorder_;
-  ScopedMockRendererUptimeTracker uptime_tracker_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMetricsEmitterTest);
@@ -350,7 +330,7 @@
 
   GlobalMemoryDumpPtr global_dump(
       memory_instrumentation::mojom::GlobalMemoryDump::New());
-  PopulateMetrics(global_dump, GetParam(), expected_metrics, &uptime_tracker_);
+  PopulateMetrics(global_dump, GetParam(), expected_metrics);
 
   scoped_refptr<ProcessMemoryMetricsEmitterFake> emitter(
       new ProcessMemoryMetricsEmitterFake(test_ukm_recorder_));
@@ -371,11 +351,12 @@
   base::flat_map<const char*, int64_t> expected_metrics =
       GetExpectedRendererMetrics();
   expected_metrics["NumberOfExtensions"] = 1;
+  expected_metrics["Uptime"] = 21;
   uint64_t dump_guid = 333;
 
   GlobalMemoryDumpPtr global_dump(
       memory_instrumentation::mojom::GlobalMemoryDump::New());
-  PopulateRendererMetrics(global_dump, expected_metrics, &uptime_tracker_, 401);
+  PopulateRendererMetrics(global_dump, expected_metrics, 401);
 
   scoped_refptr<ProcessMemoryMetricsEmitterFake> emitter(
       new ProcessMemoryMetricsEmitterFake(test_ukm_recorder_));
@@ -398,7 +379,7 @@
   std::vector<base::flat_map<const char*, int64_t>> entries_metrics;
   for (const auto& ptype : entries_ptypes) {
     auto expected_metrics = GetExpectedProcessMetrics(ptype);
-    PopulateMetrics(global_dump, ptype, expected_metrics, &uptime_tracker_);
+    PopulateMetrics(global_dump, ptype, expected_metrics);
     entries_metrics.push_back(expected_metrics);
   }
 
@@ -427,7 +408,7 @@
         memory_instrumentation::mojom::GlobalMemoryDump::New());
     for (const auto& ptype : entries_ptypes[i]) {
       auto expected_metrics = GetExpectedProcessMetrics(ptype);
-      PopulateMetrics(global_dump, ptype, expected_metrics, &uptime_tracker_);
+      PopulateMetrics(global_dump, ptype, expected_metrics);
       expected_metrics.erase("TimeSinceLastVisible");
       entries_metrics.push_back(expected_metrics);
     }
@@ -447,7 +428,7 @@
   base::flat_map<const char*, int64_t> expected_metrics =
       GetExpectedRendererMetrics();
   AddPageMetrics(expected_metrics);
-  PopulateRendererMetrics(global_dump, expected_metrics, &uptime_tracker_, 201);
+  PopulateRendererMetrics(global_dump, expected_metrics, 201);
 
   scoped_refptr<ProcessMemoryMetricsEmitterFake> emitter(
       new ProcessMemoryMetricsEmitterFake(test_ukm_recorder_));
@@ -481,7 +462,7 @@
   base::flat_map<const char*, int64_t> expected_metrics =
       GetExpectedRendererMetrics();
   AddPageMetrics(expected_metrics);
-  PopulateRendererMetrics(global_dump, expected_metrics, &uptime_tracker_, 201);
+  PopulateRendererMetrics(global_dump, expected_metrics, 201);
 
   scoped_refptr<ProcessMemoryMetricsEmitterFake> emitter(
       new ProcessMemoryMetricsEmitterFake(test_ukm_recorder_));
@@ -514,9 +495,9 @@
       memory_instrumentation::mojom::GlobalMemoryDump::New());
   base::flat_map<const char*, int64_t> expected_metrics =
       GetExpectedRendererMetrics();
-  PopulateRendererMetrics(global_dump, expected_metrics, &uptime_tracker_, 200);
-  PopulateRendererMetrics(global_dump, expected_metrics, &uptime_tracker_, 201);
-  PopulateRendererMetrics(global_dump, expected_metrics, &uptime_tracker_, 202);
+  PopulateRendererMetrics(global_dump, expected_metrics, 200);
+  PopulateRendererMetrics(global_dump, expected_metrics, 201);
+  PopulateRendererMetrics(global_dump, expected_metrics, 202);
 
   scoped_refptr<ProcessMemoryMetricsEmitterFake> emitter(
       new ProcessMemoryMetricsEmitterFake(test_ukm_recorder_));
diff --git a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
index 908720e..80ee01e 100644
--- a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
+++ b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
@@ -58,15 +58,16 @@
 #include "components/ntp_snippets/user_classifier.h"
 #include "components/offline_pages/features/features.h"
 #include "components/prefs/pref_service.h"
-#include "components/safe_json/safe_json_parser.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/common/service_manager_connection.h"
 #include "google_apis/google_api_keys.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 
 #if defined(OS_ANDROID)
 #include "chrome/browser/android/chrome_feature_list.h"
@@ -307,7 +308,9 @@
   return base::MakeUnique<BreakingNewsGCMAppHandler>(
       gcm_driver, instance_id_profile_service->driver(), pref_service,
       std::move(subscription_manager),
-      base::Bind(&safe_json::SafeJsonParser::Parse),
+      base::Bind(
+          &data_decoder::SafeJsonParser::Parse,
+          content::ServiceManagerConnection::GetForProcess()->GetConnector()),
       base::MakeUnique<base::DefaultClock>(),
       /*token_validation_timer=*/base::MakeUnique<base::OneShotTimer>(),
       /*forced_subscription_timer=*/base::MakeUnique<base::OneShotTimer>());
@@ -373,7 +376,10 @@
 #endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
   auto suggestions_fetcher = base::MakeUnique<RemoteSuggestionsFetcherImpl>(
       signin_manager, token_service, request_context, pref_service,
-      language_histogram, base::Bind(&safe_json::SafeJsonParser::Parse),
+      language_histogram,
+      base::Bind(
+          &data_decoder::SafeJsonParser::Parse,
+          content::ServiceManagerConnection::GetForProcess()->GetConnector()),
       GetFetchEndpoint(chrome::GetChannel()), api_key, user_classifier);
 
   std::unique_ptr<BreakingNewsListener> breaking_news_raw_data_provider;
diff --git a/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc
index 4ee513c..c2e9ec77 100644
--- a/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc
+++ b/chrome/browser/ntp_snippets/contextual_content_suggestions_service_factory.cc
@@ -20,10 +20,11 @@
 #include "components/ntp_snippets/remote/cached_image_fetcher.h"
 #include "components/ntp_snippets/remote/remote_suggestions_database.h"
 #include "components/prefs/pref_service.h"
-#include "components/safe_json/safe_json_parser.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 
 #if defined(OS_ANDROID)
 #include "chrome/browser/android/chrome_feature_list.h"
@@ -98,7 +99,9 @@
   auto contextual_suggestions_fetcher =
       base::MakeUnique<ContextualSuggestionsFetcherImpl>(
           signin_manager, token_service, request_context, pref_service,
-          base::Bind(&safe_json::SafeJsonParser::Parse));
+          base::Bind(&data_decoder::SafeJsonParser::Parse,
+                     content::ServiceManagerConnection::GetForProcess()
+                         ->GetConnector()));
   const base::FilePath::CharType kDatabaseFolder[] =
       FILE_PATH_LITERAL("contextualSuggestionsDatabase");
   base::FilePath database_dir(profile->GetPath().Append(kDatabaseFolder));
diff --git a/chrome/browser/ntp_tiles/chrome_popular_sites_factory.cc b/chrome/browser/ntp_tiles/chrome_popular_sites_factory.cc
index 0368cd6..3cc880ab 100644
--- a/chrome/browser/ntp_tiles/chrome_popular_sites_factory.cc
+++ b/chrome/browser/ntp_tiles/chrome_popular_sites_factory.cc
@@ -10,13 +10,16 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "components/ntp_tiles/popular_sites_impl.h"
-#include "components/safe_json/safe_json_parser.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 
 std::unique_ptr<ntp_tiles::PopularSites>
 ChromePopularSitesFactory::NewForProfile(Profile* profile) {
   return base::MakeUnique<ntp_tiles::PopularSitesImpl>(
       profile->GetPrefs(), TemplateURLServiceFactory::GetForProfile(profile),
       g_browser_process->variations_service(), profile->GetRequestContext(),
-      base::Bind(safe_json::SafeJsonParser::Parse));
+      base::Bind(
+          data_decoder::SafeJsonParser::Parse,
+          content::ServiceManagerConnection::GetForProcess()->GetConnector()));
 }
diff --git a/chrome/browser/plugins/plugins_resource_service.cc b/chrome/browser/plugins/plugins_resource_service.cc
index eb38078..647f8adc 100644
--- a/chrome/browser/plugins/plugins_resource_service.cc
+++ b/chrome/browser/plugins/plugins_resource_service.cc
@@ -14,7 +14,8 @@
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
-#include "components/safe_json/safe_json_parser.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 #include "url/gurl.h"
 
 namespace {
@@ -82,7 +83,9 @@
           kCacheUpdateDelayMs,
           g_browser_process->system_request_context(),
           switches::kDisableBackgroundNetworking,
-          base::Bind(safe_json::SafeJsonParser::Parse),
+          base::Bind(data_decoder::SafeJsonParser::Parse,
+                     content::ServiceManagerConnection::GetForProcess()
+                         ->GetConnector()),
           kTrafficAnnotation) {}
 
 void PluginsResourceService::Init() {
diff --git a/chrome/browser/predictors/loading_test_util.cc b/chrome/browser/predictors/loading_test_util.cc
index 7c97a9b..65ed703 100644
--- a/chrome/browser/predictors/loading_test_util.cc
+++ b/chrome/browser/predictors/loading_test_util.cc
@@ -204,6 +204,7 @@
     config->max_hosts_to_track = 2;
     config->min_url_visit_count = 2;
     config->max_resources_per_entry = 4;
+    config->max_origins_per_entry = 5;
     config->max_consecutive_misses = 2;
     config->max_redirect_consecutive_misses = 2;
     config->min_resource_confidence_to_trigger_prefetch = 0.5;
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.h b/chrome/browser/predictors/resource_prefetch_predictor.h
index ada7851..7253988 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor.h
@@ -188,6 +188,8 @@
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, NavigationUrlNotInDB);
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest,
                            NavigationUrlNotInDBAndDBFull);
+  FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest,
+                           NavigationManyResourcesWithDifferentOrigins);
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, RedirectUrlNotInDB);
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, RedirectUrlInDB);
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, OnMainFrameRequest);
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
index 1b1d960..1faf3cc 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
@@ -771,6 +771,68 @@
   EXPECT_EQ(mock_tables_->origin_table_.data_, expected_origin_data);
 }
 
+TEST_F(ResourcePrefetchPredictorTest,
+       NavigationManyResourcesWithDifferentOrigins) {
+  const int kVisitCount = 4;
+  AddUrlToHistory("http://www.google.com", kVisitCount);
+
+  URLRequestSummary main_frame =
+      CreateURLRequestSummary(1, "http://www.google.com");
+
+  auto gen = [](int i) {
+    return base::StringPrintf("http://cdn%d.google.com/script.js", i);
+  };
+  std::vector<URLRequestSummary> resources;
+  const int num_resources =
+      std::max(predictor_->config_.max_resources_per_entry,
+               predictor_->config_.max_origins_per_entry) +
+      10;
+  for (int i = 1; i <= num_resources; ++i) {
+    resources.push_back(CreateURLRequestSummary(
+        1, "http://www.google.com", gen(i), content::RESOURCE_TYPE_SCRIPT,
+        net::MEDIUM, "text/javascript", false));
+  }
+
+  auto page_summary = CreatePageRequestSummary(
+      "http://www.google.com", "http://www.google.com", resources);
+
+  StrictMock<MockResourcePrefetchPredictorObserver> mock_observer(predictor_);
+  EXPECT_CALL(mock_observer, OnNavigationLearned(kVisitCount, page_summary));
+
+  predictor_->RecordPageRequestSummary(
+      base::MakeUnique<PageRequestSummary>(page_summary));
+  profile_->BlockUntilHistoryProcessesPendingRequests();
+
+  PrefetchData url_data = CreatePrefetchData("http://www.google.com/");
+  for (int i = 1;
+       i <= static_cast<int>(predictor_->config_.max_resources_per_entry);
+       ++i) {
+    InitializeResourceData(url_data.add_resources(), gen(i),
+                           content::RESOURCE_TYPE_SCRIPT, 1, 0, 0, i,
+                           net::MEDIUM, false, false);
+  }
+  EXPECT_EQ(mock_tables_->url_resource_table_.data_,
+            PrefetchDataMap({{url_data.primary_key(), url_data}}));
+
+  PrefetchData host_data = CreatePrefetchData("www.google.com");
+  host_data.mutable_resources()->CopyFrom(url_data.resources());
+  EXPECT_EQ(mock_tables_->host_resource_table_.data_,
+            PrefetchDataMap({{host_data.primary_key(), host_data}}));
+
+  OriginData origin_data = CreateOriginData("www.google.com");
+  InitializeOriginStat(origin_data.add_origins(), "http://www.google.com/", 1,
+                       0, 0, 1, false, true);
+  for (int i = 1;
+       i <= static_cast<int>(predictor_->config_.max_origins_per_entry) - 1;
+       ++i) {
+    InitializeOriginStat(origin_data.add_origins(),
+                         GURL(gen(i)).GetOrigin().spec(), 1, 0, 0, i + 1, false,
+                         true);
+  }
+  EXPECT_EQ(mock_tables_->origin_table_.data_,
+            OriginDataMap({{origin_data.host(), origin_data}}));
+}
+
 TEST_F(ResourcePrefetchPredictorTest, RedirectUrlNotInDB) {
   const int kVisitCount = 4;
   AddUrlToHistory("https://facebook.com/google", kVisitCount);
diff --git a/chrome/browser/resource_coordinator/browser_child_process_watcher.cc b/chrome/browser/resource_coordinator/browser_child_process_watcher.cc
new file mode 100644
index 0000000..e91d89b
--- /dev/null
+++ b/chrome/browser/resource_coordinator/browser_child_process_watcher.cc
@@ -0,0 +1,68 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/resource_coordinator/browser_child_process_watcher.h"
+
+#include "base/process/process.h"
+#include "content/public/browser/child_process_data.h"
+#include "content/public/common/process_type.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
+
+namespace resource_coordinator {
+
+BrowserChildProcessWatcher::BrowserChildProcessWatcher() {
+  BrowserChildProcessObserver::Add(this);
+}
+
+BrowserChildProcessWatcher::~BrowserChildProcessWatcher() {
+  BrowserChildProcessObserver::Remove(this);
+}
+
+void BrowserChildProcessWatcher::BrowserChildProcessLaunchedAndConnected(
+    const content::ChildProcessData& data) {
+  if (!resource_coordinator::IsResourceCoordinatorEnabled())
+    return;
+
+  if (data.process_type == content::PROCESS_TYPE_GPU) {
+    gpu_process_resource_coordinator_ =
+        base::MakeUnique<resource_coordinator::ResourceCoordinatorInterface>(
+            content::ServiceManagerConnection::GetForProcess()->GetConnector(),
+            resource_coordinator::CoordinationUnitType::kProcess);
+
+    base::ProcessId pid = base::GetProcId(data.handle);
+    gpu_process_resource_coordinator_->SetProperty(
+        resource_coordinator::mojom::PropertyType::kPID, pid);
+
+    gpu_process_resource_coordinator_->SetProperty(
+        resource_coordinator::mojom::PropertyType::kLaunchTime,
+        base::Time::Now().ToTimeT());
+  }
+}
+
+void BrowserChildProcessWatcher::BrowserChildProcessHostDisconnected(
+    const content::ChildProcessData& data) {
+  if (data.process_type == content::PROCESS_TYPE_GPU)
+    GPUProcessStopped();
+}
+
+void BrowserChildProcessWatcher::BrowserChildProcessCrashed(
+    const content::ChildProcessData& data,
+    int exit_code) {
+  if (data.process_type == content::PROCESS_TYPE_GPU)
+    GPUProcessStopped();
+}
+
+void BrowserChildProcessWatcher::BrowserChildProcessKilled(
+    const content::ChildProcessData& data,
+    int exit_code) {
+  if (data.process_type == content::PROCESS_TYPE_GPU)
+    GPUProcessStopped();
+}
+
+void BrowserChildProcessWatcher::GPUProcessStopped() {
+  gpu_process_resource_coordinator_.reset();
+}
+
+}  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/browser_child_process_watcher.h b/chrome/browser/resource_coordinator/browser_child_process_watcher.h
new file mode 100644
index 0000000..8e637e1
--- /dev/null
+++ b/chrome/browser/resource_coordinator/browser_child_process_watcher.h
@@ -0,0 +1,42 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_BROWSER_CHILD_PROCESS_WATCHER_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_BROWSER_CHILD_PROCESS_WATCHER_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "content/public/browser/browser_child_process_observer.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/resource_coordinator/public/cpp/resource_coordinator_interface.h"
+
+namespace resource_coordinator {
+
+class BrowserChildProcessWatcher : public content::BrowserChildProcessObserver {
+ public:
+  BrowserChildProcessWatcher();
+  ~BrowserChildProcessWatcher() override;
+
+ private:
+  // BrowserChildProcessObserver overrides.
+  void BrowserChildProcessLaunchedAndConnected(
+      const content::ChildProcessData& data) override;
+  void BrowserChildProcessHostDisconnected(
+      const content::ChildProcessData& data) override;
+  void BrowserChildProcessCrashed(const content::ChildProcessData& data,
+                                  int exit_code) override;
+  void BrowserChildProcessKilled(const content::ChildProcessData& data,
+                                 int exit_code) override;
+
+  void GPUProcessStopped();
+
+  std::unique_ptr<resource_coordinator::ResourceCoordinatorInterface>
+      gpu_process_resource_coordinator_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserChildProcessWatcher);
+};
+
+}  // namespace resource_coordinator
+
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_BROWSER_CHILD_PROCESS_WATCHER_H_
diff --git a/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc
new file mode 100644
index 0000000..d8f9552
--- /dev/null
+++ b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc
@@ -0,0 +1,38 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h"
+
+#include "base/process/process.h"
+#include "chrome/browser/resource_coordinator/browser_child_process_watcher.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
+
+ChromeBrowserMainExtraPartsResourceCoordinator::
+    ChromeBrowserMainExtraPartsResourceCoordinator() = default;
+ChromeBrowserMainExtraPartsResourceCoordinator::
+    ~ChromeBrowserMainExtraPartsResourceCoordinator() = default;
+
+void ChromeBrowserMainExtraPartsResourceCoordinator::
+    ServiceManagerConnectionStarted(
+        content::ServiceManagerConnection* connection) {
+  if (!resource_coordinator::IsResourceCoordinatorEnabled())
+    return;
+
+  process_resource_coordinator_ =
+      base::MakeUnique<resource_coordinator::ResourceCoordinatorInterface>(
+          connection->GetConnector(),
+          resource_coordinator::CoordinationUnitType::kProcess);
+
+  process_resource_coordinator_->SetProperty(
+      resource_coordinator::mojom::PropertyType::kPID,
+      base::Process::Current().Pid());
+
+  process_resource_coordinator_->SetProperty(
+      resource_coordinator::mojom::PropertyType::kLaunchTime,
+      base::Time::Now().ToTimeT());
+
+  browser_child_process_watcher_ =
+      base::MakeUnique<resource_coordinator::BrowserChildProcessWatcher>();
+}
diff --git a/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h
new file mode 100644
index 0000000..2305c5b
--- /dev/null
+++ b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h
@@ -0,0 +1,34 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_CHROME_BROWSER_MAIN_EXTRA_PARTS_RESOURCE_COORDINATOR_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_CHROME_BROWSER_MAIN_EXTRA_PARTS_RESOURCE_COORDINATOR_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "chrome/browser/chrome_browser_main_extra_parts.h"
+#include "chrome/browser/resource_coordinator/browser_child_process_watcher.h"
+#include "services/resource_coordinator/public/cpp/resource_coordinator_interface.h"
+
+class ChromeBrowserMainExtraPartsResourceCoordinator
+    : public ChromeBrowserMainExtraParts {
+ public:
+  ChromeBrowserMainExtraPartsResourceCoordinator();
+  ~ChromeBrowserMainExtraPartsResourceCoordinator() override;
+
+ private:
+  // ChromeBrowserMainExtraParts overrides.
+  void ServiceManagerConnectionStarted(
+      content::ServiceManagerConnection* connection) override;
+
+  std::unique_ptr<resource_coordinator::ResourceCoordinatorInterface>
+      process_resource_coordinator_;
+
+  std::unique_ptr<resource_coordinator::BrowserChildProcessWatcher>
+      browser_child_process_watcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainExtraPartsResourceCoordinator);
+};
+
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_CHROME_BROWSER_MAIN_EXTRA_PARTS_RESOURCE_COORDINATOR_H_
diff --git a/chrome/browser/safe_json_parser_browsertest.cc b/chrome/browser/safe_json_parser_browsertest.cc
index 1432563..4c66ab8 100644
--- a/chrome/browser/safe_json_parser_browsertest.cc
+++ b/chrome/browser/safe_json_parser_browsertest.cc
@@ -9,13 +9,14 @@
 #include "base/json/json_writer.h"
 #include "base/values.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "components/safe_json/safe_json_parser.h"
+#include "content/public/common/service_manager_connection.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 
 namespace {
 
-using safe_json::SafeJsonParser;
+using data_decoder::SafeJsonParser;
 
 std::string MaybeToJson(const base::Value* value) {
   if (!value)
@@ -55,7 +56,9 @@
       error_callback = base::Bind(&SafeJsonParserTest::ExpectError,
                                   base::Unretained(this), error);
     }
-    SafeJsonParser::Parse(json, success_callback, error_callback);
+    SafeJsonParser::Parse(
+        content::ServiceManagerConnection::GetForProcess()->GetConnector(),
+        json, success_callback, error_callback);
 
     message_loop_runner_->Run();
     message_loop_runner_ = nullptr;
@@ -89,8 +92,7 @@
   scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
 };
 
-// Flaky in debug builds: http://crbug.com/611067
-IN_PROC_BROWSER_TEST_F(SafeJsonParserTest, DISABLED_Parse) {
+IN_PROC_BROWSER_TEST_F(SafeJsonParserTest, Parse) {
   TestParse("{}");
   TestParse("choke");
   TestParse("{\"awesome\": true}");
diff --git a/chrome/browser/search/one_google_bar/one_google_bar_fetcher_impl.cc b/chrome/browser/search/one_google_bar/one_google_bar_fetcher_impl.cc
index 969430bd..187b89a7 100644
--- a/chrome/browser/search/one_google_bar/one_google_bar_fetcher_impl.cc
+++ b/chrome/browser/search/one_google_bar/one_google_bar_fetcher_impl.cc
@@ -16,14 +16,15 @@
 #include "chrome/common/chrome_content_client.h"
 #include "components/google/core/browser/google_url_tracker.h"
 #include "components/google/core/browser/google_util.h"
-#include "components/safe_json/safe_json_parser.h"
 #include "components/variations/net/variations_http_headers.h"
+#include "content/public/common/service_manager_connection.h"
 #include "net/base/load_flags.h"
 #include "net/base/url_util.h"
 #include "net/http/http_status_code.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 
 namespace {
 
@@ -294,7 +295,8 @@
     response = response.substr(strlen(kResponsePreamble));
   }
 
-  safe_json::SafeJsonParser::Parse(
+  data_decoder::SafeJsonParser::Parse(
+      content::ServiceManagerConnection::GetForProcess()->GetConnector(),
       response,
       base::Bind(&OneGoogleBarFetcherImpl::JsonParsed,
                  weak_ptr_factory_.GetWeakPtr()),
diff --git a/chrome/browser/search/one_google_bar/one_google_bar_fetcher_impl_unittest.cc b/chrome/browser/search/one_google_bar/one_google_bar_fetcher_impl_unittest.cc
index 491a61b..685262a7 100644
--- a/chrome/browser/search/one_google_bar/one_google_bar_fetcher_impl_unittest.cc
+++ b/chrome/browser/search/one_google_bar/one_google_bar_fetcher_impl_unittest.cc
@@ -7,7 +7,6 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
 #include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
@@ -16,12 +15,14 @@
 #include "base/time/time.h"
 #include "chrome/browser/search/one_google_bar/one_google_bar_data.h"
 #include "components/google/core/browser/google_url_tracker.h"
-#include "components/safe_json/testing_json_parser.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_service_manager_context.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_status_code.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_request_status.h"
 #include "net/url_request/url_request_test_util.h"
+#include "services/data_decoder/public/cpp/testing_json_parser.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -108,10 +109,11 @@
 
  private:
   // variations::AppendVariationHeaders and SafeJsonParser require a
-  // ThreadTaskRunnerHandle to be set.
-  base::MessageLoop message_loop_;
+  // threads and a ServiceManagerConnection to be set.
+  content::TestBrowserThreadBundle thread_bundle_;
+  content::TestServiceManagerContext service_manager_context_;
 
-  safe_json::TestingJsonParser::ScopedFactoryOverride factory_override_;
+  data_decoder::TestingJsonParser::ScopedFactoryOverride factory_override_;
 
   net::TestURLFetcherFactory url_fetcher_factory_;
 
diff --git a/chrome/browser/supervised_user/supervised_user_whitelist_service_unittest.cc b/chrome/browser/supervised_user/supervised_user_whitelist_service_unittest.cc
index 2829bf6..9246b59 100644
--- a/chrome/browser/supervised_user/supervised_user_whitelist_service_unittest.cc
+++ b/chrome/browser/supervised_user/supervised_user_whitelist_service_unittest.cc
@@ -31,7 +31,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if !defined(OS_ANDROID)
-#include "components/safe_json/testing_json_parser.h"
+#include "services/data_decoder/public/cpp/testing_json_parser.h"
 #endif
 
 namespace {
@@ -162,7 +162,7 @@
   TestingProfile profile_;
 
 #if !defined(OS_ANDROID)
-  safe_json::TestingJsonParser::ScopedFactoryOverride factory_override_;
+  data_decoder::TestingJsonParser::ScopedFactoryOverride factory_override_;
 #endif
 
   std::unique_ptr<MockSupervisedUserWhitelistInstaller> installer_;
diff --git a/chrome/browser/thumbnails/thumbnail_service_impl.cc b/chrome/browser/thumbnails/thumbnail_service_impl.cc
index 2ca6786..b675587be 100644
--- a/chrome/browser/thumbnails/thumbnail_service_impl.cc
+++ b/chrome/browser/thumbnails/thumbnail_service_impl.cc
@@ -4,13 +4,11 @@
 
 #include "chrome/browser/thumbnails/thumbnail_service_impl.h"
 
-#include "base/feature_list.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/time/time.h"
 #include "chrome/browser/history/history_utils.h"
 #include "chrome/browser/history/top_sites_factory.h"
 #include "chrome/browser/thumbnails/thumbnailing_context.h"
-#include "chrome/common/chrome_features.h"
 #include "content/public/browser/browser_thread.h"
 #include "url/gurl.h"
 
@@ -83,19 +81,15 @@
     if (local_ptr->IsNonForcedFull())
       return false;
 
-    if (base::FeatureList::IsEnabled(
-            features::kCaptureThumbnailDependingOnTransitionType)) {
-      // Skip if the transition type is not interesting:
-      // Only new segments (roughly "initial navigations", e.g. not clicks on a
-      // link) can end up in TopSites (see HistoryBackend::UpdateSegments).
-      // Note that for pages that are already in TopSites, we don't care about
-      // the transition type, since for those we know we'll need the thumbnail.
-      if (!ui::PageTransitionCoreTypeIs(transition,
-                                        ui::PAGE_TRANSITION_TYPED) &&
-          !ui::PageTransitionCoreTypeIs(transition,
-                                        ui::PAGE_TRANSITION_AUTO_BOOKMARK)) {
-        return false;
-      }
+    // Skip if the transition type is not interesting:
+    // Only new segments (roughly "initial navigations", e.g. not clicks on a
+    // link) can end up in TopSites (see HistoryBackend::UpdateSegments).
+    // Note that for pages that are already in TopSites, we don't care about
+    // the transition type, since for those we know we'll need the thumbnail.
+    if (!ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) &&
+        !ui::PageTransitionCoreTypeIs(transition,
+                                      ui::PAGE_TRANSITION_AUTO_BOOKMARK)) {
+      return false;
     }
   }
 
diff --git a/chrome/browser/thumbnails/thumbnail_service_unittest.cc b/chrome/browser/thumbnails/thumbnail_service_unittest.cc
index 414bfee..a59bf4aae 100644
--- a/chrome/browser/thumbnails/thumbnail_service_unittest.cc
+++ b/chrome/browser/thumbnails/thumbnail_service_unittest.cc
@@ -9,10 +9,8 @@
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/history/history_utils.h"
 #include "chrome/browser/history/top_sites_factory.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/history/core/browser/top_sites_impl.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -161,10 +159,6 @@
 
 TEST_F(ThumbnailServiceTest,
        ShouldAcquireTempThumbnailDependingOnTransitionType) {
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(
-      features::kCaptureThumbnailDependingOnTransitionType);
-
   const GURL kUnknownURL("http://www.google.com/");
   const ui::PageTransition interesting_transition = ui::PAGE_TRANSITION_TYPED;
   const ui::PageTransition uninteresting_transition = ui::PAGE_TRANSITION_LINK;
diff --git a/chrome/browser/thumbnails/thumbnail_tab_helper.cc b/chrome/browser/thumbnails/thumbnail_tab_helper.cc
index 687c221..0ef7c193 100644
--- a/chrome/browser/thumbnails/thumbnail_tab_helper.cc
+++ b/chrome/browser/thumbnails/thumbnail_tab_helper.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/thumbnails/thumbnail_tab_helper.h"
 
-#include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/task_scheduler/task_traits.h"
@@ -12,7 +11,6 @@
 #include "chrome/browser/thumbnails/thumbnail_service.h"
 #include "chrome/browser/thumbnails/thumbnail_service_factory.h"
 #include "chrome/browser/thumbnails/thumbnail_utils.h"
-#include "chrome/common/chrome_features.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/notification_details.h"
@@ -59,16 +57,13 @@
 // UpdateThumbnailIfNecessary(), which updates the thumbnail for the current
 // tab if needed. The heuristics to judge whether to update the thumbnail are
 // implemented in ThumbnailService::ShouldAcquirePageThumbnail().
-// There are several triggers that can start the process:
+// There are two triggers that can start the process:
 // - When a renderer is about to be hidden (this usually occurs when the current
 //   tab is closed or another tab is clicked).
-// - If features::kCaptureThumbnailOnNavigatingAway is enabled: Just before
-//   navigating away from the current page.
+// - Just before navigating away from the current page.
 
 ThumbnailTabHelper::ThumbnailTabHelper(content::WebContents* contents)
     : content::WebContentsObserver(contents),
-      capture_on_navigating_away_(base::FeatureList::IsEnabled(
-          features::kCaptureThumbnailOnNavigatingAway)),
       page_transition_(ui::PAGE_TRANSITION_LINK),
       load_interrupted_(false),
       weak_factory_(this) {
@@ -122,12 +117,12 @@
       navigation_handle->IsSameDocument()) {
     return;
   }
-  if (capture_on_navigating_away_) {
-    // At this point, the new navigation has just been started, but the
-    // WebContents still shows the previous page. Grab a thumbnail before it
-    // goes away.
-    UpdateThumbnailIfNecessary();
-  }
+
+  // At this point, the new navigation has just been started, but the
+  // WebContents still shows the previous page. Grab a thumbnail before it
+  // goes away.
+  UpdateThumbnailIfNecessary();
+
   // Reset the page transition to some uninteresting type, since the actual
   // type isn't available at this point. We'll get it in DidFinishNavigation
   // (if that happens, which isn't guaranteed).
diff --git a/chrome/browser/thumbnails/thumbnail_tab_helper.h b/chrome/browser/thumbnails/thumbnail_tab_helper.h
index 68a40b3..0eb1da5 100644
--- a/chrome/browser/thumbnails/thumbnail_tab_helper.h
+++ b/chrome/browser/thumbnails/thumbnail_tab_helper.h
@@ -71,8 +71,6 @@
   // Indicates that the given widget has changed is visibility.
   void WidgetHidden(content::RenderWidgetHost* widget);
 
-  const bool capture_on_navigating_away_;
-
   content::NotificationRegistrar registrar_;
 
   ui::PageTransition page_transition_;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index f193af5..4872d16 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -73,12 +73,16 @@
     "autofill/popup_view_common.h",
     "blocked_content/blocked_window_params.cc",
     "blocked_content/blocked_window_params.h",
+    "blocked_content/console_logger.cc",
+    "blocked_content/console_logger.h",
     "blocked_content/popup_blocker_tab_helper.cc",
     "blocked_content/popup_blocker_tab_helper.h",
     "blocked_content/popup_opener_tab_helper.cc",
     "blocked_content/popup_opener_tab_helper.h",
     "blocked_content/popup_tracker.cc",
     "blocked_content/popup_tracker.h",
+    "blocked_content/safe_browsing_triggered_popup_blocker.cc",
+    "blocked_content/safe_browsing_triggered_popup_blocker.h",
     "blocked_content/scoped_visibility_tracker.cc",
     "blocked_content/scoped_visibility_tracker.h",
     "blocked_content/tab_under_navigation_throttle.cc",
@@ -428,9 +432,9 @@
     "//components/resources",
     "//components/safe_browsing/common:safe_browsing_prefs",
     "//components/safe_browsing/db:database_manager",
+    "//components/safe_browsing/db:util",
     "//components/safe_browsing/password_protection",
     "//components/safe_browsing/web_ui",
-    "//components/safe_json",
     "//components/search",
     "//components/search_engines",
     "//components/security_interstitials/core",
diff --git a/chrome/browser/ui/android/page_info/page_info_popup_android.cc b/chrome/browser/ui/android/page_info/page_info_popup_android.cc
index be6e53a..6a50ce9 100644
--- a/chrome/browser/ui/android/page_info/page_info_popup_android.cc
+++ b/chrome/browser/ui/android/page_info/page_info_popup_android.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "chrome/browser/ui/page_info/page_info.h"
 #include "chrome/browser/ui/page_info/page_info_ui.h"
+#include "chrome/common/chrome_features.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/security_state/core/security_state.h"
@@ -119,6 +120,8 @@
   permissions_to_display.push_back(CONTENT_SETTINGS_TYPE_POPUPS);
   permissions_to_display.push_back(CONTENT_SETTINGS_TYPE_ADS);
   permissions_to_display.push_back(CONTENT_SETTINGS_TYPE_AUTOPLAY);
+  if (base::FeatureList::IsEnabled(features::kSoundContentSetting))
+    permissions_to_display.push_back(CONTENT_SETTINGS_TYPE_SOUND);
 
   std::map<ContentSettingsType, ContentSetting>
       user_specified_settings_to_display;
diff --git a/chrome/browser/ui/app_list/search/common/json_response_fetcher.cc b/chrome/browser/ui/app_list/search/common/json_response_fetcher.cc
index 7975c35..2fbb1a6 100644
--- a/chrome/browser/ui/app_list/search/common/json_response_fetcher.cc
+++ b/chrome/browser/ui/app_list/search/common/json_response_fetcher.cc
@@ -9,10 +9,11 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
-#include "components/safe_json/safe_json_parser.h"
+#include "content/public/common/service_manager_connection.h"
 #include "net/base/load_flags.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 #include "url/gurl.h"
 
 namespace app_list {
@@ -76,9 +77,11 @@
   fetcher->GetResponseAsString(&json_data);
 
   // The parser will call us back via one of the callbacks.
-  safe_json::SafeJsonParser::Parse(
-      json_data, base::Bind(&JSONResponseFetcher::OnJsonParseSuccess,
-                            weak_factory_.GetWeakPtr()),
+  data_decoder::SafeJsonParser::Parse(
+      content::ServiceManagerConnection::GetForProcess()->GetConnector(),
+      json_data,
+      base::Bind(&JSONResponseFetcher::OnJsonParseSuccess,
+                 weak_factory_.GetWeakPtr()),
       base::Bind(&JSONResponseFetcher::OnJsonParseError,
                  weak_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/ui/blocked_content/console_logger.cc b/chrome/browser/ui/blocked_content/console_logger.cc
new file mode 100644
index 0000000..4bb56a54
--- /dev/null
+++ b/chrome/browser/ui/blocked_content/console_logger.cc
@@ -0,0 +1,18 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/blocked_content/console_logger.h"
+
+#include "base/logging.h"
+#include "content/public/browser/render_frame_host.h"
+
+ConsoleLogger::ConsoleLogger() = default;
+ConsoleLogger::~ConsoleLogger() = default;
+
+void ConsoleLogger::LogInFrame(content::RenderFrameHost* render_frame_host,
+                               content::ConsoleMessageLevel level,
+                               const std::string& message) {
+  DCHECK(render_frame_host);
+  render_frame_host->AddMessageToConsole(level, message);
+}
diff --git a/chrome/browser/ui/blocked_content/console_logger.h b/chrome/browser/ui/blocked_content/console_logger.h
new file mode 100644
index 0000000..810b638
--- /dev/null
+++ b/chrome/browser/ui/blocked_content/console_logger.h
@@ -0,0 +1,34 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_BLOCKED_CONTENT_CONSOLE_LOGGER_H_
+#define CHROME_BROWSER_UI_BLOCKED_CONTENT_CONSOLE_LOGGER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "content/public/common/console_message_level.h"
+
+namespace content {
+class RenderFrameHost;
+}
+
+// This simple class just forwards console logging to the associated
+// RenderFrameHost, to send down to the renderer. It exists for unit tests to
+// mock out, allowing unit tests to expect console messages without having to
+// write a full browser test.
+class ConsoleLogger {
+ public:
+  ConsoleLogger();
+  virtual ~ConsoleLogger();
+
+  virtual void LogInFrame(content::RenderFrameHost* render_frame_host,
+                          content::ConsoleMessageLevel level,
+                          const std::string& message);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ConsoleLogger);
+};
+
+#endif  // CHROME_BROWSER_UI_BLOCKED_CONTENT_CONSOLE_LOGGER_H_
diff --git a/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.cc b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.cc
new file mode 100644
index 0000000..54c7f65
--- /dev/null
+++ b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.cc
@@ -0,0 +1,142 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.h"
+
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_macros.h"
+#include "chrome/browser/ui/blocked_content/console_logger.h"
+#include "components/safe_browsing/db/util.h"
+#include "components/safe_browsing/db/v4_protocol_manager_util.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/page_navigator.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/console_message_level.h"
+#include "third_party/WebKit/public/web/WebTriggeringEventInfo.h"
+
+namespace {
+
+const char kIgnoreSublistsParam[] = "ignore_sublists";
+
+void LogAction(SafeBrowsingTriggeredPopupBlocker::Action action) {
+  UMA_HISTOGRAM_ENUMERATION("ContentSettings.Popups.StrongBlockerActions",
+                            action,
+                            SafeBrowsingTriggeredPopupBlocker::Action::kCount);
+}
+
+}  // namespace
+
+using safe_browsing::SubresourceFilterLevel;
+
+const base::Feature kAbusiveExperienceEnforce{
+    "AbusiveExperienceEnforce", base::FEATURE_DISABLED_BY_DEFAULT};
+
+SafeBrowsingTriggeredPopupBlocker::~SafeBrowsingTriggeredPopupBlocker() =
+    default;
+
+SafeBrowsingTriggeredPopupBlocker::SafeBrowsingTriggeredPopupBlocker(
+    content::WebContents* web_contents,
+    std::unique_ptr<ConsoleLogger> logger)
+    : content::WebContentsObserver(web_contents),
+      scoped_observer_(this),
+      logger_(std::move(logger)),
+      ignore_sublists_(
+          base::GetFieldTrialParamByFeatureAsBool(kAbusiveExperienceEnforce,
+                                                  kIgnoreSublistsParam,
+                                                  false /* default_value */)) {
+  if (auto* observer_manager =
+          subresource_filter::SubresourceFilterObserverManager::FromWebContents(
+              web_contents)) {
+    scoped_observer_.Add(observer_manager);
+  }
+}
+
+bool SafeBrowsingTriggeredPopupBlocker::ShouldApplyStrongPopupBlocker(
+    const content::OpenURLParams* open_url_params) {
+  LogAction(Action::kConsidered);
+  if (!is_triggered_for_current_committed_load_)
+    return false;
+
+  bool should_block = true;
+  if (open_url_params) {
+    should_block = open_url_params->triggering_event_info ==
+                   blink::WebTriggeringEventInfo::kFromUntrustedEvent;
+  }
+
+  // TODO(csharrison): Log some dry-run style metrics for when the feature is
+  // not enabled.
+  if (!base::FeatureList::IsEnabled(kAbusiveExperienceEnforce)) {
+    return false;
+  }
+
+  // TODO(csharrison): Migrate SubresourceFilter* popup metrics.
+  if (should_block) {
+    LogAction(Action::kBlocked);
+    logger_->LogInFrame(web_contents()->GetMainFrame(),
+                        content::CONSOLE_MESSAGE_LEVEL_ERROR,
+                        kAbusiveEnforceMessage);
+  }
+  return should_block;
+}
+
+void SafeBrowsingTriggeredPopupBlocker::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (!navigation_handle->IsInMainFrame())
+    return;
+
+  base::Optional<SubresourceFilterLevel> level;
+  level_for_next_committed_navigation_.swap(level);
+
+  // Only care about main frame navigations that commit.
+  if (!navigation_handle->HasCommitted() ||
+      navigation_handle->IsSameDocument()) {
+    return;
+  }
+
+  is_triggered_for_current_committed_load_ = false;
+  if (navigation_handle->IsErrorPage())
+    return;
+
+  // Log a warning only if we've matched a warn-only safe browsing list.
+  if (level == SubresourceFilterLevel::ENFORCE) {
+    is_triggered_for_current_committed_load_ = true;
+    LogAction(Action::kEnforcedSite);
+  } else if (level == SubresourceFilterLevel::WARN) {
+    logger_->LogInFrame(web_contents()->GetMainFrame(),
+                        content::CONSOLE_MESSAGE_LEVEL_WARNING,
+                        kAbusiveWarnMessage);
+    LogAction(Action::kWarningSite);
+  }
+  LogAction(Action::kNavigation);
+}
+
+// This method will always be called before the DidFinishNavigation associated
+// with this handle.
+void SafeBrowsingTriggeredPopupBlocker::OnSafeBrowsingCheckComplete(
+    content::NavigationHandle* navigation_handle,
+    safe_browsing::SBThreatType threat_type,
+    const safe_browsing::ThreatMetadata& threat_metadata) {
+  DCHECK(navigation_handle->IsInMainFrame());
+  if (threat_type !=
+      safe_browsing::SBThreatType::SB_THREAT_TYPE_SUBRESOURCE_FILTER)
+    return;
+  if (ignore_sublists_) {
+    // No warning for ignore_sublists mode.
+    level_for_next_committed_navigation_ = SubresourceFilterLevel::ENFORCE;
+    return;
+  }
+
+  auto abusive = threat_metadata.subresource_filter_match.find(
+      safe_browsing::SubresourceFilterType::ABUSIVE);
+  if (abusive == threat_metadata.subresource_filter_match.end())
+    return;
+  level_for_next_committed_navigation_ = abusive->second;
+}
+
+void SafeBrowsingTriggeredPopupBlocker::OnSubresourceFilterGoingAway() {
+  scoped_observer_.RemoveAll();
+}
diff --git a/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.h b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.h
new file mode 100644
index 0000000..87e4154
--- /dev/null
+++ b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.h
@@ -0,0 +1,112 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_BLOCKED_CONTENT_SAFE_BROWSING_TRIGGERED_POPUP_BLOCKER_H_
+#define CHROME_BROWSER_UI_BLOCKED_CONTENT_SAFE_BROWSING_TRIGGERED_POPUP_BLOCKER_H_
+
+#include <memory>
+
+#include "base/feature_list.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "base/scoped_observer.h"
+#include "components/safe_browsing/db/util.h"
+#include "components/subresource_filter/content/browser/subresource_filter_observer.h"
+#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+struct OpenURLParams;
+class WebContents;
+}  // namespace content
+
+class ConsoleLogger;
+
+extern const base::Feature kAbusiveExperienceEnforce;
+
+constexpr char kAbusiveEnforceMessage[] =
+    "Chrome prevented this site from opening a new tab or window. Learn more "
+    "at https://www.chromestatus.com/feature/5243055179300864";
+constexpr char kAbusiveWarnMessage[] =
+    "Chrome might start preventing this site from opening new tabs or "
+    "windows in the future. Learn more at "
+    "https://www.chromestatus.com/feature/5243055179300864";
+
+// This class observes main frame navigation checks incoming from safe browsing
+// (currently implemented by the subresource_filter component). For navigations
+// which match the ABUSIVE safe browsing list, this class will help the popup
+// tab helper in applying a stronger policy for blocked popups.
+class SafeBrowsingTriggeredPopupBlocker
+    : public content::WebContentsObserver,
+      public subresource_filter::SubresourceFilterObserver {
+ public:
+  // This enum backs a histogram. Please append new entries to the end, and
+  // update enums.xml when making changes.
+  enum class Action : int {
+    // User committed a navigation to a non-error page.
+    kNavigation,
+
+    // Safe Browsing considered this page abusive and the page should be warned.
+    // Logged at navigation commit.
+    kWarningSite,
+
+    // Safe Browsing considered this page abusive and the page should be be
+    // blocked against. Logged at navigation commit.
+    kEnforcedSite,
+
+    // The popup blocker called into this object to ask if the strong blocking
+    // should be applied.
+    kConsidered,
+
+    // This object responded to the popup blocker in the affirmative, and the
+    // popup was blocked.
+    kBlocked,
+
+    // Add new entries before this one
+    kCount
+  };
+  explicit SafeBrowsingTriggeredPopupBlocker(
+      content::WebContents* web_contents,
+      std::unique_ptr<ConsoleLogger> logger);
+  ~SafeBrowsingTriggeredPopupBlocker() override;
+
+  bool ShouldApplyStrongPopupBlocker(
+      const content::OpenURLParams* open_url_params);
+
+ private:
+  // content::WebContentsObserver:
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
+
+  // subresource_filter::SubresourceFilterObserver:
+  void OnSafeBrowsingCheckComplete(
+      content::NavigationHandle* navigation_handle,
+      safe_browsing::SBThreatType threat_type,
+      const safe_browsing::ThreatMetadata& threat_metadata) override;
+  void OnSubresourceFilterGoingAway() override;
+
+  ScopedObserver<subresource_filter::SubresourceFilterObserverManager,
+                 subresource_filter::SubresourceFilterObserver>
+      scoped_observer_;
+
+  // Whether the next main frame navigation that commits should trigger the
+  // stronger popup blocker in enforce or warn mode.
+  base::Optional<safe_browsing::SubresourceFilterLevel>
+      level_for_next_committed_navigation_;
+
+  std::unique_ptr<ConsoleLogger> logger_;
+
+  // Whether to ignore the threat pattern type. Useful for flexibility because
+  // we have to wait until metadata patterns reach Stable before using them
+  // without error. Governed by a variation param.
+  bool ignore_sublists_ = false;
+
+  // Whether the current committed page load should trigger the stronger popup
+  // blocker.
+  bool is_triggered_for_current_committed_load_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingTriggeredPopupBlocker);
+};
+
+#endif  // CHROME_BROWSER_UI_BLOCKED_CONTENT_SAFE_BROWSING_TRIGGERED_POPUP_BLOCKER_H_
diff --git a/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
new file mode 100644
index 0000000..15e2e456f
--- /dev/null
+++ b/chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc
@@ -0,0 +1,346 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/test/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
+#include "chrome/browser/subresource_filter/chrome_subresource_filter_client.h"
+#include "chrome/browser/ui/blocked_content/console_logger.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "components/safe_browsing/db/v4_protocol_manager_util.h"
+#include "components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h"
+#include "content/public/test/navigation_simulator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/web/WebTriggeringEventInfo.h"
+#include "ui/base/page_transition_types.h"
+#include "ui/base/window_open_disposition.h"
+#include "url/gurl.h"
+
+class TestConsoleLogger : public ConsoleLogger {
+ public:
+  TestConsoleLogger() {}
+  ~TestConsoleLogger() override {}
+
+  void LogInFrame(content::RenderFrameHost* render_frame_host,
+                  content::ConsoleMessageLevel level,
+                  const std::string& message) override {
+    messages_.push_back(message);
+  }
+
+  const std::vector<std::string>& messages() { return messages_; }
+
+ private:
+  std::vector<std::string> messages_;
+  DISALLOW_COPY_AND_ASSIGN(TestConsoleLogger);
+};
+
+class SafeBrowsingTriggeredPopupBlockerTest
+    : public ChromeRenderViewHostTestHarness {
+ public:
+  SafeBrowsingTriggeredPopupBlockerTest() {}
+  ~SafeBrowsingTriggeredPopupBlockerTest() override {}
+
+  // ChromeRenderViewHostTestHarness:
+  void SetUp() override {
+    ChromeRenderViewHostTestHarness::SetUp();
+
+    // Set up safe browsing service with the fake database manager.
+    //
+    // TODO(csharrison): This is a bit ugly. See if the instructions in
+    // test_safe_browsing_service.h can be adapted to be used in unit tests.
+    safe_browsing::TestSafeBrowsingServiceFactory sb_service_factory;
+    fake_safe_browsing_database_ = new FakeSafeBrowsingDatabaseManager();
+    sb_service_factory.SetTestDatabaseManager(
+        fake_safe_browsing_database_.get());
+    safe_browsing::SafeBrowsingService::RegisterFactory(&sb_service_factory);
+    auto* safe_browsing_service =
+        sb_service_factory.CreateSafeBrowsingService();
+    safe_browsing::SafeBrowsingService::RegisterFactory(nullptr);
+    TestingBrowserProcess::GetGlobal()->SetSafeBrowsingService(
+        safe_browsing_service);
+    g_browser_process->safe_browsing_service()->Initialize();
+
+    // Required for the safe browsing notifications on navigation.
+    ChromeSubresourceFilterClient::CreateForWebContents(web_contents());
+
+    scoped_feature_list_ = DefaultFeatureList();
+
+    auto console_logger = base::MakeUnique<TestConsoleLogger>();
+    console_logger_ = console_logger.get();
+    popup_blocker_ = base::MakeUnique<SafeBrowsingTriggeredPopupBlocker>(
+        web_contents(), std::move(console_logger));
+  }
+
+  void TearDown() override {
+    fake_safe_browsing_database_ = nullptr;
+    TestingBrowserProcess::GetGlobal()->safe_browsing_service()->ShutDown();
+
+    // Must explicitly set these to null and pump the run loop to ensure that
+    // all cleanup related to these classes actually happens.
+    TestingBrowserProcess::GetGlobal()->SetSafeBrowsingService(nullptr);
+    base::RunLoop().RunUntilIdle();
+
+    ChromeRenderViewHostTestHarness::TearDown();
+  }
+
+  virtual std::unique_ptr<base::test::ScopedFeatureList> DefaultFeatureList() {
+    auto feature_list = base::MakeUnique<base::test::ScopedFeatureList>();
+    feature_list->InitAndEnableFeature(kAbusiveExperienceEnforce);
+    return feature_list;
+  }
+
+  FakeSafeBrowsingDatabaseManager* fake_safe_browsing_database() {
+    return fake_safe_browsing_database_.get();
+  }
+
+  base::test::ScopedFeatureList* ResetFeatureAndGet() {
+    scoped_feature_list_ = base::MakeUnique<base::test::ScopedFeatureList>();
+    return scoped_feature_list_.get();
+  }
+
+  SafeBrowsingTriggeredPopupBlocker* popup_blocker() {
+    return popup_blocker_.get();
+  }
+
+  void MarkUrlAsAbusiveWithLevel(const GURL& url,
+                                 safe_browsing::SubresourceFilterLevel level) {
+    safe_browsing::ThreatMetadata metadata;
+    metadata.subresource_filter_match
+        [safe_browsing::SubresourceFilterType::ABUSIVE] = level;
+    fake_safe_browsing_database()->AddBlacklistedUrl(
+        url, safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER, metadata);
+  }
+
+  void MarkUrlAsAbusiveEnforce(const GURL& url) {
+    MarkUrlAsAbusiveWithLevel(url,
+                              safe_browsing::SubresourceFilterLevel::ENFORCE);
+  }
+
+  void MarkUrlAsAbusiveWarning(const GURL& url) {
+    MarkUrlAsAbusiveWithLevel(url, safe_browsing::SubresourceFilterLevel::WARN);
+  }
+
+  TestConsoleLogger* console_logger() { return console_logger_; }
+
+ private:
+  std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
+  scoped_refptr<FakeSafeBrowsingDatabaseManager> fake_safe_browsing_database_;
+  std::unique_ptr<SafeBrowsingTriggeredPopupBlocker> popup_blocker_;
+
+  // Owned by the popup blocker.
+  TestConsoleLogger* console_logger_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingTriggeredPopupBlockerTest);
+};
+
+class IgnoreSublistSafeBrowsingTriggeredPopupBlockerTest
+    : public SafeBrowsingTriggeredPopupBlockerTest {
+  std::unique_ptr<base::test::ScopedFeatureList> DefaultFeatureList() override {
+    auto feature_list = base::MakeUnique<base::test::ScopedFeatureList>();
+    feature_list->InitAndEnableFeatureWithParameters(
+        kAbusiveExperienceEnforce, {{"ignore_sublists", "true"}});
+    return feature_list;
+  }
+};
+
+TEST_F(IgnoreSublistSafeBrowsingTriggeredPopupBlockerTest,
+       MatchNoSublist_BlocksPopup) {
+  const GURL url("https://example.test/");
+  fake_safe_browsing_database()->AddBlacklistedUrl(
+      url, safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER);
+  NavigateAndCommit(url);
+  EXPECT_TRUE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+}
+
+// ignore_sublists should still block on URLs matching a sublist.
+TEST_F(IgnoreSublistSafeBrowsingTriggeredPopupBlockerTest,
+       MatchSublist_BlocksPopup) {
+  const GURL url("https://example.test/");
+  MarkUrlAsAbusiveEnforce(url);
+  NavigateAndCommit(url);
+  EXPECT_TRUE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+}
+
+TEST_F(SafeBrowsingTriggeredPopupBlockerTest, MatchingURL_BlocksPopupAndLogs) {
+  const GURL url("https://example.test/");
+  MarkUrlAsAbusiveEnforce(url);
+  NavigateAndCommit(url);
+  EXPECT_TRUE(console_logger()->messages().empty());
+
+  EXPECT_TRUE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+  EXPECT_EQ(1u, console_logger()->messages().size());
+  EXPECT_EQ(console_logger()->messages().front(), kAbusiveEnforceMessage);
+}
+
+TEST_F(SafeBrowsingTriggeredPopupBlockerTest,
+       MatchingURL_BlocksPopupFromOpenURL) {
+  const GURL url("https://example.test/");
+  MarkUrlAsAbusiveEnforce(url);
+  NavigateAndCommit(url);
+
+  // If the popup is coming from OpenURL params, the strong popup blocker is
+  // only going to look at the triggering event info. It will only block the
+  // popup if we know the triggering event is untrusted.
+  content::OpenURLParams params(
+      GURL("https://example.popup/"), content::Referrer(),
+      WindowOpenDisposition::NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK,
+      true /* is_renderer_initiated */);
+  EXPECT_FALSE(popup_blocker()->ShouldApplyStrongPopupBlocker(&params));
+
+  params.triggering_event_info =
+      blink::WebTriggeringEventInfo::kFromUntrustedEvent;
+  EXPECT_TRUE(popup_blocker()->ShouldApplyStrongPopupBlocker(&params));
+}
+
+TEST_F(SafeBrowsingTriggeredPopupBlockerTest, NoMatch_NoBlocking) {
+  const GURL url("https://example.test/");
+  NavigateAndCommit(url);
+  EXPECT_FALSE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+  EXPECT_TRUE(console_logger()->messages().empty());
+}
+
+TEST_F(SafeBrowsingTriggeredPopupBlockerTest, NoFeature_NoBlocking) {
+  ResetFeatureAndGet()->InitAndDisableFeature(kAbusiveExperienceEnforce);
+  const GURL url("https://example.test/");
+  MarkUrlAsAbusiveEnforce(url);
+  NavigateAndCommit(url);
+  EXPECT_FALSE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+}
+
+TEST_F(SafeBrowsingTriggeredPopupBlockerTest, OnlyBlockOnMatchingUrls) {
+  const GURL url1("https://example.first/");
+  const GURL url2("https://example.second/");
+  const GURL url3("https://example.third/");
+  // Only mark url2 as abusive.
+  MarkUrlAsAbusiveEnforce(url2);
+
+  NavigateAndCommit(url1);
+  EXPECT_FALSE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+
+  NavigateAndCommit(url2);
+  EXPECT_TRUE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+
+  NavigateAndCommit(url3);
+  EXPECT_FALSE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+
+  NavigateAndCommit(url1);
+  EXPECT_FALSE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+}
+
+TEST_F(SafeBrowsingTriggeredPopupBlockerTest,
+       SameDocumentNavigation_MaintainsBlocking) {
+  const GURL url("https://example.first/");
+  const GURL hash_url("https://example.first/#hash");
+
+  MarkUrlAsAbusiveEnforce(url);
+  NavigateAndCommit(url);
+  EXPECT_TRUE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+
+  // This is merely a same document navigation, keep the popup blocker.
+  NavigateAndCommit(hash_url);
+  EXPECT_TRUE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+}
+
+TEST_F(SafeBrowsingTriggeredPopupBlockerTest,
+       FailNavigation_MaintainsBlocking) {
+  const GURL url("https://example.first/");
+  const GURL fail_url("https://example.fail/");
+
+  MarkUrlAsAbusiveEnforce(url);
+  NavigateAndCommit(url);
+  EXPECT_TRUE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+
+  // Abort the navigation before it commits.
+  content::NavigationSimulator::NavigateAndFailFromDocument(
+      fail_url, net::ERR_ABORTED, main_rfh());
+  EXPECT_TRUE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+
+  // Committing an error page should probably reset the blocker though, despite
+  // the fact that it is probably a bug for an error page to spawn popups.
+  content::NavigationSimulator::NavigateAndFailFromDocument(
+      fail_url, net::ERR_CONNECTION_RESET, main_rfh());
+  EXPECT_FALSE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+}
+
+TEST_F(SafeBrowsingTriggeredPopupBlockerTest, LogActions) {
+  base::HistogramTester histogram_tester;
+  const char kActionHistogram[] = "ContentSettings.Popups.StrongBlockerActions";
+  int total_count = 0;
+  // Call this when a new histogram entry is logged. Call it multiple times if
+  // multiple entries are logged.
+  auto check_histogram = [&](SafeBrowsingTriggeredPopupBlocker::Action action,
+                             int expected_count) {
+    histogram_tester.ExpectBucketCount(
+        kActionHistogram, static_cast<int>(action), expected_count);
+    total_count++;
+  };
+
+  const GURL url_enforce("https://example.enforce/");
+  const GURL url_warn("https://example.warn/");
+  const GURL url_nothing("https://example.nothing/");
+  MarkUrlAsAbusiveEnforce(url_enforce);
+  MarkUrlAsAbusiveWarning(url_warn);
+
+  // Navigate to an enforce site.
+  NavigateAndCommit(url_enforce);
+  check_histogram(SafeBrowsingTriggeredPopupBlocker::Action::kNavigation, 1);
+  check_histogram(SafeBrowsingTriggeredPopupBlocker::Action::kEnforcedSite, 1);
+  histogram_tester.ExpectTotalCount(kActionHistogram, total_count);
+
+  // Block two popups.
+  EXPECT_TRUE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+  check_histogram(SafeBrowsingTriggeredPopupBlocker::Action::kConsidered, 1);
+  check_histogram(SafeBrowsingTriggeredPopupBlocker::Action::kBlocked, 1);
+  histogram_tester.ExpectTotalCount(kActionHistogram, total_count);
+
+  EXPECT_TRUE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+  check_histogram(SafeBrowsingTriggeredPopupBlocker::Action::kConsidered, 2);
+  check_histogram(SafeBrowsingTriggeredPopupBlocker::Action::kBlocked, 2);
+  histogram_tester.ExpectTotalCount(kActionHistogram, total_count);
+
+  // Navigate to a warn site.
+  NavigateAndCommit(url_warn);
+  check_histogram(SafeBrowsingTriggeredPopupBlocker::Action::kNavigation, 2);
+  check_histogram(SafeBrowsingTriggeredPopupBlocker::Action::kWarningSite, 1);
+  histogram_tester.ExpectTotalCount(kActionHistogram, total_count);
+
+  // Let one popup through.
+  EXPECT_FALSE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+  check_histogram(SafeBrowsingTriggeredPopupBlocker::Action::kConsidered, 3);
+  histogram_tester.ExpectTotalCount(kActionHistogram, total_count);
+
+  // Navigate to a site not matched in Safe Browsing.
+  NavigateAndCommit(url_nothing);
+  check_histogram(SafeBrowsingTriggeredPopupBlocker::Action::kNavigation, 3);
+  histogram_tester.ExpectTotalCount(kActionHistogram, total_count);
+
+  // Let one popup through.
+  EXPECT_FALSE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+  check_histogram(SafeBrowsingTriggeredPopupBlocker::Action::kConsidered, 4);
+  histogram_tester.ExpectTotalCount(kActionHistogram, total_count);
+}
+
+TEST_F(SafeBrowsingTriggeredPopupBlockerTest, WarningMatch_OnlyLogs) {
+  const GURL url("https://example.test/");
+
+  MarkUrlAsAbusiveWarning(url);
+  NavigateAndCommit(url);
+
+  // Warning should come at navigation commit time, not at popup time.
+  EXPECT_EQ(1u, console_logger()->messages().size());
+  EXPECT_EQ(console_logger()->messages().front(), kAbusiveWarnMessage);
+
+  EXPECT_FALSE(popup_blocker()->ShouldApplyStrongPopupBlocker(nullptr));
+}
diff --git a/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm
index 26ec81b..e642ac1b 100644
--- a/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm
+++ b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm
@@ -106,6 +106,7 @@
   base::scoped_nsobject<NSTextField> usernameField_;
   // The field contains the password or IDP origin for federated credentials.
   base::scoped_nsobject<NSTextField> passwordField_;
+  base::scoped_nsobject<NSTextField> passwordText_;
   base::scoped_nsobject<NSButton> passwordViewButton_;
   base::scoped_nsobject<NSButton> saveButton_;
   base::scoped_nsobject<NSButton> neverButton_;
@@ -141,12 +142,17 @@
   if (combobox) {
     FillPasswordCombobox(self.model->pending_password(), visible, combobox);
   } else {
+    NSRect oldFrame = [passwordField_ frame];
+    CGFloat offsetY = 0;
     if (visible) {
       InitEditableLabel(passwordField_.get(), form.password_value);
+      offsetY = NSMidY([passwordText_ frame]) - NSMidY(oldFrame);
     } else {
       InitLabel(passwordField_.get(),
                 base::string16(form.password_value.length(), '*'));
+      offsetY = NSMaxY([passwordText_ frame]) - NSMaxY(oldFrame);
     }
+    [passwordField_ setFrame:NSOffsetRect(oldFrame, 0, offsetY)];
   }
   [[self.view window]
       makeFirstResponder:(visible ? passwordField_.get() : saveButton_.get())];
@@ -242,25 +248,26 @@
   }
   [container addSubview:passwordField_];
 
-  NSTextField* usernameLabel =
+  NSTextField* usernameText =
       Label(l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_USERNAME_LABEL));
-  [container addSubview:usernameLabel];
-  NSTextField* passwordLabel =
-      Label(l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_PASSWORD_LABEL));
-  [container addSubview:passwordLabel];
+  [container addSubview:usernameText];
+  passwordText_.reset([Label(
+      l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_PASSWORD_LABEL)) retain]);
+  [container addSubview:passwordText_];
 
   // Layout the elements.
   CGFloat firstColumnSize =
-      std::max(NSWidth([usernameLabel frame]), NSWidth([passwordLabel frame]));
+      std::max(NSWidth([usernameText frame]), NSWidth([passwordText_ frame]));
   // Bottow row.
   CGFloat rowHeight = std::max(NSHeight([passwordField_ frame]),
-                               NSHeight([passwordLabel frame]));
-  CGFloat curY = (rowHeight - NSHeight([passwordLabel frame])) / 2;
-  [passwordLabel setFrameOrigin:NSMakePoint(firstColumnSize -
-                                                NSWidth([passwordLabel frame]),
+                               NSHeight([passwordText_ frame]));
+  CGFloat curY = (rowHeight - NSHeight([passwordText_ frame])) / 2;
+  [passwordText_ setFrameOrigin:NSMakePoint(firstColumnSize -
+                                                NSWidth([passwordText_ frame]),
                                             curY)];
-  CGFloat curX = NSMaxX([passwordLabel frame]) + kItemLabelSpacing;
-  curY = (rowHeight - NSHeight([passwordField_ frame])) / 2;
+  CGFloat curX = NSMaxX([passwordText_ frame]) + kItemLabelSpacing;
+  // Password field is top-aligned with the label because it's not editable.
+  curY = NSMaxY([passwordText_ frame]) - NSHeight([passwordField_ frame]);
   [passwordField_ setFrameOrigin:NSMakePoint(curX, curY)];
   CGFloat remainingWidth = kDesiredRowWidth - NSMinX([passwordField_ frame]);
   if (passwordViewButton_) {
@@ -276,11 +283,11 @@
   // Next row.
   CGFloat rowY = rowHeight + kRelatedControlVerticalSpacing;
   rowHeight = std::max(NSHeight([usernameField_ frame]),
-                       NSHeight([usernameLabel frame]));
-  curX = firstColumnSize - NSWidth([usernameLabel frame]);
-  curY = (rowHeight - NSHeight([usernameLabel frame])) / 2 + rowY;
-  [usernameLabel setFrameOrigin:NSMakePoint(curX, curY)];
-  curX = NSMaxX([usernameLabel frame]) + kItemLabelSpacing;
+                       NSHeight([usernameText frame]));
+  curX = firstColumnSize - NSWidth([usernameText frame]);
+  curY = (rowHeight - NSHeight([usernameText frame])) / 2 + rowY;
+  [usernameText setFrameOrigin:NSMakePoint(curX, curY)];
+  curX = NSMaxX([usernameText frame]) + kItemLabelSpacing;
   curY = (rowHeight - NSHeight([usernameField_ frame])) / 2 + rowY;
   [usernameField_ setFrameOrigin:NSMakePoint(curX, curY)];
   remainingWidth = kDesiredRowWidth - NSMinX([usernameField_ frame]);
diff --git a/chrome/browser/ui/cocoa/tabs/tab_view.mm b/chrome/browser/ui/cocoa/tabs/tab_view.mm
index fa3ecea4..47e42fe7 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_view.mm
@@ -36,7 +36,8 @@
 const SkColor kDarkModeIconColor = SkColorSetARGB(0xFF, 0xC4, 0xC4, 0xC4);
 
 bool IsTabStripKeyboardFocusEnabled() {
-  return base::FeatureList::IsEnabled(features::kTabStripKeyboardFocus);
+  return base::FeatureList::IsEnabled(features::kTabStripKeyboardFocus) &&
+         [NSApp isFullKeyboardAccessEnabled];
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/search/ntp_user_data_logger_unittest.cc b/chrome/browser/ui/search/ntp_user_data_logger_unittest.cc
index 8226965..cddacd92 100644
--- a/chrome/browser/ui/search/ntp_user_data_logger_unittest.cc
+++ b/chrome/browser/ui/search/ntp_user_data_logger_unittest.cc
@@ -93,378 +93,386 @@
               ElementsAre(Bucket(0, 1), Bucket(8, 1)));
 }
 
-// TODO(https://crbug.com/767406): Split this test in readable units.
 TEST(NTPUserDataLoggerTest, TestLogMostVisitedImpression) {
   base::StatisticsRecorder::Initialize();
 
-  base::HistogramTester histogram_tester;
-
   TestNTPUserDataLogger logger(GURL("chrome://newtab/"));
 
-  base::TimeDelta delta = base::TimeDelta::FromMilliseconds(0);
+  const base::TimeDelta delta = base::TimeDelta::FromMilliseconds(0);
 
-  // Impressions increment the associated bins.
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      0, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::INFERRED,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      1, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::INFERRED,
-      TileVisualType::THUMBNAIL_FAILED, base::Time(), GURL()));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      2, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::INFERRED,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      3, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::INFERRED,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      4, TileSource::TOP_SITES, TileTitleSource::TITLE_TAG,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      5, TileSource::TOP_SITES, TileTitleSource::MANIFEST,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      6, TileSource::POPULAR, TileTitleSource::TITLE_TAG,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      7, TileSource::POPULAR_BAKED_IN, TileTitleSource::META_TAG,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
+  {
+    base::HistogramTester histogram_tester;
 
-  // Repeated impressions for the same bins are ignored.
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      0, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::UNKNOWN,
-      TileVisualType::THUMBNAIL_FAILED, base::Time(), GURL()));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      1, TileSource::TOP_SITES, TileTitleSource::UNKNOWN,
-      TileVisualType::THUMBNAIL_FAILED, base::Time(), GURL()));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      2, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::UNKNOWN,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      3, TileSource::TOP_SITES, TileTitleSource::UNKNOWN,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    // Impressions increment the associated bins.
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        0, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::INFERRED,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        1, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::INFERRED,
+        TileVisualType::THUMBNAIL_FAILED, base::Time(), GURL()));
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        2, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::INFERRED,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        3, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::INFERRED,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        4, TileSource::TOP_SITES, TileTitleSource::TITLE_TAG,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        5, TileSource::TOP_SITES, TileTitleSource::MANIFEST,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        6, TileSource::POPULAR, TileTitleSource::TITLE_TAG,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        7, TileSource::POPULAR_BAKED_IN, TileTitleSource::META_TAG,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
 
-  // Impressions are silently ignored for tiles >= 8.
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      8, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::UNKNOWN,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      9, TileSource::TOP_SITES, TileTitleSource::UNKNOWN,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    // Repeated impressions for the same bins are ignored.
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        0, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::UNKNOWN,
+        TileVisualType::THUMBNAIL_FAILED, base::Time(), GURL()));
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        1, TileSource::TOP_SITES, TileTitleSource::UNKNOWN,
+        TileVisualType::THUMBNAIL_FAILED, base::Time(), GURL()));
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        2, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::UNKNOWN,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        3, TileSource::TOP_SITES, TileTitleSource::UNKNOWN,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
 
-  // The actual histograms are emitted only after the ALL_TILES_LOADED event, so
-  // at this point everything should still be empty.
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression"),
-      IsEmpty());
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression.server"),
-      IsEmpty());
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression.client"),
-      IsEmpty());
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType"), IsEmpty());
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.client"),
-              IsEmpty());
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.server"),
-              IsEmpty());
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle"),
-              IsEmpty());
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle.client"),
-              IsEmpty());
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle.server"),
-              IsEmpty());
+    // Impressions are silently ignored for tiles >= 8.
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        8, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::UNKNOWN,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        9, TileSource::TOP_SITES, TileTitleSource::UNKNOWN,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
 
-  // Send the ALL_TILES_LOADED event, this should trigger emitting histograms.
-  logger.LogEvent(NTP_ALL_TILES_LOADED, delta);
+    // The actual histograms are emitted only after the ALL_TILES_LOADED event,
+    // so at this point everything should still be empty.
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression"),
+        IsEmpty());
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.SuggestionsImpression.server"),
+                IsEmpty());
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.SuggestionsImpression.client"),
+                IsEmpty());
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType"),
+                IsEmpty());
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.client"),
+                IsEmpty());
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.server"),
+                IsEmpty());
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle"),
+                IsEmpty());
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle.client"),
+                IsEmpty());
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle.server"),
+                IsEmpty());
 
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression"),
-      ElementsAre(Bucket(0, 1), Bucket(1, 1), Bucket(2, 1), Bucket(3, 1),
-                  Bucket(4, 1), Bucket(5, 1), Bucket(6, 1), Bucket(7, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression.server"),
-      ElementsAre(Bucket(0, 1), Bucket(1, 1), Bucket(2, 1), Bucket(3, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression.client"),
-      ElementsAre(Bucket(4, 1), Bucket(5, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples(
-                  "NewTabPage.SuggestionsImpression.popular_fetched"),
-              ElementsAre(Bucket(6, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples(
-                  "NewTabPage.SuggestionsImpression.popular_baked_in"),
-              ElementsAre(Bucket(7, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileType"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 7),
-                  Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileType.server"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 3),
-                  Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.client"),
-              ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 2)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileType.popular_fetched"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileType.popular_baked_in"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle"),
-              ElementsAre(Bucket(kManifestTitleSource, 1),
-                          Bucket(kMetaTagTitleSource, 1),
-                          Bucket(kTitleTagTitleSource, 2),
-                          Bucket(kInferredTitleSource, 4)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle.server"),
-              ElementsAre(Bucket(kInferredTitleSource, 4)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle.client"),
-              ElementsAre(Bucket(kManifestTitleSource, 1),
-                          Bucket(kTitleTagTitleSource, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTitle.popular_fetched"),
-      ElementsAre(Bucket(kTitleTagTitleSource, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTitle.popular_baked_in"),
-      ElementsAre(Bucket(kMetaTagTitleSource, 1)));
+    // Send the ALL_TILES_LOADED event, this should trigger emitting histograms.
+    logger.LogEvent(NTP_ALL_TILES_LOADED, delta);
+
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression"),
+        ElementsAre(Bucket(0, 1), Bucket(1, 1), Bucket(2, 1), Bucket(3, 1),
+                    Bucket(4, 1), Bucket(5, 1), Bucket(6, 1), Bucket(7, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples(
+            "NewTabPage.SuggestionsImpression.server"),
+        ElementsAre(Bucket(0, 1), Bucket(1, 1), Bucket(2, 1), Bucket(3, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.SuggestionsImpression.client"),
+                ElementsAre(Bucket(4, 1), Bucket(5, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.SuggestionsImpression.popular_fetched"),
+                ElementsAre(Bucket(6, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.SuggestionsImpression.popular_baked_in"),
+                ElementsAre(Bucket(7, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileType"),
+        ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 7),
+                    Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileType.server"),
+        ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 3),
+                    Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.client"),
+                ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 2)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileType.popular_fetched"),
+        ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileType.popular_baked_in"),
+        ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle"),
+                ElementsAre(Bucket(kManifestTitleSource, 1),
+                            Bucket(kMetaTagTitleSource, 1),
+                            Bucket(kTitleTagTitleSource, 2),
+                            Bucket(kInferredTitleSource, 4)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle.server"),
+                ElementsAre(Bucket(kInferredTitleSource, 4)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle.client"),
+                ElementsAre(Bucket(kManifestTitleSource, 1),
+                            Bucket(kTitleTagTitleSource, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTitle.popular_fetched"),
+        ElementsAre(Bucket(kTitleTagTitleSource, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTitle.popular_baked_in"),
+        ElementsAre(Bucket(kMetaTagTitleSource, 1)));
+  }
 
   // After navigating away from the NTP and back, we record again.
-  logger.NavigatedFromURLToURL(GURL("chrome://newtab/"),
-                               GURL("http://chromium.org"));
-  logger.NavigatedFromURLToURL(GURL("http://chromium.org"),
-                               GURL("chrome://newtab/"));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      0, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::INFERRED,
+  {
+    base::HistogramTester histogram_tester;
 
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      1, TileSource::POPULAR, TileTitleSource::MANIFEST,
+    logger.NavigatedFromURLToURL(GURL("chrome://newtab/"),
+                                 GURL("http://chromium.org"));
+    logger.NavigatedFromURLToURL(GURL("http://chromium.org"),
+                                 GURL("chrome://newtab/"));
 
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      2, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::INFERRED,
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        0, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::INFERRED,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        1, TileSource::POPULAR, TileTitleSource::MANIFEST,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        2, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::INFERRED,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
+        3, TileSource::TOP_SITES, TileTitleSource::MANIFEST,
+        TileVisualType::THUMBNAIL_FAILED, base::Time(), GURL()));
+    logger.LogEvent(NTP_ALL_TILES_LOADED, delta);
 
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  logger.LogMostVisitedImpression(ntp_tiles::NTPTileImpression(
-      3, TileSource::TOP_SITES, TileTitleSource::MANIFEST,
-
-      TileVisualType::THUMBNAIL_FAILED, base::Time(), GURL()));
-  logger.LogEvent(NTP_ALL_TILES_LOADED, delta);
-
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression"),
-      ElementsAre(Bucket(0, 2), Bucket(1, 2), Bucket(2, 2), Bucket(3, 2),
-                  Bucket(4, 1), Bucket(5, 1), Bucket(6, 1), Bucket(7, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression.server"),
-      ElementsAre(Bucket(0, 2), Bucket(1, 1), Bucket(2, 2), Bucket(3, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression.client"),
-      ElementsAre(Bucket(3, 1), Bucket(4, 1), Bucket(5, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples(
-                  "NewTabPage.SuggestionsImpression.popular_fetched"),
-              ElementsAre(Bucket(1, 1), Bucket(6, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples(
-                  "NewTabPage.SuggestionsImpression.popular_baked_in"),
-              ElementsAre(Bucket(7, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileType"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 10),
-                  Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 2)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileType.server"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 5),
-                  Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileType.client"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 2),
-                  Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileType.popular_fetched"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 2)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileType.popular_baked_in"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle"),
-              ElementsAre(Bucket(kManifestTitleSource, 3),
-                          Bucket(kMetaTagTitleSource, 1),
-                          Bucket(kTitleTagTitleSource, 2),
-                          Bucket(kInferredTitleSource, 6)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle.server"),
-              ElementsAre(Bucket(kInferredTitleSource, 6)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle.client"),
-              ElementsAre(Bucket(kManifestTitleSource, 2),
-                          Bucket(kTitleTagTitleSource, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTitle.popular_fetched"),
-      ElementsAre(Bucket(kManifestTitleSource, 1),
-                  Bucket(kTitleTagTitleSource, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTitle.popular_baked_in"),
-      ElementsAre(Bucket(kMetaTagTitleSource, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression"),
+        ElementsAre(Bucket(0, 1), Bucket(1, 1), Bucket(2, 1), Bucket(3, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.SuggestionsImpression.server"),
+                ElementsAre(Bucket(0, 1), Bucket(2, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.SuggestionsImpression.client"),
+                ElementsAre(Bucket(3, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.SuggestionsImpression.popular_fetched"),
+                ElementsAre(Bucket(1, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.SuggestionsImpression.popular_baked_in"),
+                IsEmpty());
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileType"),
+        ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 3),
+                    Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileType.server"),
+                ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 2)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileType.client"),
+        ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileType.popular_fetched"),
+        ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileType.popular_baked_in"),
+        IsEmpty());
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle"),
+                ElementsAre(Bucket(kManifestTitleSource, 2),
+                            Bucket(kInferredTitleSource, 2)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle.server"),
+                ElementsAre(Bucket(kInferredTitleSource, 2)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitle.client"),
+                ElementsAre(Bucket(kManifestTitleSource, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTitle.popular_fetched"),
+        ElementsAre(Bucket(kManifestTitleSource, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTitle.popular_baked_in"),
+        IsEmpty());
+  }
 }
 
-// TODO(https://crbug.com/767406): Split this test in readable units.
 TEST(NTPUserDataLoggerTest, TestLogMostVisitedNavigation) {
   base::StatisticsRecorder::Initialize();
 
-  base::HistogramTester histogram_tester;
-
   TestNTPUserDataLogger logger(GURL("chrome://newtab/"));
 
-  logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
-      0, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::UNKNOWN,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited"),
-              ElementsAre(Bucket(0, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
-              ElementsAre(Bucket(0, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"),
-              IsEmpty());
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked"),
-              ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.server"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.client"),
-      IsEmpty());
+  {
+    base::HistogramTester histogram_tester;
 
-  logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
-      1, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::UNKNOWN,
-      TileVisualType::THUMBNAIL_FAILED, base::Time(), GURL()));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited"),
-              ElementsAre(Bucket(0, 1), Bucket(1, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
-              ElementsAre(Bucket(0, 1), Bucket(1, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"),
-              IsEmpty());
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1),
-                  Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.server"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1),
-                  Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.client"),
-      IsEmpty());
+    logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
+        0, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::UNKNOWN,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
 
-  logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
-      2, TileSource::TOP_SITES, TileTitleSource::MANIFEST,
-      TileVisualType::THUMBNAIL_FAILED, base::Time(), GURL()));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited"),
-              ElementsAre(Bucket(0, 1), Bucket(1, 1), Bucket(2, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
-              ElementsAre(Bucket(0, 1), Bucket(1, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"),
-              ElementsAre(Bucket(2, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1),
-                  Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 2)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.server"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1),
-                  Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.client"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited"),
+                ElementsAre(Bucket(0, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
+                ElementsAre(Bucket(0, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"),
+                IsEmpty());
 
-  logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
-      3, TileSource::POPULAR, TileTitleSource::META_TAG,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.MostVisited"),
-      ElementsAre(Bucket(0, 1), Bucket(1, 1), Bucket(2, 1), Bucket(3, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
-              ElementsAre(Bucket(0, 1), Bucket(1, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"),
-              ElementsAre(Bucket(2, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular_fetched"),
-      ElementsAre(Bucket(3, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 2),
-                  Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 2)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.server"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1),
-                  Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.client"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples(
-                  "NewTabPage.TileTypeClicked.popular_fetched"),
-              ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitleClicked"),
-              ElementsAre(Bucket(kUnknownTitleSource, 2),
-                          Bucket(kManifestTitleSource, 1),
-                          Bucket(kMetaTagTitleSource, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTitleClicked.server"),
-      ElementsAre(Bucket(kUnknownTitleSource, 2)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTitleClicked.client"),
-      ElementsAre(Bucket(kManifestTitleSource, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples(
-                  "NewTabPage.TileTitleClicked.popular_fetched"),
-              ElementsAre(Bucket(kMetaTagTitleSource, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked"),
+                ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.server"),
+        ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.client"),
+        IsEmpty());
+  }
 
-  // Navigations always increase.
-  logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
-      0, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::UNKNOWN,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
-      1, TileSource::TOP_SITES, TileTitleSource::TITLE_TAG,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
-      2, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::UNKNOWN,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
-      3, TileSource::POPULAR, TileTitleSource::MANIFEST,
-      TileVisualType::THUMBNAIL, base::Time(), GURL()));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.MostVisited"),
-      ElementsAre(Bucket(0, 2), Bucket(1, 2), Bucket(2, 2), Bucket(3, 2)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
-              ElementsAre(Bucket(0, 2), Bucket(1, 1), Bucket(2, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"),
-              ElementsAre(Bucket(1, 1), Bucket(2, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.MostVisited.popular_fetched"),
-      ElementsAre(Bucket(3, 2)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 6),
-                  Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 2)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.server"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 3),
-                  Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.client"),
-      ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1),
-                  Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples(
-                  "NewTabPage.TileTypeClicked.popular_fetched"),
-              ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 2)));
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitleClicked"),
-              ElementsAre(Bucket(kUnknownTitleSource, 4),
-                          Bucket(kManifestTitleSource, 2),
-                          Bucket(kMetaTagTitleSource, 1),
-                          Bucket(kTitleTagTitleSource, 1)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTitleClicked.server"),
-      ElementsAre(Bucket(kUnknownTitleSource, 4)));
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("NewTabPage.TileTitleClicked.client"),
-      ElementsAre(Bucket(kManifestTitleSource, 1),
-                  Bucket(kTitleTagTitleSource, 1)));
-  EXPECT_THAT(histogram_tester.GetAllSamples(
-                  "NewTabPage.TileTitleClicked.popular_fetched"),
-              ElementsAre(Bucket(kManifestTitleSource, 1),
-                          Bucket(kMetaTagTitleSource, 1)));
+  {
+    base::HistogramTester histogram_tester;
+
+    logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
+        1, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::UNKNOWN,
+        TileVisualType::THUMBNAIL_FAILED, base::Time(), GURL()));
+
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited"),
+                ElementsAre(Bucket(1, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
+                ElementsAre(Bucket(1, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"),
+                IsEmpty());
+
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked"),
+        ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.server"),
+        ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.client"),
+        IsEmpty());
+  }
+
+  {
+    base::HistogramTester histogram_tester;
+
+    logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
+        2, TileSource::TOP_SITES, TileTitleSource::MANIFEST,
+        TileVisualType::THUMBNAIL_FAILED, base::Time(), GURL()));
+
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited"),
+                ElementsAre(Bucket(2, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
+                IsEmpty());
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"),
+                ElementsAre(Bucket(2, 1)));
+
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked"),
+        ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.server"),
+        IsEmpty());
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.client"),
+        ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL_FAILED, 1)));
+  }
+
+  {
+    base::HistogramTester histogram_tester;
+
+    logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
+        3, TileSource::POPULAR, TileTitleSource::META_TAG,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited"),
+                ElementsAre(Bucket(3, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
+                IsEmpty());
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"),
+                IsEmpty());
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.MostVisited.popular_fetched"),
+                ElementsAre(Bucket(3, 1)));
+
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked"),
+                ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.server"),
+        IsEmpty());
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.client"),
+        IsEmpty());
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.TileTypeClicked.popular_fetched"),
+                ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
+
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitleClicked"),
+                ElementsAre(Bucket(kMetaTagTitleSource, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTitleClicked.server"),
+        IsEmpty());
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTitleClicked.client"),
+        IsEmpty());
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.TileTitleClicked.popular_fetched"),
+                ElementsAre(Bucket(kMetaTagTitleSource, 1)));
+  }
+
+  {
+    base::HistogramTester histogram_tester;
+
+    // Navigations always increase.
+    logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
+        0, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::UNKNOWN,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
+        1, TileSource::TOP_SITES, TileTitleSource::TITLE_TAG,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
+        2, TileSource::SUGGESTIONS_SERVICE, TileTitleSource::UNKNOWN,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+    logger.LogMostVisitedNavigation(ntp_tiles::NTPTileImpression(
+        3, TileSource::POPULAR, TileTitleSource::MANIFEST,
+        TileVisualType::THUMBNAIL, base::Time(), GURL()));
+
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.MostVisited"),
+        ElementsAre(Bucket(0, 1), Bucket(1, 1), Bucket(2, 1), Bucket(3, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.server"),
+                ElementsAre(Bucket(0, 1), Bucket(2, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"),
+                ElementsAre(Bucket(1, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.MostVisited.popular_fetched"),
+                ElementsAre(Bucket(3, 1)));
+
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked"),
+                ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 4)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.server"),
+        ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 2)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTypeClicked.client"),
+        ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.TileTypeClicked.popular_fetched"),
+                ElementsAre(Bucket(ntp_tiles::TileVisualType::THUMBNAIL, 1)));
+
+    EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.TileTitleClicked"),
+                ElementsAre(Bucket(kUnknownTitleSource, 2),
+                            Bucket(kManifestTitleSource, 1),
+                            Bucket(kTitleTagTitleSource, 1)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTitleClicked.server"),
+        ElementsAre(Bucket(kUnknownTitleSource, 2)));
+    EXPECT_THAT(
+        histogram_tester.GetAllSamples("NewTabPage.TileTitleClicked.client"),
+        ElementsAre(Bucket(kTitleTagTitleSource, 1)));
+    EXPECT_THAT(histogram_tester.GetAllSamples(
+                    "NewTabPage.TileTitleClicked.popular_fetched"),
+                ElementsAre(Bucket(kManifestTitleSource, 1)));
+  }
 }
 
 TEST(NTPUserDataLoggerTest, TestLoadTime) {
diff --git a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos_unittest.cc b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos_unittest.cc
index d7bcf1d..73e7895d 100644
--- a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos_unittest.cc
+++ b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos_unittest.cc
@@ -92,7 +92,6 @@
       DispatchKeyEventPostIMECallback callback) override {
     std::move(callback).Run(false);
   }
-  void SetCandidateWindowVisible(bool visible) override {}
 
   mojo::Binding<ui::mojom::TextInputClient> binding_;
   std::unique_ptr<base::RunLoop> run_loop_;
diff --git a/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc b/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc
index 00d02153..665d679 100644
--- a/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc
+++ b/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc
@@ -11,10 +11,6 @@
 
 #include "base/strings/utf_string_conversions.h"
 
-#if defined(OS_CHROMEOS)
-#include "ui/base/ime/ime_bridge.h"
-#endif
-
 RemoteTextInputClient::RemoteTextInputClient(
     ui::mojom::TextInputClientPtr remote_client,
     ui::TextInputType text_input_type,
@@ -27,11 +23,7 @@
       text_input_mode_(text_input_mode),
       text_direction_(text_direction),
       text_input_flags_(text_input_flags),
-      caret_bounds_(caret_bounds) {
-#if defined(OS_CHROMEOS)
-  ui::IMEBridge::Get()->SetCandidateWindowHandler(this);
-#endif
-}
+      caret_bounds_(caret_bounds) {}
 
 RemoteTextInputClient::~RemoteTextInputClient() {}
 
@@ -185,21 +177,3 @@
                                           base::OnceCallback<void(bool)>());
   return ui::EventDispatchDetails();
 }
-
-void RemoteTextInputClient::UpdateLookupTable(
-    const ui::CandidateWindow& candidate_window,
-    bool visible) {}
-
-void RemoteTextInputClient::UpdatePreeditText(const base::string16& text,
-                                              uint32_t cursor_pos,
-                                              bool visible) {}
-
-void RemoteTextInputClient::SetCursorBounds(const gfx::Rect& cursor_bounds,
-                                            const gfx::Rect& composition_head) {
-}
-
-void RemoteTextInputClient::OnCandidateWindowVisibilityChanged(bool visible) {
-#if defined(OS_CHROMEOS)
-  remote_client_->SetCandidateWindowVisible(visible);
-#endif
-}
diff --git a/chrome/browser/ui/views/ime_driver/remote_text_input_client.h b/chrome/browser/ui/views/ime_driver/remote_text_input_client.h
index 2e38097..ba549fd 100644
--- a/chrome/browser/ui/views/ime_driver/remote_text_input_client.h
+++ b/chrome/browser/ui/views/ime_driver/remote_text_input_client.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_UI_VIEWS_IME_DRIVER_REMOTE_TEXT_INPUT_CLIENT_H_
 
 #include "services/ui/public/interfaces/ime/ime.mojom.h"
-#include "ui/base/ime/chromeos/ime_candidate_window_handler_interface.h"
 #include "ui/base/ime/input_method_delegate.h"
 #include "ui/base/ime/text_input_client.h"
 
@@ -14,8 +13,7 @@
 // a remote client. This is intended to be passed to the overrides of
 // ui::InputMethod::SetFocusedTextInputClient().
 class RemoteTextInputClient : public ui::TextInputClient,
-                              public ui::internal::InputMethodDelegate,
-                              chromeos::IMECandidateWindowHandlerInterface {
+                              public ui::internal::InputMethodDelegate {
  public:
   RemoteTextInputClient(ui::mojom::TextInputClientPtr remote_client,
                         ui::TextInputType text_input_type,
@@ -63,16 +61,6 @@
   ui::EventDispatchDetails DispatchKeyEventPostIME(
       ui::KeyEvent* event) override;
 
-  // chromeos::IMECandidateWindowHandlerInterface:
-  void UpdateLookupTable(const ui::CandidateWindow& candidate_window,
-                         bool visible) override;
-  void UpdatePreeditText(const base::string16& text,
-                         uint32_t cursor_pos,
-                         bool visible) override;
-  void SetCursorBounds(const gfx::Rect& cursor_bounds,
-                       const gfx::Rect& composition_head) override;
-  void OnCandidateWindowVisibilityChanged(bool visible) override;
-
   ui::mojom::TextInputClientPtr remote_client_;
   ui::TextInputType text_input_type_;
   ui::TextInputMode text_input_mode_;
diff --git a/chrome/browser/vr/elements/exit_warning_texture.cc b/chrome/browser/vr/elements/exit_warning_texture.cc
index f1955caa..663f2a7 100644
--- a/chrome/browser/vr/elements/exit_warning_texture.cc
+++ b/chrome/browser/vr/elements/exit_warning_texture.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/vr/elements/exit_warning_texture.h"
 
 #include "cc/paint/skia_paint_canvas.h"
-#include "components/strings/grit/components_strings.h"
+#include "chrome/grit/generated_resources.h"
 #include "components/vector_icons/vector_icons.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/canvas.h"
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 51e59f5..265fbc9 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -123,18 +123,6 @@
 // Enables Basic/Advanced tabs in ClearBrowsingData.
 const base::Feature kTabsInCbd{"TabsInCBD", base::FEATURE_ENABLED_BY_DEFAULT};
 
-// If enabled, we'll only take thumbnails of unknown URLs (i.e. URLs that are
-// not (yet) part of TopSites) if they have an interesting transition type, i.e.
-// one that qualifies for inclusion in TopSites.
-const base::Feature kCaptureThumbnailDependingOnTransitionType{
-    "CaptureThumbnailDependingOnTransitionType",
-    base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Whether to capture page thumbnails when navigating away from the current page
-// (in addition to any other times this might happen).
-const base::Feature kCaptureThumbnailOnNavigatingAway{
-    "CaptureThumbnailOnNavigatingAway", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Whether to trigger app banner installability checks on page load.
 const base::Feature kCheckInstallabilityForBannerOnLoad{
     "CheckInstallabilityForBannerOnLoad", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 5d518a1e..02b9983 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -66,10 +66,6 @@
 extern const base::Feature kTabStripKeyboardFocus;
 #endif  // defined(OS_MACOSX)
 
-extern const base::Feature kCaptureThumbnailDependingOnTransitionType;
-
-extern const base::Feature kCaptureThumbnailOnNavigatingAway;
-
 extern const base::Feature kCheckInstallabilityForBannerOnLoad;
 
 extern const base::Feature kClickToOpenPDFPlaceholder;
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index d3e5aa3a..21f7d6f 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -1698,14 +1698,11 @@
   base::Time chrome_66_not_before = base::Time::FromDoubleT(1464739200);
   const char* in_future_string =
       cert_validity_start < chrome_66_not_before ? "in M66" : "in M70";
-  std::string port;
-  if (url.port() != "443")
-    port = base::StringPrintf(":%s", url.port().c_str());
   *console_message = base::StringPrintf(
-      "The SSL certificate used to load resources from %s://%s%s"
+      "The SSL certificate used to load resources from %s"
       " will be distrusted %s. Once distrusted, users will be prevented from "
       "loading these resources. See https://g.co/chrome/symantecpkicerts for "
       "more information.",
-      url.scheme().c_str(), url.host().c_str(), port.c_str(), in_future_string);
+      url::Origin(url).Serialize().c_str(), in_future_string);
   return true;
 }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 56fa72b..0f838fa 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3398,6 +3398,7 @@
     "../browser/ui/autofill/autofill_popup_layout_model_unittest.cc",
     "../browser/ui/autofill/popup_view_common_unittest.cc",
     "../browser/ui/blocked_content/popup_opener_tab_helper_unittest.cc",
+    "../browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc",
     "../browser/ui/blocked_content/scoped_visibility_tracker_unittest.cc",
     "../browser/ui/bookmarks/bookmark_editor_unittest.cc",
     "../browser/ui/bookmarks/bookmark_ui_utils_desktop_unittest.cc",
@@ -3555,7 +3556,6 @@
     "//components/safe_browsing:features",
     "//components/safe_browsing/db",
     "//components/safe_browsing/db:test_database_manager",
-    "//components/safe_json:test_support",
     "//components/spellcheck:build_features",
     "//components/strings",
     "//components/subresource_filter/core/browser:test_support",
@@ -3581,6 +3581,7 @@
     "//net",
     "//net:test_support",
     "//ppapi/features",
+    "//services/data_decoder/public/cpp:test_support",
     "//skia",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 9804992..8342cfd2 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -254,7 +254,9 @@
          # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1960
         'CorrectEventFiringTest.testShouldFireMouseDownEventWhenClicking',
         # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2076
-        'CorrectEventFiringTest.testShouldReportTheXAndYCoordinatesWhenClicking'
+        'CorrectEventFiringTest.testShouldReportTheXAndYCoordinatesWhenClicking',
+        # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2077
+        'CorrectEventFiringTest.testShouldEmitClickEventWhenClickingOnATextInputElement',
     ]
 )
 
diff --git a/chrome/test/data/android/render_tests/NewTabPageTest.new_tab_page_scrolled.Nexus_5-19.png b/chrome/test/data/android/render_tests/NewTabPageTest.new_tab_page_scrolled.Nexus_5-19.png
index 16ca9405..b9669e7d 100644
--- a/chrome/test/data/android/render_tests/NewTabPageTest.new_tab_page_scrolled.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/NewTabPageTest.new_tab_page_scrolled.Nexus_5-19.png
Binary files differ
diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn
index 9b68da2..38e2b30b 100644
--- a/chrome/utility/BUILD.gn
+++ b/chrome/utility/BUILD.gn
@@ -40,7 +40,6 @@
     "//chrome/common/profiling",
     "//chrome/profiling",
     "//components/payments/content/utility",
-    "//components/safe_json/utility",
     "//components/search_engines",
     "//components/strings",
     "//components/url_formatter",
diff --git a/chrome/utility/DEPS b/chrome/utility/DEPS
index fa24cc3..c31c46e 100644
--- a/chrome/utility/DEPS
+++ b/chrome/utility/DEPS
@@ -6,7 +6,6 @@
   "+components/payments/content/utility",
   "+components/printing/service/public/cpp",
   "+components/printing/service/public/interfaces",
-  "+components/safe_json",
   "+components/wifi",
   "+content/public/child",
   "+content/public/network",
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc
index 15b164c0..e29b25a 100644
--- a/chrome/utility/chrome_content_utility_client.cc
+++ b/chrome/utility/chrome_content_utility_client.cc
@@ -22,7 +22,6 @@
 #include "chrome/utility/printing/pdf_to_pwg_raster_converter_impl.h"
 #include "chrome/utility/utility_message_handler.h"
 #include "components/payments/content/utility/payment_manifest_parser.h"
-#include "components/safe_json/utility/safe_json_parser_mojo_impl.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/simple_connection_filter.h"
@@ -292,9 +291,6 @@
 #endif  // !defined(OS_ANDROID)
     registry->AddInterface(base::Bind(&payments::PaymentManifestParser::Create),
                            base::ThreadTaskRunnerHandle::Get());
-    registry->AddInterface(
-        base::Bind(&safe_json::SafeJsonParserMojoImpl::Create),
-        base::ThreadTaskRunnerHandle::Get());
 #if defined(OS_WIN)
     registry->AddInterface(base::Bind(&ShellHandlerImpl::Create),
                            base::ThreadTaskRunnerHandle::Get());
diff --git a/components/BUILD.gn b/components/BUILD.gn
index ceb26d5..2efb7edb 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -213,7 +213,6 @@
       "//components/safe_browsing/common:unit_tests",
       "//components/safe_browsing/password_protection:password_protection_unittest",
       "//components/safe_browsing/triggers:unit_tests",
-      "//components/safe_json:unit_tests",
       "//components/security_state/content:unit_tests",
       "//components/spellcheck/browser:unit_tests",
       "//components/spellcheck/renderer:unit_tests",
@@ -253,8 +252,6 @@
       "//components/invalidation/impl",
       "//components/invalidation/impl:java",
       "//components/policy/android:policy_java",
-      "//components/safe_json",
-      "//components/safe_json/android:safe_json_java",
       "//components/signin/core/browser",
       "//components/signin/core/browser/android:java",
       "//components/spellcheck/browser/android:java",
diff --git a/components/certificate_transparency/BUILD.gn b/components/certificate_transparency/BUILD.gn
index ef07c14a..f55ed3d7 100644
--- a/components/certificate_transparency/BUILD.gn
+++ b/components/certificate_transparency/BUILD.gn
@@ -20,7 +20,6 @@
     "//base",
     "//components/base32",
     "//components/prefs",
-    "//components/safe_json",
     "//components/url_formatter",
     "//components/url_matcher",
     "//net",
@@ -43,7 +42,6 @@
     "//base/test:test_support",
     "//components/base32",
     "//components/prefs:test_support",
-    "//components/safe_json:test_support",
     "//net:test_support",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/components/certificate_transparency/DEPS b/components/certificate_transparency/DEPS
index 575b1501..4a85886 100644
--- a/components/certificate_transparency/DEPS
+++ b/components/certificate_transparency/DEPS
@@ -1,7 +1,6 @@
 include_rules = [
   "+components/base32",
   "+components/prefs",
-  "+components/safe_json",
   "+components/url_formatter",
   "+components/url_matcher",
   "+crypto",
diff --git a/components/cronet/ios/BUILD.gn b/components/cronet/ios/BUILD.gn
index b2b7eca8..13bffdc 100644
--- a/components/cronet/ios/BUILD.gn
+++ b/components/cronet/ios/BUILD.gn
@@ -94,6 +94,8 @@
   if (!use_platform_icu_alternatives) {
     deps += [ "//base:i18n" ]
   }
+
+  configs += [ "//build/config/compiler:enable_arc" ]
 }
 
 source_set("cronet_sources_with_global_state") {
@@ -186,6 +188,7 @@
   public_deps = [
     "//components/grpc_support",
   ]
+  configs += [ "//build/config/compiler:enable_arc" ]
 }
 
 # A static library which contains all dependencies of :cronet_static.
diff --git a/components/cronet/ios/Cronet.mm b/components/cronet/ios/Cronet.mm
index eeee8b65..607bbfbd 100644
--- a/components/cronet/ios/Cronet.mm
+++ b/components/cronet/ios/Cronet.mm
@@ -23,6 +23,10 @@
 #include "net/cert/cert_verifier.h"
 #include "net/url_request/url_request_context_getter.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 // Cronet NSError constants.
 NSString* const CRNCronetErrorDomain = @"CRNCronetErrorDomain";
 NSString* const CRNInvalidArgumentKey = @"CRNInvalidArgumentKey";
@@ -82,11 +86,11 @@
  public:
   CronetHttpProtocolHandlerDelegate(net::URLRequestContextGetter* getter,
                                     RequestFilterBlock filter)
-      : getter_(getter), filter_(filter, base::scoped_policy::RETAIN) {}
+      : getter_(getter), filter_(filter) {}
 
   void SetRequestFilterBlock(RequestFilterBlock filter) {
     base::AutoLock auto_lock(lock_);
-    filter_.reset(filter, base::scoped_policy::RETAIN);
+    filter_.reset(filter);
   }
 
  private:
diff --git a/components/cronet/ios/cronet_environment.mm b/components/cronet/ios/cronet_environment.mm
index ce76b280..d03df14 100644
--- a/components/cronet/ios/cronet_environment.mm
+++ b/components/cronet/ios/cronet_environment.mm
@@ -56,6 +56,10 @@
 #include "url/scheme_host_port.h"
 #include "url/url_util.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace {
 
 // Request context getter for Cronet.
diff --git a/components/cronet/tools/generate_accept_languages.py b/components/cronet/tools/generate_accept_languages.py
index ec571f7..7d3dee57 100644
--- a/components/cronet/tools/generate_accept_languages.py
+++ b/components/cronet/tools/generate_accept_languages.py
@@ -31,7 +31,7 @@
   return dict(accept_langs for accept_langs in accept_langs_list
     if accept_langs)
 
-HEADER = "NSDictionary* acceptLangs = @{"
+HEADER = "static NSDictionary* const acceptLangs = @{"
 def LINE(locale, accept_langs):
   return '  @"' + locale + '" : @"' + accept_langs + '",'
 FOOTER = "};"
diff --git a/components/flags_ui/resources/flags.css b/components/flags_ui/resources/flags.css
index ffa91e3..f8976f0 100644
--- a/components/flags_ui/resources/flags.css
+++ b/components/flags_ui/resources/flags.css
@@ -111,13 +111,12 @@
   border-radius: 3px;
   box-sizing: border-box;
   font-size: 1em;
-  padding: 12px 12px 12px 36px;
+  padding: 12px 36px;
   width: 100%;
 }
 
 [dir='rtl'] #search {
   background-position: right 50%;
-  padding: 12px 36px 12px 12px;
 }
 
 #search:focus {
@@ -242,12 +241,6 @@
   width: 150px;
 }
 
-.experiment .platforms::before {
-  content: '–';
-  display: inline;
-  padding: 0 2px;
-}
-
 .experiment-disable-link,
 .experiment-enable-link {
   background: white;
@@ -441,19 +434,16 @@
 
 @media (max-width: 360px) {
   #experiment-reset-all {
-    padding: 8px;
+    font-size: 0.8em;
+    padding: 4px 8px;
   }
 
   .experiment-restart-button {
     padding: 8px;
   }
 
-  .restart-notice {
-    font-size: 1em;
-  }
-
   #search {
-    padding: 8px 4px 8px 36px;
+    padding: 8px 36px;
   }
 }
 
@@ -485,7 +475,7 @@
     padding: 0 16px;
   }
 
-  #flagsTemplate > .flex-container:first-child {
+  #flagsTemplate > .flex-container:first-child:not('.version') {
     flex-direction: column;
     text-align: left;
   }
@@ -498,17 +488,35 @@
     width: 100%;
   }
 
-  #flagsTemplate > .flex-container #version {
-    padding-bottom: 16px;
-    text-align: left;
-  }
-
   [dir='rtl'] #flagsTemplate > .flex-container #version {
     text-align: right;
   }
 
   #needs-restart {
-    padding: 8px 4px;
+    padding: 8px 12px;
+  }
+
+  .experiment-restart-button {
+    padding: 8px 16px;
+  }
+
+  .restart-notice {
+    font-size: 1em;
+    padding: 4px;
+  }
+
+  /* Hide the overflow description text */
+  .experiment p {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    width: 100%;
+  }
+
+  .searching .experiment p,
+  .experiment .expand p {
+    overflow: visible;
+    white-space: normal;
   }
 }
 
diff --git a/components/flags_ui/resources/flags.html b/components/flags_ui/resources/flags.html
index 89d2e1a..1b1c3a9a 100644
--- a/components/flags_ui/resources/flags.html
+++ b/components/flags_ui/resources/flags.html
@@ -64,7 +64,7 @@
                 <h3 class="experiment-name" jscontent="name"
                     jsvalues="title: is_default ? '' : 'Experiment enabled'">Name</h3>
                 <p>
-                  <span jsvalues=".innerHTML:description"></span>
+                  <span jsvalues=".innerHTML:description"></span> –
                   <span class="platforms" jscontent="supported_platforms.join(', ')"></span>
                 </p>
                 <a class="permalink" jsvalues="href: '#' + internal_name"
diff --git a/components/flags_ui/resources/flags.js b/components/flags_ui/resources/flags.js
index 002c6acc..d571077 100644
--- a/components/flags_ui/resources/flags.js
+++ b/components/flags_ui/resources/flags.js
@@ -59,6 +59,17 @@
     });
   }
 
+  var smallScreenCheck = window.matchMedia('(max-width: 480px)');
+  // Toggling of experiment description overflow content on smaller screens.
+  elements = document.querySelectorAll('.experiment .flex:first-child');
+  for (var i = 0; i < elements.length; ++i) {
+    elements[i].onclick = function(e) {
+      if (smallScreenCheck.matches) {
+        this.classList.toggle('expand');
+      }
+    };
+  }
+
   $('experiment-reset-all').onclick = resetAllFlags;
 
   highlightReferencedFlag();
@@ -202,8 +213,8 @@
 var FlagSearch = function() {
   FlagSearch.instance_ = this;
 
-  this.experiments_ = [];
-  this.unavailableExperiments_ = [];
+  this.experiments_ = Object.assign({}, FlagSearch.SearchContent);
+  this.unavailableExperiments_ = Object.assign({}, FlagSearch.SearchContent);
 
   this.searchBox_ = $('search');
   this.noMatchMsg_ = document.querySelectorAll('.no-match');
@@ -216,6 +227,16 @@
 FlagSearch.SEARCH_DEBOUNCE_TIME_MS = 150;
 
 /**
+ * Object definition for storing the elements which are searched on.
+ * @typedef {Object<string, HTMLElement[]>}
+ */
+FlagSearch.SearchContent = {
+  link: [],
+  title: [],
+  description: []
+};
+
+/**
  * Get the singleton instance of FlagSearch.
  * @return {Object} Instance of FlagSearch.
  */
@@ -230,13 +251,22 @@
 FlagSearch.prototype = {
   /**
    * Initialises the in page search. Adding searchbox listeners and
-   * collates the permalinks used for string matching.
+   * collates the text elements used for string matching.
    */
   init: function() {
-    this.experiments_ =
+    this.experiments_.link =
         document.querySelectorAll('#tab-content-available .permalink');
-    this.unavailableExperiments_ =
+    this.experiments_.title =
+        document.querySelectorAll('#tab-content-available .experiment-name');
+    this.experiments_.description =
+        document.querySelectorAll('#tab-content-available p');
+
+    this.unavailableExperiments_.link =
         document.querySelectorAll('#tab-content-unavailable .permalink');
+    this.unavailableExperiments_.title =
+        document.querySelectorAll('#tab-content-unavailable .experiment-name');
+    this.unavailableExperiments_.description =
+        document.querySelectorAll('#tab-content-unavailable p');
 
     if (!this.initialized) {
       this.searchBox_.addEventListener('keyup', this.debounceSearch.bind(this));
@@ -244,8 +274,14 @@
           this.clearSearch.bind(this));
 
       window.addEventListener('keyup', function(e) {
-          if (e.key == '/') {
-            this.searchBox_.focus();
+          switch(e.key) {
+            case '/':
+              this.searchBox_.focus();
+              break;
+            case 'Escape':
+            case 'Enter':
+              this.searchBox_.blur();
+              break;
           }
       }.bind(this));
       this.searchBox_.focus();
@@ -264,30 +300,30 @@
   /**
    * Reset existing highlights on an element.
    * @param {HTMLElement} el The element to remove all highlighted mark up on.
-   * @param {string} flag The flag name to reset the element's textContent to.
+   * @param {string} text Text to reset the element's textContent to.
    */
-  resetHighlights: function(el, flag) {
+  resetHighlights: function(el, text) {
     if (el.children) {
-      el.textContent = flag;
+      el.textContent = text;
     }
   },
 
   /**
-   * Highlights the search term within the permalink flag name.
+   * Highlights the search term within a given element.
    * @param {string} searchTerm Search term user entered.
-   * @param {HTMLElement} el The permalink node where the search tern occurs.
+   * @param {HTMLElement} el The node containing the text to match against.
    * @return {boolean} Whether there was a match.
    */
-  highlightMatches: function(searchTerm, el) {
+  highlightMatchInElement: function(searchTerm, el) {
     // Experiment container.
     var parentEl = el.parentNode.parentNode.parentNode;
-    var flag = el.textContent.toLowerCase();
-    var match = flag.indexOf(searchTerm);
+    var text = el.textContent;
+    var match = text.toLowerCase().indexOf(searchTerm);
 
     parentEl.classList.toggle('hidden', match == -1);
 
     if (match == -1) {
-      this.resetHighlights(el, flag);
+      this.resetHighlights(el, text);
       return false;
     }
 
@@ -297,56 +333,85 @@
 
       if (match > 0) {
         var textNodePrefix =
-            document.createTextNode(flag.substring(0, match));
+            document.createTextNode(text.substring(0, match));
         el.appendChild(textNodePrefix);
       }
 
       var matchEl = document.createElement('mark');
-      matchEl.textContent = flag.substr(match, searchTerm.length);
+      matchEl.textContent = text.substr(match, searchTerm.length);
       el.appendChild(matchEl);
 
-      var matchSuffix = flag.substring(match + searchTerm.length);
+      var matchSuffix = text.substring(match + searchTerm.length);
       if (matchSuffix) {
         var textNodeSuffix = document.createTextNode(matchSuffix);
         el.appendChild(textNodeSuffix);
       }
     } else {
-      this.resetHighlights(el, flag);
+      this.resetHighlights(el, text);
     }
     return true;
   },
 
   /**
-   * Performs a search against the permalinks.
+   * Goes through all experiment text and highlights the relevant matches.
+   * Only the first instance of a match in each experiment text block is
+   * highlighted. This prevents the sea of yellow that happens using the global
+   * find in page search.
+   * @param {FlagSearch.SearchContent} searchContent Object containing the
+   *     experiment text elements to search against.
+   * @param {string} searchTerm
+   * @return {number} The number of matches found.
+   */
+  highlightAllMatches: function(searchContent, searchTerm) {
+    var matches = 0;
+    for (var i = 0, j = searchContent.link.length; i < j; i++) {
+      if (this.highlightMatchInElement(searchTerm, searchContent.title[i])) {
+        this.resetHighlights(searchContent.description[i],
+            searchContent.description[i].textContent);
+        this.resetHighlights(searchContent.link[i],
+            searchContent.link[i].textContent);
+        matches++;
+        continue;
+      }
+      if (this.highlightMatchInElement(searchTerm,
+          searchContent.description[i])) {
+        this.resetHighlights(searchContent.title[i],
+            searchContent.title[i].textContent);
+        this.resetHighlights(searchContent.link[i],
+            searchContent.link[i].textContent);
+        matches++;
+        continue;
+      }
+      // Match links, replace spaces with hyphens as flag names don't
+      // have spaces.
+      if (this.highlightMatchInElement(searchTerm.replace(/\s/, '-'),
+          searchContent.link[i])) {
+        this.resetHighlights(searchContent.title[i],
+            searchContent.title[i].textContent);
+        this.resetHighlights(searchContent.description[i],
+            searchContent.description[i].textContent);
+        matches++;
+      }
+    }
+    return matches;
+  },
+
+  /**
+   * Performs a search against the experiment title, description, permalink.
    * @param {Event} e
    */
   doSearch: function(e) {
-    // Replace spaces with hyphens as flag names don't have spaces.
     var searchTerm =
-        this.searchBox_.value.trim().toLowerCase().replace(/\s/, '-');
-    var matches = 0;
-    var unavailableMatches = 0;
+        this.searchBox_.value.trim().toLowerCase();
 
     if (searchTerm || searchTerm == '') {
-      if (searchTerm) {
-        document.body.classList.add('searching');
-      }
+      document.body.classList.toggle('searching', searchTerm);
       // Available experiments
-      for (var i = 0, j = this.experiments_.length; i < j; i++) {
-        if (this.highlightMatches(searchTerm, this.experiments_[i])) {
-          matches++;
-        }
-      }
-      this.noMatchMsg_[0].classList.toggle('hidden', matches);
-
+      this.noMatchMsg_[0].classList.toggle('hidden',
+          this.highlightAllMatches(this.experiments_, searchTerm));
       // Unavailable experiments
-      for (var i = 0, j = this.unavailableExperiments_.length; i < j; i++) {
-        if (this.highlightMatches(searchTerm,
-            this.unavailableExperiments_[i])) {
-          unavailableMatches++;
-        }
-      }
-      this.noMatchMsg_[1].classList.toggle('hidden', unavailableMatches);
+      this.noMatchMsg_[1].classList.toggle('hidden',
+          this.highlightAllMatches(this.unavailableExperiments_, searchTerm));
     }
 
     this.searchIntervalId_ = null;
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn
index c1bc7f5..87bd855 100644
--- a/components/metrics/BUILD.gn
+++ b/components/metrics/BUILD.gn
@@ -337,6 +337,7 @@
     "net/network_metrics_provider_unittest.cc",
     "persisted_logs_unittest.cc",
     "persistent_system_profile_unittest.cc",
+    "reporting_service_unittest.cc",
     "single_sample_metrics_factory_impl_unittest.cc",
     "stability_metrics_helper_unittest.cc",
     "stability_metrics_provider_unittest.cc",
diff --git a/components/metrics/metrics_log_uploader.h b/components/metrics/metrics_log_uploader.h
index 3fe7f5e3..14d8816 100644
--- a/components/metrics/metrics_log_uploader.h
+++ b/components/metrics/metrics_log_uploader.h
@@ -13,6 +13,8 @@
 
 namespace metrics {
 
+class ReportingInfo;
+
 // MetricsLogUploader is an abstract base class for uploading UMA logs on behalf
 // of MetricsService.
 class MetricsLogUploader {
@@ -34,7 +36,8 @@
   // |log_hash| is expected to be the hex-encoded SHA1 hash of the log data
   // before compression.
   virtual void UploadLog(const std::string& compressed_log_data,
-                         const std::string& log_hash) = 0;
+                         const std::string& log_hash,
+                         const ReportingInfo& reporting_info) = 0;
 };
 
 }  // namespace metrics
diff --git a/components/metrics/net/net_metrics_log_uploader.cc b/components/metrics/net/net_metrics_log_uploader.cc
index 3830b6291d..e1b4a692 100644
--- a/components/metrics/net/net_metrics_log_uploader.cc
+++ b/components/metrics/net/net_metrics_log_uploader.cc
@@ -4,9 +4,11 @@
 
 #include "components/metrics/net/net_metrics_log_uploader.h"
 
+#include "base/base64.h"
 #include "base/metrics/histogram_macros.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
 #include "components/metrics/metrics_log_uploader.h"
+#include "components/metrics/proto/reporting_info.pb.h"
 #include "net/base/load_flags.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_fetcher.h"
@@ -93,6 +95,16 @@
   }
 }
 
+std::string SerializeReportingInfo(
+    const metrics::ReportingInfo& reporting_info) {
+  std::string result;
+  std::string bytes;
+  bool success = reporting_info.SerializeToString(&bytes);
+  DCHECK(success);
+  base::Base64Encode(bytes, &result);
+  return result;
+}
+
 }  // namespace
 
 namespace metrics {
@@ -113,13 +125,16 @@
 }
 
 void NetMetricsLogUploader::UploadLog(const std::string& compressed_log_data,
-                                      const std::string& log_hash) {
-  UploadLogToURL(compressed_log_data, log_hash, GURL(server_url_));
+                                      const std::string& log_hash,
+                                      const ReportingInfo& reporting_info) {
+  UploadLogToURL(compressed_log_data, log_hash, reporting_info,
+                 GURL(server_url_));
 }
 
 void NetMetricsLogUploader::UploadLogToURL(
     const std::string& compressed_log_data,
     const std::string& log_hash,
+    const ReportingInfo& reporting_info,
     const GURL& url) {
   current_fetch_ =
       net::URLFetcher::Create(url, net::URLFetcher::POST, this,
@@ -146,6 +161,10 @@
   DCHECK(!log_hash.empty());
   current_fetch_->AddExtraRequestHeader("X-Chrome-UMA-Log-SHA1: " + log_hash);
 
+  std::string reporting_info_string = SerializeReportingInfo(reporting_info);
+  current_fetch_->AddExtraRequestHeader("X-Chrome-UMA-ReportingInfo:" +
+                                        reporting_info_string);
+
   // Drop cookies and auth data.
   current_fetch_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
                                net::LOAD_DO_NOT_SEND_AUTH_DATA |
diff --git a/components/metrics/net/net_metrics_log_uploader.h b/components/metrics/net/net_metrics_log_uploader.h
index ad531b95..9c240498 100644
--- a/components/metrics/net/net_metrics_log_uploader.h
+++ b/components/metrics/net/net_metrics_log_uploader.h
@@ -42,11 +42,14 @@
   // MetricsLogUploader:
   // Uploads a log to the server_url specified in the constructor.
   void UploadLog(const std::string& compressed_log_data,
-                 const std::string& log_hash) override;
+                 const std::string& log_hash,
+                 const ReportingInfo& reporting_info) override;
+
  private:
   // Uploads a log to a URL passed as a parameter.
   void UploadLogToURL(const std::string& compressed_log_data,
                       const std::string& log_hash,
+                      const ReportingInfo& reporting_info,
                       const GURL& url);
 
   // net::URLFetcherDelegate:
diff --git a/components/metrics/net/net_metrics_log_uploader_unittest.cc b/components/metrics/net/net_metrics_log_uploader_unittest.cc
index 70d94fd..a65ef53 100644
--- a/components/metrics/net/net_metrics_log_uploader_unittest.cc
+++ b/components/metrics/net/net_metrics_log_uploader_unittest.cc
@@ -4,8 +4,10 @@
 
 #include "components/metrics/net/net_metrics_log_uploader.h"
 
+#include "base/base64.h"
 #include "base/bind.h"
 #include "base/macros.h"
+#include "components/metrics/proto/reporting_info.pb.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -17,17 +19,23 @@
   }
 
   void CreateAndOnUploadCompleteReuseUploader() {
+    ReportingInfo reporting_info;
+    reporting_info.set_attempt_count(10);
     uploader_.reset(new NetMetricsLogUploader(
         NULL, "http://dummy_server", "dummy_mime", MetricsLogUploader::UMA,
         base::Bind(&NetMetricsLogUploaderTest::OnUploadCompleteReuseUploader,
                    base::Unretained(this))));
-    uploader_->UploadLog("initial_dummy_data", "initial_dummy_hash");
+    uploader_->UploadLog("initial_dummy_data", "initial_dummy_hash",
+                         reporting_info);
   }
 
   void OnUploadCompleteReuseUploader(int response_code, int error_code) {
     ++on_upload_complete_count_;
-    if (on_upload_complete_count_ == 1)
-      uploader_->UploadLog("dummy_data", "dummy_hash");
+    if (on_upload_complete_count_ == 1) {
+      ReportingInfo reporting_info;
+      reporting_info.set_attempt_count(20);
+      uploader_->UploadLog("dummy_data", "dummy_hash", reporting_info);
+    }
   }
 
   int on_upload_complete_count() const {
@@ -41,16 +49,33 @@
   DISALLOW_COPY_AND_ASSIGN(NetMetricsLogUploaderTest);
 };
 
+void CheckReportingInfoHeader(net::TestURLFetcher* fetcher,
+                              int expected_attempt_count) {
+  net::HttpRequestHeaders headers;
+  fetcher->GetExtraRequestHeaders(&headers);
+  std::string reporting_info_base64;
+  EXPECT_TRUE(
+      headers.GetHeader("X-Chrome-UMA-ReportingInfo", &reporting_info_base64));
+  std::string reporting_info_string;
+  EXPECT_TRUE(
+      base::Base64Decode(reporting_info_base64, &reporting_info_string));
+  ReportingInfo reporting_info;
+  EXPECT_TRUE(reporting_info.ParseFromString(reporting_info_string));
+  EXPECT_EQ(reporting_info.attempt_count(), expected_attempt_count);
+}
+
 TEST_F(NetMetricsLogUploaderTest, OnUploadCompleteReuseUploader) {
   net::TestURLFetcherFactory factory;
   CreateAndOnUploadCompleteReuseUploader();
 
   // Mimic the initial fetcher callback.
   net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
+  CheckReportingInfoHeader(fetcher, 10);
   fetcher->delegate()->OnURLFetchComplete(fetcher);
 
   // Mimic the second fetcher callback.
   fetcher = factory.GetFetcherByID(0);
+  CheckReportingInfoHeader(fetcher, 20);
   fetcher->delegate()->OnURLFetchComplete(fetcher);
 
   EXPECT_EQ(on_upload_complete_count(), 2);
diff --git a/components/metrics/reporting_service.cc b/components/metrics/reporting_service.cc
index 04fa2750..bd6c76d5 100644
--- a/components/metrics/reporting_service.cc
+++ b/components/metrics/reporting_service.cc
@@ -113,8 +113,10 @@
     upload_scheduler_->UploadFinished(true);
     return;
   }
-  if (!log_store()->has_staged_log())
+  if (!log_store()->has_staged_log()) {
+    reporting_info_.set_attempt_count(0);
     log_store()->StageNextLog();
+  }
 
   // Proceed to stage the log for upload if log size satisfies cellular log
   // upload constrains.
@@ -149,10 +151,12 @@
                    self_ptr_factory_.GetWeakPtr()));
   }
 
+  reporting_info_.set_attempt_count(reporting_info_.attempt_count() + 1);
+
   const std::string hash =
       base::HexEncode(log_store()->staged_log_hash().data(),
                       log_store()->staged_log_hash().size());
-  log_uploader_->UploadLog(log_store()->staged_log(), hash);
+  log_uploader_->UploadLog(log_store()->staged_log(), hash, reporting_info_);
 }
 
 void ReportingService::OnLogUploadComplete(int response_code, int error_code) {
@@ -161,6 +165,8 @@
   DCHECK(log_upload_in_progress_);
   log_upload_in_progress_ = false;
 
+  reporting_info_.set_last_response_code(response_code);
+
   // Log a histogram to track response success vs. failure rates.
   LogResponseOrErrorCode(response_code, error_code);
 
diff --git a/components/metrics/reporting_service.h b/components/metrics/reporting_service.h
index b1a36f7bb..678e24de 100644
--- a/components/metrics/reporting_service.h
+++ b/components/metrics/reporting_service.h
@@ -16,6 +16,7 @@
 #include "build/build_config.h"
 #include "components/metrics/data_use_tracker.h"
 #include "components/metrics/metrics_log_uploader.h"
+#include "components/metrics/proto/reporting_info.pb.h"
 
 class PrefService;
 class PrefRegistrySimple;
@@ -131,6 +132,9 @@
   // upload has been done yet.
   base::TimeTicks last_upload_finish_time_;
 
+  // Info on current reporting state to send along with reports.
+  ReportingInfo reporting_info_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   // Weak pointers factory used to post task on different threads. All weak
diff --git a/components/metrics/reporting_service_unittest.cc b/components/metrics/reporting_service_unittest.cc
new file mode 100644
index 0000000..7c2699a
--- /dev/null
+++ b/components/metrics/reporting_service_unittest.cc
@@ -0,0 +1,142 @@
+// 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 "components/metrics/reporting_service.h"
+
+#include <stdint.h>
+
+#include <deque>
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/sha1.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/metrics/log_store.h"
+#include "components/metrics/test_metrics_service_client.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/zlib/google/compression_utils.h"
+
+namespace metrics {
+
+namespace {
+
+const char kTestUploadUrl[] = "test_url";
+const char kTestMimeType[] = "test_mime_type";
+
+class TestLogStore : public LogStore {
+ public:
+  TestLogStore() {}
+  ~TestLogStore() {}
+
+  void AddLog(const std::string& log) { logs_.push_back(log); }
+
+  // LogStore:
+  bool has_unsent_logs() const override { return !logs_.empty(); }
+  bool has_staged_log() const override { return !staged_log_hash_.empty(); }
+  const std::string& staged_log() const override { return logs_.front(); }
+  const std::string& staged_log_hash() const override {
+    return staged_log_hash_;
+  }
+  void StageNextLog() override {
+    if (has_unsent_logs())
+      staged_log_hash_ = base::SHA1HashString(logs_.front());
+  }
+  void DiscardStagedLog() override {
+    if (!has_staged_log())
+      return;
+    logs_.pop_front();
+    staged_log_hash_.clear();
+  }
+  void PersistUnsentLogs() const override {}
+  void LoadPersistedUnsentLogs() override {}
+
+ private:
+  std::string staged_log_hash_;
+  std::deque<std::string> logs_;
+};
+
+class TestReportingService : public ReportingService {
+ public:
+  TestReportingService(MetricsServiceClient* client, PrefService* local_state)
+      : ReportingService(client, local_state, 100) {
+    Initialize();
+  }
+  ~TestReportingService() override {}
+
+  void AddLog(const std::string& log) { log_store_.AddLog(log); }
+
+ private:
+  // ReportingService:
+  LogStore* log_store() override { return &log_store_; }
+  std::string GetUploadUrl() const override { return kTestUploadUrl; }
+  base::StringPiece upload_mime_type() const override { return kTestMimeType; }
+  MetricsLogUploader::MetricServiceType service_type() const override {
+    return MetricsLogUploader::MetricServiceType::UMA;
+  }
+
+  TestLogStore log_store_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestReportingService);
+};
+
+class ReportingServiceTest : public testing::Test {
+ public:
+  ReportingServiceTest()
+      : task_runner_(new base::TestSimpleTaskRunner),
+        task_runner_handle_(task_runner_) {
+    ReportingService::RegisterPrefs(testing_local_state_.registry());
+  }
+
+  ~ReportingServiceTest() override {}
+
+  PrefService* GetLocalState() { return &testing_local_state_; }
+
+ protected:
+  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+  base::ThreadTaskRunnerHandle task_runner_handle_;
+  TestMetricsServiceClient client_;
+
+ private:
+  TestingPrefServiceSimple testing_local_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReportingServiceTest);
+};
+
+}  // namespace
+
+TEST_F(ReportingServiceTest, BasicTest) {
+  TestReportingService service(&client_, GetLocalState());
+  service.AddLog("log1");
+  service.AddLog("log2");
+
+  service.EnableReporting();
+  task_runner_->RunPendingTasks();
+  client_.uploader()->is_uploading();
+  EXPECT_TRUE(client_.uploader()->is_uploading());
+  EXPECT_EQ(1, client_.uploader()->reporting_info().attempt_count());
+  EXPECT_FALSE(client_.uploader()->reporting_info().has_last_response_code());
+
+  client_.uploader()->CompleteUpload(404);
+  task_runner_->RunPendingTasks();
+  EXPECT_TRUE(client_.uploader()->is_uploading());
+  EXPECT_EQ(2, client_.uploader()->reporting_info().attempt_count());
+  EXPECT_EQ(404, client_.uploader()->reporting_info().last_response_code());
+
+  client_.uploader()->CompleteUpload(200);
+  task_runner_->RunPendingTasks();
+  EXPECT_TRUE(client_.uploader()->is_uploading());
+  EXPECT_EQ(1, client_.uploader()->reporting_info().attempt_count());
+  EXPECT_EQ(200, client_.uploader()->reporting_info().last_response_code());
+
+  client_.uploader()->CompleteUpload(200);
+  EXPECT_EQ(0U, task_runner_->NumPendingTasks());
+  EXPECT_FALSE(client_.uploader()->is_uploading());
+}
+
+}  // namespace metrics
diff --git a/components/metrics/test_metrics_log_uploader.cc b/components/metrics/test_metrics_log_uploader.cc
index 0eff63f..d1a02af 100644
--- a/components/metrics/test_metrics_log_uploader.cc
+++ b/components/metrics/test_metrics_log_uploader.cc
@@ -16,13 +16,16 @@
 void TestMetricsLogUploader::CompleteUpload(int response_code) {
   DCHECK(is_uploading_);
   is_uploading_ = false;
+  last_reporting_info_.Clear();
   on_upload_complete_.Run(response_code, 0);
 }
 
 void TestMetricsLogUploader::UploadLog(const std::string& compressed_log_data,
-                                       const std::string& log_hash) {
+                                       const std::string& log_hash,
+                                       const ReportingInfo& reporting_info) {
   DCHECK(!is_uploading_);
   is_uploading_ = true;
+  last_reporting_info_ = reporting_info;
 }
 
 }  // namespace metrics
diff --git a/components/metrics/test_metrics_log_uploader.h b/components/metrics/test_metrics_log_uploader.h
index 5730ee5..a290c8e7 100644
--- a/components/metrics/test_metrics_log_uploader.h
+++ b/components/metrics/test_metrics_log_uploader.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_METRICS_TEST_METRICS_LOG_UPLOADER_H_
 
 #include "components/metrics/metrics_log_uploader.h"
+#include "components/metrics/proto/reporting_info.pb.h"
 
 namespace metrics {
 
@@ -21,12 +22,16 @@
   // Check if UploadLog has been called.
   bool is_uploading() const { return is_uploading_; }
 
+  const ReportingInfo& reporting_info() const { return last_reporting_info_; }
+
  private:
   // MetricsLogUploader:
   void UploadLog(const std::string& compressed_log_data,
-                 const std::string& log_hash) override;
+                 const std::string& log_hash,
+                 const ReportingInfo& reporting_info) override;
 
   const MetricsLogUploader::UploadCallback on_upload_complete_;
+  ReportingInfo last_reporting_info_;
   bool is_uploading_;
 
   DISALLOW_COPY_AND_ASSIGN(TestMetricsLogUploader);
diff --git a/components/nacl/features.gni b/components/nacl/features.gni
index de172b4d..4e48271 100644
--- a/components/nacl/features.gni
+++ b/components/nacl/features.gni
@@ -8,10 +8,14 @@
   # Enables Native Client support.
   # Temporarily disable nacl on arm64 linux to get rid of compilation errors.
   # TODO: When mipsel-nacl-clang is available, drop the exclusion.
-  enable_nacl = !is_ios && !is_android && !is_fuchsia && !is_chromecast &&
-                current_cpu != "mipsel" && current_cpu != "mips64el" &&
-                !(is_linux && target_cpu == "arm64")
+  enable_nacl =
+      !is_ios && !is_android && !is_fuchsia && !is_chromecast &&
+      current_cpu != "mipsel" && current_cpu != "mips64el" &&
+      !(is_linux && target_cpu == "arm64") && !(is_win && host_os != "win")
 
   # Non-SFI is not yet supported on mipsel
   enable_nacl_nonsfi = current_cpu != "mipsel" && current_cpu != "mips64el"
 }
+
+assert(!(is_win && host_os != "win") || !enable_nacl,
+       "NaCl doesn't work in win cross builds, crbug.com/774186")
diff --git a/components/omnibox/browser/shortcuts_provider.cc b/components/omnibox/browser/shortcuts_provider.cc
index 68f3ffc..32f47bf9 100644
--- a/components/omnibox/browser/shortcuts_provider.cc
+++ b/components/omnibox/browser/shortcuts_provider.cc
@@ -198,6 +198,7 @@
     const base::string16& find_text,
     const WordMap& find_words,
     const base::string16& text,
+    const bool text_is_search_query,
     const ACMatchClassifications& original_class) {
   DCHECK(!find_text.empty());
   DCHECK(!find_words.empty());
@@ -212,31 +213,35 @@
   // First check whether |text| begins with |find_text| and mark that whole
   // section as a match if so.
   base::string16 text_lowercase(base::i18n::ToLower(text));
+  const ACMatchClassification::Style& class_of_find_text =
+      text_is_search_query ? ACMatchClassification::NONE
+                           : ACMatchClassification::MATCH;
+  const ACMatchClassification::Style& class_of_additional_text =
+      text_is_search_query ? ACMatchClassification::MATCH
+                           : ACMatchClassification::NONE;
   ACMatchClassifications match_class;
   size_t last_position = 0;
   if (base::StartsWith(text_lowercase, find_text,
                        base::CompareCase::SENSITIVE)) {
-    match_class.push_back(
-        ACMatchClassification(0, ACMatchClassification::MATCH));
+    match_class.push_back(ACMatchClassification(0, class_of_find_text));
     last_position = find_text.length();
     // If |text_lowercase| is actually equal to |find_text|, we don't need to
     // (and in fact shouldn't) put a trailing NONE classification after the end
     // of the string.
     if (last_position < text_lowercase.length()) {
       match_class.push_back(
-          ACMatchClassification(last_position, ACMatchClassification::NONE));
+          ACMatchClassification(last_position, class_of_additional_text));
     }
   } else {
     // |match_class| should start at position 0.  If the first matching word is
     // found at position 0, this will be popped from the vector further down.
-    match_class.push_back(
-        ACMatchClassification(0, ACMatchClassification::NONE));
+    match_class.push_back(ACMatchClassification(0, class_of_additional_text));
   }
 
   // Now, starting with |last_position|, check each character in
   // |text_lowercase| to see if we have words starting with that character in
   // |find_words|.  If so, check each of them to see if they match the portion
-  // of |text_lowercase| beginning with |last_position|.  Accept the first
+  // of |text_lowercase| beginning with |last_position|. Accept the first
   // matching word found (which should be the longest possible match at this
   // location, given the construction of |find_words|) and add a MATCH region to
   // |match_class|, moving |last_position| to be after the matching word.  If we
@@ -255,10 +260,10 @@
           match_class.pop_back();
 
         AutocompleteMatch::AddLastClassificationIfNecessary(
-            &match_class, last_position, ACMatchClassification::MATCH);
+            &match_class, last_position, class_of_find_text);
         if (word_end < text_lowercase.length()) {
           match_class.push_back(
-              ACMatchClassification(word_end, ACMatchClassification::NONE));
+              ACMatchClassification(word_end, class_of_additional_text));
         }
         last_position = word_end;
         break;
@@ -393,7 +398,8 @@
   // otherwise prevent inline autocompletion.  This allows, for example, the
   // input of "foo.c" to autocomplete to "foo.com" for a fill_into_edit of
   // "http://foo.com".
-  if (AutocompleteMatch::IsSearchType(match.type)) {
+  const bool is_search_type = AutocompleteMatch::IsSearchType(match.type);
+  if (is_search_type) {
     if (match.fill_into_edit.size() >= input.text().size() &&
         std::equal(match.fill_into_edit.begin(),
                    match.fill_into_edit.begin() + input.text().size(),
@@ -423,10 +429,12 @@
   // Try to mark pieces of the contents and description as matches if they
   // appear in |input.text()|.
   if (!terms_map.empty()) {
-    match.contents_class = ClassifyAllMatchesInString(
-        term_string, terms_map, match.contents, match.contents_class);
+    match.contents_class =
+        ClassifyAllMatchesInString(term_string, terms_map, match.contents,
+                                   is_search_type, match.contents_class);
     match.description_class = ClassifyAllMatchesInString(
-        term_string, terms_map, match.description, match.description_class);
+        term_string, terms_map, match.description,
+        /*text_is_search_query=*/false, match.description_class);
   }
   return match;
 }
diff --git a/components/omnibox/browser/shortcuts_provider.h b/components/omnibox/browser/shortcuts_provider.h
index feee948..c6646f94 100644
--- a/components/omnibox/browser/shortcuts_provider.h
+++ b/components/omnibox/browser/shortcuts_provider.h
@@ -47,21 +47,34 @@
   // equal_range().
   static WordMap CreateWordMapForString(const base::string16& text);
 
-  // Given |text| and a corresponding base set of classifications
-  // |original_class|, adds ACMatchClassification::MATCH markers for all
-  // instances of the words from |find_words| within |text| and returns the
-  // resulting classifications.  (|find_text| is provided as the original string
-  // used to create |find_words|.  This is supplied because it's common for this
-  // to be a prefix of |text|, so we can quickly check for that and mark that
-  // entire substring as a match before proceeding with the more generic
-  // algorithm.)
+  // Finds all instances of the words from |find_words| within |text|, adds
+  // classifications to |original_class| according to the logic described below,
+  // and returns the result.
   //
-  // For example, given the |text|
-  // "Sports and News at sports.somesite.com - visit us!" and |original_class|
-  // {{0, NONE}, {18, URL}, {37, NONE}} (marking "sports.somesite.com" as a
-  // URL), calling with |find_text| set to "sp ew" would return
-  // {{0, MATCH}, {2, NONE}, {12, MATCH}, {14, NONE}, {18, URL|MATCH},
-  // {20, URL}, {37, NONE}}.
+  //   - if |text_is_search_query| is false, the function adds
+  //   ACMatchClassification::MATCH markers for all such instances.
+  //
+  //   For example, given the |text|
+  //   "Sports and News at sports.somesite.com - visit us!" and |original_class|
+  //   {{0, NONE}, {18, URL}, {37, NONE}} (marking "sports.somesite.com" as a
+  //   URL), calling with |find_text| set to "sp ew" would return
+  //   {{0, MATCH}, {2, NONE}, {12, MATCH}, {14, NONE}, {18, URL|MATCH},
+  //   {20, URL}, {37, NONE}}.
+  //
+  //
+  //   - if |text_is_search_query| is true, applies the same logic, but uses
+  //   NONE for the matching text and MATCH for the non-matching text. This is
+  //   done to mimic the behavior of SearchProvider which decorates matches
+  //   according to the approach used by Google Suggest.
+  //
+  //   For example, given that |text| corresponds to a search query "panama
+  //   canal" and |original class| is {{0, NONE}}, calling with |find_text| set
+  //   to "canal" would return {{0,MATCH}, {7, NONE}}.
+  //
+  // |find_text| is provided as the original string used to create
+  // |find_words|.  This is supplied because it's common for this to be a prefix
+  // of |text|, so we can quickly check for that and mark that entire substring
+  // as a match before proceeding with the more generic algorithm.
   //
   // |find_words| should be as constructed by CreateWordMapForString(find_text).
   //
@@ -71,6 +84,7 @@
       const base::string16& find_text,
       const WordMap& find_words,
       const base::string16& text,
+      const bool text_is_search_query,
       const ACMatchClassifications& original_class);
 
   // ShortcutsBackendObserver:
diff --git a/components/omnibox/browser/shortcuts_provider_unittest.cc b/components/omnibox/browser/shortcuts_provider_unittest.cc
index 726c219..a910561d 100644
--- a/components/omnibox/browser/shortcuts_provider_unittest.cc
+++ b/components/omnibox/browser/shortcuts_provider_unittest.cc
@@ -223,26 +223,30 @@
 // convenient.
 class ClassifyTest {
  public:
-  ClassifyTest(const base::string16& text, ACMatchClassifications matches);
+  ClassifyTest(const base::string16& text,
+               const bool text_is_query,
+               ACMatchClassifications matches);
   ~ClassifyTest();
 
   ACMatchClassifications RunTest(const base::string16& find_text);
 
  private:
   const base::string16 text_;
+  const bool text_is_query_;
   const ACMatchClassifications matches_;
 };
 
 ClassifyTest::ClassifyTest(const base::string16& text,
+                           const bool text_is_query,
                            ACMatchClassifications matches)
-    : text_(text), matches_(matches) {}
+    : text_(text), text_is_query_(text_is_query), matches_(matches) {}
 
 ClassifyTest::~ClassifyTest() {}
 
 ACMatchClassifications ClassifyTest::RunTest(const base::string16& find_text) {
   return ShortcutsProvider::ClassifyAllMatchesInString(
       find_text, ShortcutsProvider::CreateWordMapForString(find_text), text_,
-      matches_);
+      text_is_query_, matches_);
 }
 
 // ShortcutsProviderTest ------------------------------------------------------
@@ -525,7 +529,7 @@
   ACMatchClassifications matches =
       AutocompleteMatch::ClassificationsFromString("0,0");
   ClassifyTest classify_test(ASCIIToUTF16("A man, a plan, a canal Panama"),
-                             matches);
+                             /*text_is_query=*/false, matches);
 
   ACMatchClassifications spans_a = classify_test.RunTest(ASCIIToUTF16("man"));
   // ACMatch spans should be: '--MMM------------------------'
@@ -545,7 +549,7 @@
   ClassifyTest classify_test2(
       ASCIIToUTF16("Yahoo! Sports - Sports News, "
                    "Scores, Rumors, Fantasy Games, and more"),
-      matches);
+      /*text_is_query=*/false, matches);
 
   ACMatchClassifications spans_d = classify_test2.RunTest(ASCIIToUTF16("ne"));
   // ACMatch spans should match first two letters of the "news".
@@ -560,7 +564,8 @@
       AutocompleteMatch::ClassificationsToString(spans_e));
 
   matches = AutocompleteMatch::ClassificationsFromString("0,1");
-  ClassifyTest classify_test3(ASCIIToUTF16("livescore.goal.com"), matches);
+  ClassifyTest classify_test3(ASCIIToUTF16("livescore.goal.com"),
+                              /*text_is_query=*/false, matches);
 
   ACMatchClassifications spans_f = classify_test3.RunTest(ASCIIToUTF16("go"));
   // ACMatch spans should match first two letters of the "goal".
@@ -569,7 +574,7 @@
 
   matches = AutocompleteMatch::ClassificationsFromString("0,0,13,1");
   ClassifyTest classify_test4(ASCIIToUTF16("Email login: mail.somecorp.com"),
-                              matches);
+                              /*text_is_query=*/false, matches);
 
   ACMatchClassifications spans_g = classify_test4.RunTest(ASCIIToUTF16("ail"));
   EXPECT_EQ("0,0,2,2,5,0,13,1,14,3,17,1",
@@ -589,14 +594,15 @@
   // Some web sites do not have a description.  If the string being searched is
   // empty, the classifications must also be empty: http://crbug.com/148647
   // Extra parens in the next line hack around C++03's "most vexing parse".
-  class ClassifyTest classify_test5((base::string16()),
+  class ClassifyTest classify_test5((base::string16()), /*text_is_query=*/false,
                                     ACMatchClassifications());
   ACMatchClassifications spans_j = classify_test5.RunTest(ASCIIToUTF16("man"));
   ASSERT_EQ(0U, spans_j.size());
 
   // Matches which end at beginning of classification merge properly.
   matches = AutocompleteMatch::ClassificationsFromString("0,4,9,0");
-  ClassifyTest classify_test6(ASCIIToUTF16("html password example"), matches);
+  ClassifyTest classify_test6(ASCIIToUTF16("html password example"),
+                              /*text_is_query=*/false, matches);
 
   // Extra space in the next string avoids having the string be a prefix of the
   // text above, which would allow for two different valid classification sets,
@@ -612,12 +618,27 @@
   // Multiple matches with both beginning and end at beginning of
   // classifications merge properly.
   matches = AutocompleteMatch::ClassificationsFromString("0,1,11,0");
-  ClassifyTest classify_test7(ASCIIToUTF16("http://a.co is great"), matches);
+  ClassifyTest classify_test7(ASCIIToUTF16("http://a.co is great"),
+                              /*text_is_query=*/false, matches);
 
   ACMatchClassifications spans_l =
       classify_test7.RunTest(ASCIIToUTF16("ht co"));
   EXPECT_EQ("0,3,2,1,9,3,11,0",
             AutocompleteMatch::ClassificationsToString(spans_l));
+
+  // Queries should be classify the same way as google seach autocomplete
+  // suggestions.
+  matches = AutocompleteMatch::ClassificationsFromString("0,0");
+  ClassifyTest classify_test8(ASCIIToUTF16("panama canal"),
+                              /*text_is_query=*/true, matches);
+
+  ACMatchClassifications spans_m = classify_test8.RunTest(ASCIIToUTF16("pan"));
+  // ACMatch spans should be: "---MMMMMMMMM";
+  EXPECT_EQ("0,0,3,2", AutocompleteMatch::ClassificationsToString(spans_m));
+  ACMatchClassifications spans_n =
+      classify_test8.RunTest(ASCIIToUTF16("canal"));
+  // ACMatch spans should be: "MMMMMM-----";
+  EXPECT_EQ("0,2,7,0", AutocompleteMatch::ClassificationsToString(spans_n));
 }
 
 TEST_F(ShortcutsProviderTest, CalculateScore) {
diff --git a/components/page_info_strings.grdp b/components/page_info_strings.grdp
index 1af436c..f5b4de86 100644
--- a/components/page_info_strings.grdp
+++ b/components/page_info_strings.grdp
@@ -322,11 +322,6 @@
       </message>
     </if>
 
-    <!-- VR browser -->
-    <message name="IDS_PAGE_INFO_VR_BROWSER_UNSUPPORTED_MODE" desc="This text is displayed as a large toast to inform the user that they cannot currently browse in VR and they will soon exit VR mode.">
-      This page contains features not yet supported in VR. Exiting...
-    </message>
-
     <!-- Password Protection -->
     <if expr="not is_android">
       <message name="IDS_PAGE_INFO_CHANGE_PASSWORD_SUMMARY" desc="A one-line summary at the top of the Page Info bubble (which shows when you click the security indicator) if user has reuse their google password on current website.">
diff --git a/components/payments/content/utility/fingerprint_parser.cc b/components/payments/content/utility/fingerprint_parser.cc
index 98cb171..680a13a 100644
--- a/components/payments/content/utility/fingerprint_parser.cc
+++ b/components/payments/content/utility/fingerprint_parser.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/strings/string_util.h"
 
 namespace payments {
 namespace {
@@ -31,6 +32,11 @@
     return output;
   }
 
+  if (!base::IsStringASCII(input)) {
+    LOG(ERROR) << "Fingerprint \"" << input << "\" should be ASCII.";
+    return output;
+  }
+
   for (size_t i = 0; i < input.size(); i += 3) {
     if (i < input.size() - 2 && input[i + 2] != ':') {
       LOG(ERROR) << "Bytes in fingerprint \"" << input
diff --git a/components/payments/content/utility/fingerprint_parser_unittest.cc b/components/payments/content/utility/fingerprint_parser_unittest.cc
index 2c79635..d7e6409c 100644
--- a/components/payments/content/utility/fingerprint_parser_unittest.cc
+++ b/components/payments/content/utility/fingerprint_parser_unittest.cc
@@ -74,6 +74,14 @@
                   .empty());
 }
 
+TEST(FingerprintParserTest, MustBeASCII) {
+  EXPECT_TRUE(FingerprintStringToByteArray("β:01:02:03:04:05:06:07:08:09:"
+                                           "A0:A1:A2:A3:A4:A5:A6:A7:A8:A9:"
+                                           "B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:"
+                                           "C0:C1")
+                  .empty());
+}
+
 TEST(FingerprintParserTest, CorrectParsing) {
   std::vector<uint8_t> actual_output = FingerprintStringToByteArray(
       "00:01:02:03:04:05:06:07:08:09:A0:"
diff --git a/components/payments/content/utility/payment_manifest_parser.cc b/components/payments/content/utility/payment_manifest_parser.cc
index b616a25e..64a93d8 100644
--- a/components/payments/content/utility/payment_manifest_parser.cc
+++ b/components/payments/content/utility/payment_manifest_parser.cc
@@ -27,6 +27,7 @@
 const size_t kMaximumNumberOfEntries = 100U;
 const char* const kDefaultApplications = "default_applications";
 const char* const kSupportedOrigins = "supported_origins";
+const char* const kHttpsPrefix = "https://";
 
 // Parses the "default_applications": ["https://some/url"] from |dict| into
 // |web_app_manifest_urls|. Returns 'false' for invalid data.
@@ -50,9 +51,12 @@
 
   for (size_t i = 0; i < apps_number; ++i) {
     std::string item;
-    if (!list->GetString(i, &item) || item.empty()) {
+    if (!list->GetString(i, &item) || item.empty() ||
+        !base::IsStringUTF8(item) ||
+        !base::StartsWith(item, kHttpsPrefix, base::CompareCase::SENSITIVE)) {
       LOG(ERROR) << "Each entry in \"" << kDefaultApplications
-                 << "\" must be a string.";
+                 << "\" must be UTF8 string that starts with \"" << kHttpsPrefix
+                 << "\".";
       web_app_manifest_urls->clear();
       return false;
     }
@@ -89,7 +93,7 @@
       if (item != "*") {
         LOG(ERROR) << "\"" << item << "\" is not a valid value for \""
                    << kSupportedOrigins
-                   << "\". Must be either \"*\" or a list of origins.";
+                   << "\". Must be either \"*\" or a list of RFC6454 origins.";
         return false;
       }
 
@@ -115,9 +119,12 @@
 
   for (size_t i = 0; i < supported_origins_number; ++i) {
     std::string item;
-    if (!list->GetString(i, &item) || item.empty()) {
+    if (!list->GetString(i, &item) || item.empty() ||
+        !base::IsStringUTF8(item) ||
+        !base::StartsWith(item, kHttpsPrefix, base::CompareCase::SENSITIVE)) {
       LOG(ERROR) << "Each entry in \"" << kSupportedOrigins
-                 << "\" must be a string.";
+                 << "\" must be UTF8 string that starts with \"" << kHttpsPrefix
+                 << "\".";
       supported_origins->clear();
       return false;
     }
diff --git a/components/payments/content/utility/payment_manifest_parser_unittest.cc b/components/payments/content/utility/payment_manifest_parser_unittest.cc
index bd711d10..c8d0132 100644
--- a/components/payments/content/utility/payment_manifest_parser_unittest.cc
+++ b/components/payments/content/utility/payment_manifest_parser_unittest.cc
@@ -22,8 +22,9 @@
       input, &actual_web_app_urls, &actual_supported_origins,
       &actual_all_origins_supported);
 
-  EXPECT_TRUE(actual_web_app_urls.empty());
-  EXPECT_TRUE(actual_supported_origins.empty());
+  EXPECT_TRUE(actual_web_app_urls.empty()) << actual_web_app_urls.front();
+  EXPECT_TRUE(actual_supported_origins.empty())
+      << actual_supported_origins.front();
   EXPECT_FALSE(actual_all_origins_supported);
 }
 
@@ -88,6 +89,11 @@
       "{\"default_applications\": [\"https://bobpay.com/app\0json\"]}");
 }
 
+TEST(PaymentManifestParserTest, DefaultApplicationsShouldBeUTF8) {
+  ExpectUnableToParsePaymentMethodManifest(
+      "{\"default_applications\":[\"https://b\x0f\x7f\xf0\xff!\"]}");
+}
+
 TEST(PaymentManifestParserTest, DefaultApplicationKeyShouldBeLowercase) {
   ExpectUnableToParsePaymentMethodManifest(
       "{\"Default_Applications\": [\"https://bobpay.com/app.json\"]}");
@@ -132,6 +138,11 @@
       "{\"supported_origins\": [\"https://bob\0pay.com\"]}");
 }
 
+TEST(PaymentManifestParserTest, SupportedOriginsShouldBeUTF8) {
+  ExpectUnableToParsePaymentMethodManifest(
+      "{\"supported_origins\":[\"https://b\x0f\x7f\xf0\xff!\"]}");
+}
+
 TEST(PaymentManifestParserTest, SupportedOriginsShouldBeHttps) {
   ExpectUnableToParsePaymentMethodManifest(
       "{\"supported_origins\": [\"http://bobpay.com\"]}");
diff --git a/components/safe_json/BUILD.gn b/components/safe_json/BUILD.gn
deleted file mode 100644
index 37befe20..0000000
--- a/components/safe_json/BUILD.gn
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-if (is_android) {
-  import("//build/config/android/rules.gni")
-}
-
-static_library("safe_json") {
-  sources = [
-    "json_sanitizer.cc",
-    "json_sanitizer.h",
-    "json_sanitizer_android.cc",
-    "safe_json_parser.cc",
-    "safe_json_parser.h",
-    "safe_json_parser_android.cc",
-    "safe_json_parser_android.h",
-    "safe_json_parser_impl.cc",
-    "safe_json_parser_impl.h",
-  ]
-
-  deps = [
-    "//base",
-    "//components/safe_json/public/interfaces",
-    "//components/strings",
-    "//content/public/browser",
-    "//content/public/common",
-    "//ui/base",
-  ]
-
-  if (is_android) {
-    sources -= [
-      "json_sanitizer.cc",
-      "safe_json_parser_impl.cc",
-      "safe_json_parser_impl.h",
-    ]
-    deps += [ "android:safe_json_jni_headers" ]
-    deps -= [
-      "//components/safe_json/public/interfaces",
-      "//content/public/browser",
-    ]
-  }
-}
-
-source_set("unit_tests") {
-  testonly = true
-  sources = [
-    "json_sanitizer_unittest.cc",
-    "testing_json_parser_unittest.cc",
-  ]
-
-  deps = [
-    ":safe_json",
-    ":test_support",
-    "//base",
-    "//testing/gtest",
-  ]
-}
-
-static_library("test_support") {
-  testonly = true
-  sources = [
-    "testing_json_parser.cc",
-    "testing_json_parser.h",
-  ]
-
-  deps = [
-    ":safe_json",
-    "//base",
-  ]
-}
diff --git a/components/safe_json/DEPS b/components/safe_json/DEPS
deleted file mode 100644
index 64027775..0000000
--- a/components/safe_json/DEPS
+++ /dev/null
@@ -1,10 +0,0 @@
-include_rules = [
-  "+components/grit/components_resources.h",
-  "+components/strings/grit/components_strings.h",
-  "+content/public/browser",
-  "+content/public/common",
-  "+content/public/utility",
-  "+jni",
-  "+mojo/public/cpp",
-  "+ui/base",
-]
diff --git a/components/safe_json/OWNERS b/components/safe_json/OWNERS
deleted file mode 100644
index c8075494..0000000
--- a/components/safe_json/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-bauerb@chromium.org
-rsesek@chromium.org
-
-# TEAM: security-dev@chromium.org
diff --git a/components/safe_json/android/BUILD.gn b/components/safe_json/android/BUILD.gn
deleted file mode 100644
index a9f89fe..0000000
--- a/components/safe_json/android/BUILD.gn
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/android/rules.gni")
-
-_jni_sources =
-    [ "java/src/org/chromium/components/safejson/JsonSanitizer.java" ]
-
-generate_jni("safe_json_jni_headers") {
-  sources = _jni_sources
-  jni_package = "safe_json"
-}
-
-android_library("safe_json_java") {
-  deps = [
-    "//base:base_java",
-  ]
-  java_files = [] + _jni_sources
-}
diff --git a/components/safe_json/public/interfaces/BUILD.gn b/components/safe_json/public/interfaces/BUILD.gn
deleted file mode 100644
index bd150aa..0000000
--- a/components/safe_json/public/interfaces/BUILD.gn
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("interfaces") {
-  sources = [
-    "safe_json.mojom",
-  ]
-
-  public_deps = [
-    "//mojo/common:common_custom_types",
-  ]
-}
diff --git a/components/safe_json/public/interfaces/OWNERS b/components/safe_json/public/interfaces/OWNERS
deleted file mode 100644
index 08850f4..0000000
--- a/components/safe_json/public/interfaces/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/components/safe_json/safe_json_parser.cc b/components/safe_json/safe_json_parser.cc
deleted file mode 100644
index 7d2bbfd..0000000
--- a/components/safe_json/safe_json_parser.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/safe_json/safe_json_parser.h"
-
-#include "build/build_config.h"
-
-#if defined(OS_ANDROID)
-#include "components/safe_json/safe_json_parser_android.h"
-#else
-#include "components/safe_json/safe_json_parser_impl.h"
-#endif
-
-namespace safe_json {
-
-namespace {
-
-SafeJsonParser::Factory g_factory = nullptr;
-
-SafeJsonParser* Create(const std::string& unsafe_json,
-                       const SafeJsonParser::SuccessCallback& success_callback,
-                       const SafeJsonParser::ErrorCallback& error_callback) {
-  if (g_factory)
-    return g_factory(unsafe_json, success_callback, error_callback);
-
-#if defined(OS_ANDROID)
-  return new SafeJsonParserAndroid(unsafe_json, success_callback,
-                                   error_callback);
-#else
-  return new SafeJsonParserImpl(unsafe_json, success_callback, error_callback);
-#endif
-}
-
-}  // namespace
-
-// static
-void SafeJsonParser::SetFactoryForTesting(Factory factory) {
-  g_factory = factory;
-}
-
-// static
-void SafeJsonParser::Parse(const std::string& unsafe_json,
-                           const SuccessCallback& success_callback,
-                           const ErrorCallback& error_callback) {
-  SafeJsonParser* parser =
-      Create(unsafe_json, success_callback, error_callback);
-  parser->Start();
-}
-
-}  // namespace safe_json
diff --git a/components/safe_json/utility/BUILD.gn b/components/safe_json/utility/BUILD.gn
deleted file mode 100644
index bc7024d6..0000000
--- a/components/safe_json/utility/BUILD.gn
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-static_library("utility") {
-  sources = [
-    "safe_json_parser_mojo_impl.cc",
-    "safe_json_parser_mojo_impl.h",
-  ]
-
-  deps = [
-    "//base",
-    "//components/safe_json/public/interfaces",
-  ]
-}
diff --git a/components/safe_json/utility/safe_json_parser_mojo_impl.cc b/components/safe_json/utility/safe_json_parser_mojo_impl.cc
deleted file mode 100644
index 559955e..0000000
--- a/components/safe_json/utility/safe_json_parser_mojo_impl.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/safe_json/utility/safe_json_parser_mojo_impl.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/json/json_reader.h"
-#include "base/memory/ptr_util.h"
-#include "base/values.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-
-namespace safe_json {
-
-SafeJsonParserMojoImpl::SafeJsonParserMojoImpl() = default;
-
-SafeJsonParserMojoImpl::~SafeJsonParserMojoImpl() = default;
-
-// static
-void SafeJsonParserMojoImpl::Create(
-    mojom::SafeJsonParserRequest request) {
-  mojo::MakeStrongBinding(base::MakeUnique<SafeJsonParserMojoImpl>(),
-                          std::move(request));
-}
-
-void SafeJsonParserMojoImpl::Parse(const std::string& json,
-                                   ParseCallback callback) {
-  int error_code;
-  std::string error;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      json, base::JSON_PARSE_RFC, &error_code, &error);
-  if (value) {
-    std::move(callback).Run(std::move(value), base::nullopt);
-  } else {
-    std::move(callback).Run(nullptr, base::make_optional(std::move(error)));
-  }
-}
-
-}  // namespace safe_json
diff --git a/components/safe_json/utility/safe_json_parser_mojo_impl.h b/components/safe_json/utility/safe_json_parser_mojo_impl.h
deleted file mode 100644
index ab4194d..0000000
--- a/components/safe_json/utility/safe_json_parser_mojo_impl.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SAFE_JSON_SAFE_JSON_PARSER_MOJO_IMPL_H_
-#define COMPONENTS_SAFE_JSON_SAFE_JSON_PARSER_MOJO_IMPL_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "components/safe_json/public/interfaces/safe_json.mojom.h"
-
-namespace safe_json {
-
-class SafeJsonParserMojoImpl : public mojom::SafeJsonParser {
- public:
-  SafeJsonParserMojoImpl();
-  ~SafeJsonParserMojoImpl() override;
-
-  static void Create(mojom::SafeJsonParserRequest request);
-
- private:
-  // mojom::SafeJsonParser implementation.
-  void Parse(const std::string& json, ParseCallback callback) override;
-
-  DISALLOW_COPY_AND_ASSIGN(SafeJsonParserMojoImpl);
-};
-
-}  // namespace safe_json
-
-#endif  // COMPONENTS_SAFE_JSON_SAFE_JSON_PARSER_MOJO_IMPL_H_
diff --git a/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.cc b/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.cc
index 49e98b75..9d1290b 100644
--- a/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.cc
+++ b/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.cc
@@ -10,7 +10,8 @@
 #include "content/public/browser/browser_thread.h"
 #include "url/gurl.h"
 
-FakeSafeBrowsingDatabaseManager::FakeSafeBrowsingDatabaseManager() {}
+FakeSafeBrowsingDatabaseManager::FakeSafeBrowsingDatabaseManager()
+    : weak_factory_(this) {}
 
 void FakeSafeBrowsingDatabaseManager::AddBlacklistedUrl(
     const GURL& url,
@@ -61,7 +62,7 @@
       content::BrowserThread::IO, FROM_HERE,
       base::Bind(&FakeSafeBrowsingDatabaseManager::
                      OnCheckUrlForSubresourceFilterComplete,
-                 base::Unretained(this), base::Unretained(client), url));
+                 weak_factory_.GetWeakPtr(), base::Unretained(client), url));
   return false;
 }
 
diff --git a/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h b/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h
index 5c7e52c..764fbdf 100644
--- a/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h
+++ b/components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h
@@ -9,6 +9,7 @@
 #include <set>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "components/safe_browsing/db/test_database_manager.h"
 #include "content/public/common/resource_type.h"
 
@@ -64,6 +65,8 @@
   bool simulate_timeout_ = false;
   bool synchronous_failure_ = false;
 
+  base::WeakPtrFactory<FakeSafeBrowsingDatabaseManager> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingDatabaseManager);
 };
 
diff --git a/components/test/BUILD.gn b/components/test/BUILD.gn
index f6402ed..57faf38 100644
--- a/components/test/BUILD.gn
+++ b/components/test/BUILD.gn
@@ -29,7 +29,6 @@
     deps += [
       "//components/invalidation/impl",
       "//components/policy/core/browser",
-      "//components/safe_json",
       "//ui/gl:test_support",
     ]
 
diff --git a/content/app/content_service_manager_main_delegate.cc b/content/app/content_service_manager_main_delegate.cc
index 104f2bd..62dceb5 100644
--- a/content/app/content_service_manager_main_delegate.cc
+++ b/content/app/content_service_manager_main_delegate.cc
@@ -109,14 +109,6 @@
     command_line->AppendArgNative(arg);
 }
 
-bool ContentServiceManagerMainDelegate::
-    ShouldTerminateServiceManagerOnInstanceQuit(
-        const service_manager::Identity& identity,
-        int* exit_code) {
-  return content_main_params_.delegate
-      ->ShouldTerminateServiceManagerOnInstanceQuit(identity, exit_code);
-}
-
 void ContentServiceManagerMainDelegate::OnServiceManagerInitialized(
     const base::Closure& quit_closure,
     service_manager::BackgroundServiceManager* service_manager) {
diff --git a/content/app/content_service_manager_main_delegate.h b/content/app/content_service_manager_main_delegate.h
index 7563ce4..4393a8f 100644
--- a/content/app/content_service_manager_main_delegate.h
+++ b/content/app/content_service_manager_main_delegate.h
@@ -34,9 +34,6 @@
   void AdjustServiceProcessCommandLine(
       const service_manager::Identity& identity,
       base::CommandLine* command_line) override;
-  bool ShouldTerminateServiceManagerOnInstanceQuit(
-      const service_manager::Identity& identity,
-      int* exit_code) override;
   void OnServiceManagerInitialized(
       const base::Closure& quit_closure,
       service_manager::BackgroundServiceManager* service_manager) override;
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index ac6c6a3..33b3ca9d4 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -1437,40 +1437,29 @@
       is_mus) {
     established_gpu_channel = always_uses_gpu = false;
   }
-  gpu::GpuChannelEstablishFactory* factory =
-      GetContentClient()->browser()->GetGpuChannelEstablishFactory();
-  if (!factory) {
-    BrowserGpuChannelHostFactory::Initialize(established_gpu_channel);
-    factory = BrowserGpuChannelHostFactory::instance();
-  }
-#if !defined(OS_ANDROID)
   if (!is_mus) {
-    // TODO(kylechar): Remove flag along with surface sequences.
-    // See https://crbug.com/676384.
+    host_frame_sink_manager_ = base::MakeUnique<viz::HostFrameSinkManager>();
+
+    // TODO(crbug.com/676384): Remove flag along with surface sequences.
     auto surface_lifetime_type =
-        base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kDisableSurfaceReferences)
+        parsed_command_line_.HasSwitch(switches::kDisableSurfaceReferences)
             ? viz::SurfaceManager::LifetimeType::SEQUENCES
             : viz::SurfaceManager::LifetimeType::REFERENCES;
     frame_sink_manager_impl_ =
         std::make_unique<viz::FrameSinkManagerImpl>(surface_lifetime_type);
 
-    host_frame_sink_manager_ = base::MakeUnique<viz::HostFrameSinkManager>();
-
     // TODO(danakj): Don't make a FrameSinkManagerImpl when display is in the
     // Gpu process, instead get the mojo pointer from the Gpu process.
     surface_utils::ConnectWithLocalFrameSinkManager(
         host_frame_sink_manager_.get(), frame_sink_manager_impl_.get());
-  }
-#endif
 
-  DCHECK(factory);
-  if (!is_mus) {
+    // Initialize GpuChannelHostFactory and ImageTransportFactory.
+    BrowserGpuChannelHostFactory::Initialize(established_gpu_channel);
     ImageTransportFactory::SetFactory(
-        std::make_unique<GpuProcessTransportFactory>(GetResizeTaskRunner()));
-    ImageTransportFactory::GetInstance()->SetGpuChannelEstablishFactory(
-        factory);
+        std::make_unique<GpuProcessTransportFactory>(
+            BrowserGpuChannelHostFactory::instance(), GetResizeTaskRunner()));
   }
+
 #if defined(USE_AURA)
   if (env_->mode() == aura::Env::Mode::LOCAL) {
     env_->set_context_factory(GetContextFactory());
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index 45bf6b1..5a0f33bf 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -231,13 +231,16 @@
 };
 
 GpuProcessTransportFactory::GpuProcessTransportFactory(
+    gpu::GpuChannelEstablishFactory* gpu_channel_factory,
     scoped_refptr<base::SingleThreadTaskRunner> resize_task_runner)
     : frame_sink_id_allocator_(kDefaultClientId),
       renderer_settings_(
           viz::CreateRendererSettings(CreateBufferToTextureTargetMap())),
       resize_task_runner_(std::move(resize_task_runner)),
       task_graph_runner_(new cc::SingleThreadTaskGraphRunner),
+      gpu_channel_factory_(gpu_channel_factory),
       callback_factory_(this) {
+  DCHECK(gpu_channel_factory_);
   cc::SetClientNameForMetrics("Browser");
 
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
@@ -380,7 +383,6 @@
         base::Bind(&GpuProcessTransportFactory::EstablishedGpuChannel,
                    callback_factory_.GetWeakPtr(), compositor,
                    create_gpu_output_surface, 0));
-    DCHECK(gpu_channel_factory_);
     gpu_channel_factory_->EstablishGpuChannel(callback);
   } else {
     EstablishedGpuChannel(compositor, create_gpu_output_surface, 0, nullptr);
@@ -501,7 +503,6 @@
           base::Bind(&GpuProcessTransportFactory::EstablishedGpuChannel,
                      callback_factory_.GetWeakPtr(), compositor,
                      create_gpu_output_surface, num_attempts + 1));
-      DCHECK(gpu_channel_factory_);
       gpu_channel_factory_->EstablishGpuChannel(callback);
       return;
     }
@@ -905,12 +906,6 @@
   return gl_helper_.get();
 }
 
-void GpuProcessTransportFactory::SetGpuChannelEstablishFactory(
-    gpu::GpuChannelEstablishFactory* factory) {
-  DCHECK(!gpu_channel_factory_ || !factory);
-  gpu_channel_factory_ = factory;
-}
-
 #if defined(OS_MACOSX)
 void GpuProcessTransportFactory::SetCompositorSuspendedForRecycle(
     ui::Compositor* compositor,
@@ -933,7 +928,6 @@
   if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
     return nullptr;
 
-  DCHECK(gpu_channel_factory_);
   scoped_refptr<gpu::GpuChannelHost> gpu_channel_host =
       gpu_channel_factory_->EstablishGpuChannelSync();
   if (!gpu_channel_host)
diff --git a/content/browser/compositor/gpu_process_transport_factory.h b/content/browser/compositor/gpu_process_transport_factory.h
index 25340e5..5d640f7 100644
--- a/content/browser/compositor/gpu_process_transport_factory.h
+++ b/content/browser/compositor/gpu_process_transport_factory.h
@@ -33,6 +33,10 @@
 class SurfaceManager;
 }
 
+namespace gpu {
+class GpuChannelEstablishFactory;
+}
+
 namespace ui {
 class ContextProviderCommandBuffer;
 }
@@ -49,7 +53,8 @@
                                    public ui::ContextFactoryPrivate,
                                    public ImageTransportFactory {
  public:
-  explicit GpuProcessTransportFactory(
+  GpuProcessTransportFactory(
+      gpu::GpuChannelEstablishFactory* gpu_channel_factory,
       scoped_refptr<base::SingleThreadTaskRunner> resize_task_runner);
 
   ~GpuProcessTransportFactory() override;
@@ -93,8 +98,6 @@
   ui::ContextFactoryPrivate* GetContextFactoryPrivate() override;
   viz::FrameSinkManagerImpl* GetFrameSinkManager() override;
   viz::GLHelper* GetGLHelper() override;
-  void SetGpuChannelEstablishFactory(
-      gpu::GpuChannelEstablishFactory* factory) override;
 #if defined(OS_MACOSX)
   void SetCompositorSuspendedForRecycle(ui::Compositor* compositor,
                                         bool suspended) override;
@@ -145,7 +148,7 @@
   scoped_refptr<viz::VulkanInProcessContextProvider>
       shared_vulkan_context_provider_;
 
-  gpu::GpuChannelEstablishFactory* gpu_channel_factory_ = nullptr;
+  gpu::GpuChannelEstablishFactory* const gpu_channel_factory_;
 
   base::WeakPtrFactory<GpuProcessTransportFactory> callback_factory_;
 
diff --git a/content/browser/compositor/image_transport_factory.h b/content/browser/compositor/image_transport_factory.h
index 0d11f33b..2530bf3 100644
--- a/content/browser/compositor/image_transport_factory.h
+++ b/content/browser/compositor/image_transport_factory.h
@@ -20,10 +20,6 @@
 class GLHelper;
 }
 
-namespace gpu {
-class GpuChannelEstablishFactory;
-}
-
 namespace content {
 
 // This class provides the interface for creating the support for the
@@ -56,9 +52,6 @@
   // (ImageTransportFactoryObserver::OnLostResources is called).
   virtual viz::GLHelper* GetGLHelper() = 0;
 
-  virtual void SetGpuChannelEstablishFactory(
-      gpu::GpuChannelEstablishFactory* factory) = 0;
-
 #if defined(OS_MACOSX)
   // Called with |suspended| as true when the ui::Compositor has been
   // disconnected from an NSView and may be attached to another one. Called
diff --git a/content/browser/compositor/test/no_transport_image_transport_factory.cc b/content/browser/compositor/test/no_transport_image_transport_factory.cc
index 04ef61e..3e33c8c 100644
--- a/content/browser/compositor/test/no_transport_image_transport_factory.cc
+++ b/content/browser/compositor/test/no_transport_image_transport_factory.cc
@@ -58,7 +58,4 @@
   return gl_helper_.get();
 }
 
-void NoTransportImageTransportFactory::SetGpuChannelEstablishFactory(
-    gpu::GpuChannelEstablishFactory* factory) {}
-
 }  // namespace content
diff --git a/content/browser/compositor/test/no_transport_image_transport_factory.h b/content/browser/compositor/test/no_transport_image_transport_factory.h
index a42428a..fb70e199e 100644
--- a/content/browser/compositor/test/no_transport_image_transport_factory.h
+++ b/content/browser/compositor/test/no_transport_image_transport_factory.h
@@ -39,8 +39,6 @@
   ui::ContextFactory* GetContextFactory() override;
   ui::ContextFactoryPrivate* GetContextFactoryPrivate() override;
   viz::GLHelper* GetGLHelper() override;
-  void SetGpuChannelEstablishFactory(
-      gpu::GpuChannelEstablishFactory* factory) override;
 #if defined(OS_MACOSX)
   void SetCompositorSuspendedForRecycle(ui::Compositor* compositor,
                                         bool suspended) override {}
diff --git a/content/browser/frame_host/frame_tree.cc b/content/browser/frame_host/frame_tree.cc
index 7d3d5d7b..45f5972 100644
--- a/content/browser/frame_host/frame_tree.cc
+++ b/content/browser/frame_host/frame_tree.cc
@@ -26,9 +26,9 @@
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/common/content_switches_internal.h"
 #include "content/common/frame_owner_properties.h"
+#include "content/common/frame_policy.h"
 #include "content/common/input_messages.h"
 #include "content/common/site_isolation_policy.h"
-#include "third_party/WebKit/public/web/WebSandboxFlags.h"
 
 namespace content {
 
@@ -178,8 +178,7 @@
                          const std::string& frame_name,
                          const std::string& frame_unique_name,
                          const base::UnguessableToken& devtools_frame_token,
-                         blink::WebSandboxFlags sandbox_flags,
-                         const ParsedFeaturePolicyHeader& container_policy,
+                         const FramePolicy& frame_policy,
                          const FrameOwnerProperties& frame_owner_properties) {
   CHECK_NE(new_routing_id, MSG_ROUTING_NONE);
 
@@ -200,8 +199,8 @@
   // empty document in the frame. This needs to happen before the call to
   // AddChild so that the effective policy is sent to any newly-created
   // RenderFrameProxy objects when the RenderFrameHost is created.
-  new_node->SetPendingSandboxFlags(sandbox_flags);
-  new_node->SetPendingContainerPolicy(container_policy);
+  new_node->SetPendingSandboxFlags(frame_policy.sandbox_flags);
+  new_node->SetPendingContainerPolicy(frame_policy.container_policy);
   new_node->CommitPendingFramePolicy();
 
   // Add the new node to the FrameTree, creating the RenderFrameHost.
diff --git a/content/browser/frame_host/frame_tree.h b/content/browser/frame_host/frame_tree.h
index 379ecda1..f3915e3a 100644
--- a/content/browser/frame_host/frame_tree.h
+++ b/content/browser/frame_host/frame_tree.h
@@ -21,6 +21,7 @@
 namespace content {
 
 struct FrameOwnerProperties;
+struct FramePolicy;
 class Navigator;
 class RenderFrameHostDelegate;
 class RenderViewHostDelegate;
@@ -128,8 +129,7 @@
                 const std::string& frame_name,
                 const std::string& frame_unique_name,
                 const base::UnguessableToken& devtools_frame_token,
-                blink::WebSandboxFlags sandbox_flags,
-                const ParsedFeaturePolicyHeader& container_policy,
+                const FramePolicy& frame_policy,
                 const FrameOwnerProperties& frame_owner_properties);
 
   // Removes a frame from the frame tree. |child|, its children, and objects
diff --git a/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc b/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc
index b08c37b..47db159 100644
--- a/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc
+++ b/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc
@@ -12,10 +12,10 @@
 #include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/common/frame_owner_properties.h"
+#include "content/common/frame_policy.h"
 #include "content/test/test_render_view_host.h"
 #include "content/test/test_web_contents.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/web/WebSandboxFlags.h"
 
 namespace content {
 
@@ -131,11 +131,11 @@
     int consumption = 0;
     for (int child_num = 1; shape[consumption++] == '('; ++child_num) {
       int child_id = self_id * 10 + child_num;
-      tree()->AddFrame(
-          node, process_id(), child_id, blink::WebTreeScopeType::kDocument,
-          std::string(), base::StringPrintf("uniqueName%d", child_id),
-          base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-          ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      tree()->AddFrame(node, process_id(), child_id,
+                       blink::WebTreeScopeType::kDocument, std::string(),
+                       base::StringPrintf("uniqueName%d", child_id),
+                       base::UnguessableToken::Create(), FramePolicy(),
+                       FrameOwnerProperties());
       FrameTreeNode* child = node->child_at(child_num - 1);
       consumption += CreateSubframes(child, child_id, shape + consumption);
     }
diff --git a/content/browser/frame_host/frame_tree_unittest.cc b/content/browser/frame_host/frame_tree_unittest.cc
index eebf250..dea82c6 100644
--- a/content/browser/frame_host/frame_tree_unittest.cc
+++ b/content/browser/frame_host/frame_tree_unittest.cc
@@ -16,6 +16,7 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
+#include "content/common/frame_policy.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/test_browser_context.h"
@@ -24,7 +25,6 @@
 #include "content/test/test_render_view_host.h"
 #include "content/test/test_web_contents.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/web/WebSandboxFlags.h"
 
 namespace content {
 
@@ -159,34 +159,28 @@
   // Simulate attaching a series of frames to build the frame tree.
   frame_tree->AddFrame(root, process_id, 14, blink::WebTreeScopeType::kDocument,
                        std::string(), "uniqueName0",
-                       base::UnguessableToken::Create(),
-                       blink::WebSandboxFlags::kNone,
-                       ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+                       base::UnguessableToken::Create(), FramePolicy(),
+                       FrameOwnerProperties());
   frame_tree->AddFrame(root, process_id, 15, blink::WebTreeScopeType::kDocument,
                        std::string(), "uniqueName1",
-                       base::UnguessableToken::Create(),
-                       blink::WebSandboxFlags::kNone,
-                       ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+                       base::UnguessableToken::Create(), FramePolicy(),
+                       FrameOwnerProperties());
   frame_tree->AddFrame(root, process_id, 16, blink::WebTreeScopeType::kDocument,
                        std::string(), "uniqueName2",
-                       base::UnguessableToken::Create(),
-                       blink::WebSandboxFlags::kNone,
-                       ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+                       base::UnguessableToken::Create(), FramePolicy(),
+                       FrameOwnerProperties());
   frame_tree->AddFrame(root->child_at(0), process_id, 244,
                        blink::WebTreeScopeType::kDocument, std::string(),
                        "uniqueName3", base::UnguessableToken::Create(),
-                       blink::WebSandboxFlags::kNone,
-                       ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+                       FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(root->child_at(1), process_id, 255,
                        blink::WebTreeScopeType::kDocument, no_children_node,
                        "uniqueName4", base::UnguessableToken::Create(),
-                       blink::WebSandboxFlags::kNone,
-                       ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+                       FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(root->child_at(0), process_id, 245,
                        blink::WebTreeScopeType::kDocument, std::string(),
                        "uniqueName5", base::UnguessableToken::Create(),
-                       blink::WebSandboxFlags::kNone,
-                       ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+                       FramePolicy(), FrameOwnerProperties());
 
   EXPECT_EQ(
       "2: [14: [244: [], 245: []], "
@@ -198,50 +192,41 @@
   frame_tree->AddFrame(child_16, process_id, 264,
                        blink::WebTreeScopeType::kDocument, std::string(),
                        "uniqueName6", base::UnguessableToken::Create(),
-                       blink::WebSandboxFlags::kNone,
-                       ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+                       FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(child_16, process_id, 265,
                        blink::WebTreeScopeType::kDocument, std::string(),
                        "uniqueName7", base::UnguessableToken::Create(),
-                       blink::WebSandboxFlags::kNone,
-                       ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+                       FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(child_16, process_id, 266,
                        blink::WebTreeScopeType::kDocument, std::string(),
                        "uniqueName8", base::UnguessableToken::Create(),
-                       blink::WebSandboxFlags::kNone,
-                       ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+                       FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(child_16, process_id, 267,
                        blink::WebTreeScopeType::kDocument, deep_subtree,
                        "uniqueName9", base::UnguessableToken::Create(),
-                       blink::WebSandboxFlags::kNone,
-                       ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+                       FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(child_16, process_id, 268,
                        blink::WebTreeScopeType::kDocument, std::string(),
                        "uniqueName10", base::UnguessableToken::Create(),
-                       blink::WebSandboxFlags::kNone,
-                       ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+                       FramePolicy(), FrameOwnerProperties());
 
   FrameTreeNode* child_267 = child_16->child_at(3);
   frame_tree->AddFrame(child_267, process_id, 365,
                        blink::WebTreeScopeType::kDocument, std::string(),
                        "uniqueName11", base::UnguessableToken::Create(),
-                       blink::WebSandboxFlags::kNone,
-                       ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+                       FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(child_267->child_at(0), process_id, 455,
                        blink::WebTreeScopeType::kDocument, std::string(),
                        "uniqueName12", base::UnguessableToken::Create(),
-                       blink::WebSandboxFlags::kNone,
-                       ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+                       FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(child_267->child_at(0)->child_at(0), process_id, 555,
                        blink::WebTreeScopeType::kDocument, std::string(),
                        "uniqueName13", base::UnguessableToken::Create(),
-                       blink::WebSandboxFlags::kNone,
-                       ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+                       FramePolicy(), FrameOwnerProperties());
   frame_tree->AddFrame(
       child_267->child_at(0)->child_at(0)->child_at(0), process_id, 655,
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName14",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
 
   // Now that's it's fully built, verify the tree structure is as expected.
   EXPECT_EQ(
@@ -314,26 +299,21 @@
 
   main_test_rfh()->OnCreateChildFrame(
       22, blink::WebTreeScopeType::kDocument, "child0", "uniqueName0",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   main_test_rfh()->OnCreateChildFrame(
       23, blink::WebTreeScopeType::kDocument, "child1", "uniqueName1",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   main_test_rfh()->OnCreateChildFrame(
       24, blink::WebTreeScopeType::kDocument, std::string(), "uniqueName2",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   FrameTreeNode* child0 = root->child_at(0);
   FrameTreeNode* child1 = root->child_at(1);
-
   FrameTreeNode* child2 = root->child_at(2);
 
   // Add one grandchild frame.
   child1->current_frame_host()->OnCreateChildFrame(
       33, blink::WebTreeScopeType::kDocument, "grandchild", "uniqueName3",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   FrameTreeNode* grandchild = child1->child_at(0);
 
   // Ensure they can be found by FTN id.
@@ -371,16 +351,13 @@
   FrameTreeNode* root = frame_tree->root();
   main_test_rfh()->OnCreateChildFrame(
       22, blink::WebTreeScopeType::kDocument, "child0", "uniqueName0",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   main_test_rfh()->OnCreateChildFrame(
       23, blink::WebTreeScopeType::kDocument, "child1", "uniqueName1",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   main_test_rfh()->OnCreateChildFrame(
       24, blink::WebTreeScopeType::kDocument, "child2", "uniqueName2",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   FrameTreeNode* child0 = root->child_at(0);
   FrameTreeNode* child1 = root->child_at(1);
   FrameTreeNode* child2 = root->child_at(2);
@@ -388,8 +365,7 @@
   // Add one grandchild frame.
   child1->current_frame_host()->OnCreateChildFrame(
       33, blink::WebTreeScopeType::kDocument, "grandchild", "uniqueName3",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   FrameTreeNode* grandchild = child1->child_at(0);
 
   // Test PreviousSibling().
@@ -420,16 +396,14 @@
   // Simulate attaching a series of frames to build the frame tree.
   main_test_rfh()->OnCreateChildFrame(
       14, blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   EXPECT_EQ(
       "RenderFrameHostChanged(new)(14) -> 2: []\n"
       "RenderFrameCreated(14) -> 2: [14: []]",
       activity.GetLog());
   main_test_rfh()->OnCreateChildFrame(
       18, blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   EXPECT_EQ(
       "RenderFrameHostChanged(new)(18) -> 2: [14: []]\n"
       "RenderFrameCreated(18) -> 2: [14: [], 18: []]",
@@ -449,16 +423,14 @@
 
   main_test_rfh()->OnCreateChildFrame(
       22, blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   EXPECT_EQ(
       "RenderFrameHostChanged(new)(22) -> 2: []\n"
       "RenderFrameCreated(22) -> 2: [22: []]",
       activity.GetLog());
   main_test_rfh()->OnCreateChildFrame(
       23, blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   EXPECT_EQ(
       "RenderFrameHostChanged(new)(23) -> 2: [22: []]\n"
       "RenderFrameCreated(23) -> 2: [22: [], 23: []]",
@@ -488,8 +460,7 @@
   ASSERT_FALSE(frame_tree->AddFrame(
       root, process_id + 1, 1, blink::WebTreeScopeType::kDocument,
       std::string(), "uniqueName0", base::UnguessableToken::Create(),
-      blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
-      FrameOwnerProperties()));
+      FramePolicy(), FrameOwnerProperties()));
   ASSERT_EQ("2: []", GetTreeState(frame_tree));
 }
 
@@ -503,19 +474,16 @@
 
   main_test_rfh()->OnCreateChildFrame(
       22, blink::WebTreeScopeType::kDocument, std::string(), "uniqueName0",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   main_test_rfh()->OnCreateChildFrame(
       23, blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
 
   // Add one grandchild frame.
   RenderFrameHostImpl* child1_rfh = root->child_at(0)->current_frame_host();
   child1_rfh->OnCreateChildFrame(
       33, blink::WebTreeScopeType::kDocument, std::string(), "uniqueName2",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
 
   // Ensure they can be found by id.
   int id1 = root->child_at(0)->frame_tree_node_id();
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index 56a66a6..e2d3dfa 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -31,6 +31,7 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
+#include "content/common/frame_policy.h"
 #include "content/common/site_isolation_policy.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/render_view_host.h"
@@ -50,7 +51,6 @@
 #include "content/test/test_web_contents.h"
 #include "skia/ext/platform_canvas.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/web/WebSandboxFlags.h"
 
 using base::Time;
 
@@ -2223,8 +2223,7 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(), blink::WebTreeScopeType::kDocument,
       std::string(), unique_name, base::UnguessableToken::Create(),
-      blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
-      FrameOwnerProperties());
+      FramePolicy(), FrameOwnerProperties());
   TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
       contents()->GetFrameTree()->root()->child_at(0)->current_frame_host());
   const GURL subframe_url("http://foo1/subframe");
@@ -2300,8 +2299,7 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(), blink::WebTreeScopeType::kDocument,
       std::string(), unique_name0, base::UnguessableToken::Create(),
-      blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
-      FrameOwnerProperties());
+      FramePolicy(), FrameOwnerProperties());
   TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
       contents()->GetFrameTree()->root()->child_at(0)->current_frame_host());
   const GURL url2("http://foo/2");
@@ -2345,8 +2343,7 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(), blink::WebTreeScopeType::kDocument,
       std::string(), unique_name1, base::UnguessableToken::Create(),
-      blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
-      FrameOwnerProperties());
+      FramePolicy(), FrameOwnerProperties());
   TestRenderFrameHost* subframe2 = static_cast<TestRenderFrameHost*>(
       contents()->GetFrameTree()->root()->child_at(1)->current_frame_host());
   const GURL url3("http://foo/3");
@@ -2390,8 +2387,7 @@
   subframe->OnCreateChildFrame(
       process()->GetNextRoutingID(), blink::WebTreeScopeType::kDocument,
       std::string(), unique_name2, base::UnguessableToken::Create(),
-      blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
-      FrameOwnerProperties());
+      FramePolicy(), FrameOwnerProperties());
   TestRenderFrameHost* subframe3 =
       static_cast<TestRenderFrameHost*>(contents()
                                             ->GetFrameTree()
@@ -2453,8 +2449,7 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(), blink::WebTreeScopeType::kDocument,
       std::string(), unique_name, base::UnguessableToken::Create(),
-      blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
-      FrameOwnerProperties());
+      FramePolicy(), FrameOwnerProperties());
   TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
       contents()->GetFrameTree()->root()->child_at(0)->current_frame_host());
   const GURL subframe_url("http://foo1/subframe");
@@ -3857,8 +3852,7 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(), blink::WebTreeScopeType::kDocument,
       std::string(), unique_name, base::UnguessableToken::Create(),
-      blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
-      FrameOwnerProperties());
+      FramePolicy(), FrameOwnerProperties());
   TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
       contents()->GetFrameTree()->root()->child_at(0)->current_frame_host());
   const GURL subframe_url("http://www.google.com/#");
@@ -4032,8 +4026,7 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(), blink::WebTreeScopeType::kDocument,
       std::string(), unique_name, base::UnguessableToken::Create(),
-      blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
-      FrameOwnerProperties());
+      FramePolicy(), FrameOwnerProperties());
   TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
       contents()->GetFrameTree()->root()->child_at(0)->current_frame_host());
   const GURL url1_sub("http://foo/subframe");
diff --git a/content/browser/frame_host/render_frame_host_feature_policy_unittest.cc b/content/browser/frame_host/render_frame_host_feature_policy_unittest.cc
index 2475dd9..77663b0 100644
--- a/content/browser/frame_host/render_frame_host_feature_policy_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_feature_policy_unittest.cc
@@ -5,6 +5,7 @@
 #include <vector>
 
 #include "content/common/feature_policy/feature_policy.h"
+#include "content/common/frame_policy.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/navigation_simulator.h"
@@ -66,8 +67,8 @@
                           blink::WebFeaturePolicyFeature feature,
                           const std::vector<std::string>& origins) {
     static_cast<TestRenderFrameHost*>(parent)->OnDidChangeFramePolicy(
-        child->GetRoutingID(), blink::WebSandboxFlags(),
-        CreateFPHeader(feature, origins));
+        child->GetRoutingID(),
+        {blink::WebSandboxFlags::kNone, CreateFPHeader(feature, origins)});
   }
 
   void SimulateNavigation(RenderFrameHost** rfh, const GURL& url) {
@@ -178,4 +179,4 @@
   EXPECT_FALSE(child->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-}  // namespace content
\ No newline at end of file
+}  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 2b2e16f..186cd94 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -83,6 +83,7 @@
 #include "content/common/content_security_policy/content_security_policy.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
+#include "content/common/frame_policy.h"
 #include "content/common/input/input_handler.mojom.h"
 #include "content/common/input_messages.h"
 #include "content/common/inter_process_time_ticks_converter.h"
@@ -1312,8 +1313,7 @@
     const std::string& frame_name,
     const std::string& frame_unique_name,
     const base::UnguessableToken& devtools_frame_token,
-    blink::WebSandboxFlags sandbox_flags,
-    const ParsedFeaturePolicyHeader& container_policy,
+    const FramePolicy& frame_policy,
     const FrameOwnerProperties& frame_owner_properties) {
   // TODO(lukasza): Call ReceivedBadMessage when |frame_unique_name| is empty.
   DCHECK(!frame_unique_name.empty());
@@ -1329,7 +1329,7 @@
   // IO thread and not taken from the renderer process.
   frame_tree_->AddFrame(frame_tree_node_, GetProcess()->GetID(), new_routing_id,
                         scope, frame_name, frame_unique_name,
-                        devtools_frame_token, sandbox_flags, container_policy,
+                        devtools_frame_token, frame_policy,
                         frame_owner_properties);
 }
 
@@ -2236,8 +2236,7 @@
 
 void RenderFrameHostImpl::OnDidChangeFramePolicy(
     int32_t frame_routing_id,
-    blink::WebSandboxFlags flags,
-    const ParsedFeaturePolicyHeader& container_policy) {
+    const FramePolicy& frame_policy) {
   // Ensure that a frame can only update sandbox flags or feature policy for its
   // immediate children.  If this is not the case, the renderer is considered
   // malicious and is killed.
@@ -2247,8 +2246,8 @@
   if (!child)
     return;
 
-  child->SetPendingSandboxFlags(flags);
-  child->SetPendingContainerPolicy(container_policy);
+  child->SetPendingSandboxFlags(frame_policy.sandbox_flags);
+  child->SetPendingContainerPolicy(frame_policy.container_policy);
 
   // Notify the RenderFrame if it lives in a different process from its parent.
   // The frame's proxies in other processes also need to learn about the updated
@@ -2258,7 +2257,7 @@
   RenderFrameHost* child_rfh = child->current_frame_host();
   if (child_rfh->GetSiteInstance() != GetSiteInstance()) {
     child_rfh->Send(new FrameMsg_DidUpdateFramePolicy(child_rfh->GetRoutingID(),
-                                                      flags, container_policy));
+                                                      frame_policy));
   }
 }
 
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index ec9ec44..6c4c072 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -118,6 +118,7 @@
 struct ContextMenuParams;
 struct FileChooserParams;
 struct FrameOwnerProperties;
+struct FramePolicy;
 struct FileChooserParams;
 struct ResourceResponse;
 
@@ -276,8 +277,7 @@
                           const std::string& frame_name,
                           const std::string& frame_unique_name,
                           const base::UnguessableToken& devtools_frame_token,
-                          blink::WebSandboxFlags sandbox_flags,
-                          const ParsedFeaturePolicyHeader& container_policy,
+                          const FramePolicy& frame_policy,
                           const FrameOwnerProperties& frame_owner_properties);
 
   // Update this frame's last committed origin.
@@ -768,10 +768,8 @@
 
   void OnEnforceInsecureRequestPolicy(blink::WebInsecureRequestPolicy policy);
   void OnUpdateToUniqueOrigin(bool is_potentially_trustworthy_unique_origin);
-  void OnDidChangeFramePolicy(
-      int32_t frame_routing_id,
-      blink::WebSandboxFlags flags,
-      const ParsedFeaturePolicyHeader& container_policy);
+  void OnDidChangeFramePolicy(int32_t frame_routing_id,
+                              const FramePolicy& frame_policy);
   void OnDidChangeFrameOwnerProperties(int32_t frame_routing_id,
                                        const FrameOwnerProperties& properties);
   void OnUpdateTitle(const base::string16& title,
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 7e44458..d2f738e4 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -555,8 +555,8 @@
     if (pair.second->GetSiteInstance() != parent_site_instance) {
       pair.second->Send(new FrameMsg_DidUpdateFramePolicy(
           pair.second->GetRoutingID(),
-          frame_tree_node_->current_replication_state().sandbox_flags,
-          frame_tree_node_->current_replication_state().container_policy));
+          {frame_tree_node_->current_replication_state().sandbox_flags,
+           frame_tree_node_->current_replication_state().container_policy}));
     }
   }
 }
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc
index c6ea752..c33d2ca 100644
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -26,6 +26,7 @@
 #include "content/browser/webui/web_ui_controller_factory_registry.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
+#include "content/common/frame_policy.h"
 #include "content/common/input_messages.h"
 #include "content/common/site_isolation_policy.h"
 #include "content/common/view_messages.h"
@@ -57,7 +58,6 @@
 #include "net/base/load_flags.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebInsecureRequestPolicy.h"
-#include "third_party/WebKit/public/web/WebSandboxFlags.h"
 #include "ui/base/page_transition_types.h"
 
 namespace content {
@@ -1950,13 +1950,11 @@
   contents()->GetMainFrame()->OnCreateChildFrame(
       contents()->GetMainFrame()->GetProcess()->GetNextRoutingID(),
       blink::WebTreeScopeType::kDocument, "frame_name", "uniqueName1",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   contents()->GetMainFrame()->OnCreateChildFrame(
       contents()->GetMainFrame()->GetProcess()->GetNextRoutingID(),
       blink::WebTreeScopeType::kDocument, "frame_name", "uniqueName2",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   RenderFrameHostManager* root_manager =
       contents()->GetFrameTree()->root()->render_manager();
   RenderFrameHostManager* iframe1 =
@@ -2091,8 +2089,7 @@
   contents1->GetMainFrame()->OnCreateChildFrame(
       contents1->GetMainFrame()->GetProcess()->GetNextRoutingID(),
       blink::WebTreeScopeType::kDocument, "frame_name", "uniqueName1",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   RenderFrameHostManager* iframe =
       contents()->GetFrameTree()->root()->child_at(0)->render_manager();
   NavigationEntryImpl entry(NULL /* instance */, kUrl2,
@@ -2141,8 +2138,7 @@
   main_rfh->OnCreateChildFrame(
       main_rfh->GetProcess()->GetNextRoutingID(),
       blink::WebTreeScopeType::kDocument, std::string(), "uniqueName1",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   RenderFrameHostManager* subframe_rfhm =
       contents()->GetFrameTree()->root()->child_at(0)->render_manager();
 
@@ -2300,13 +2296,11 @@
   int process_id = root1->current_frame_host()->GetProcess()->GetID();
   tree1->AddFrame(root1, process_id, 12, blink::WebTreeScopeType::kDocument,
                   std::string(), "uniqueName0",
-                  base::UnguessableToken::Create(),
-                  blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
+                  base::UnguessableToken::Create(), FramePolicy(),
                   FrameOwnerProperties());
   tree1->AddFrame(root1, process_id, 13, blink::WebTreeScopeType::kDocument,
                   std::string(), "uniqueName1",
-                  base::UnguessableToken::Create(),
-                  blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
+                  base::UnguessableToken::Create(), FramePolicy(),
                   FrameOwnerProperties());
 
   std::unique_ptr<TestWebContents> tab2(
@@ -2317,13 +2311,11 @@
   process_id = root2->current_frame_host()->GetProcess()->GetID();
   tree2->AddFrame(root2, process_id, 22, blink::WebTreeScopeType::kDocument,
                   std::string(), "uniqueName2",
-                  base::UnguessableToken::Create(),
-                  blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
+                  base::UnguessableToken::Create(), FramePolicy(),
                   FrameOwnerProperties());
   tree2->AddFrame(root2, process_id, 23, blink::WebTreeScopeType::kDocument,
                   std::string(), "uniqueName3",
-                  base::UnguessableToken::Create(),
-                  blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
+                  base::UnguessableToken::Create(), FramePolicy(),
                   FrameOwnerProperties());
 
   std::unique_ptr<TestWebContents> tab3(
@@ -2339,8 +2331,7 @@
   process_id = root4->current_frame_host()->GetProcess()->GetID();
   tree4->AddFrame(root4, process_id, 42, blink::WebTreeScopeType::kDocument,
                   std::string(), "uniqueName4",
-                  base::UnguessableToken::Create(),
-                  blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
+                  base::UnguessableToken::Create(), FramePolicy(),
                   FrameOwnerProperties());
 
   root1->child_at(1)->SetOpener(root1->child_at(1));
@@ -2390,18 +2381,15 @@
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       blink::WebTreeScopeType::kDocument, "frame1", "uniqueName1",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       blink::WebTreeScopeType::kDocument, "frame2", "uniqueName2",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       blink::WebTreeScopeType::kDocument, "frame3", "uniqueName3",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
 
   FrameTreeNode* root = contents()->GetFrameTree()->root();
   RenderFrameHostManager* child1 = root->child_at(0)->render_manager();
@@ -2491,8 +2479,7 @@
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       blink::WebTreeScopeType::kDocument, "frame1", "uniqueName1",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
 
   FrameTreeNode* root = contents()->GetFrameTree()->root();
   RenderFrameHostManager* child = root->child_at(0)->render_manager();
@@ -3036,8 +3023,7 @@
   main_test_rfh()->OnCreateChildFrame(
       main_test_rfh()->GetProcess()->GetNextRoutingID(),
       blink::WebTreeScopeType::kDocument, "frame1", "uniqueName1",
-      base::UnguessableToken::Create(), blink::WebSandboxFlags::kNone,
-      ParsedFeaturePolicyHeader(), FrameOwnerProperties());
+      base::UnguessableToken::Create(), FramePolicy(), FrameOwnerProperties());
 
   FrameTreeNode* root = contents()->GetFrameTree()->root();
   RenderFrameHostManager* child = root->child_at(0)->render_manager();
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc
index a842664..9ee3ffc 100644
--- a/content/browser/frame_host/render_frame_message_filter.cc
+++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -21,6 +21,7 @@
 #include "content/common/content_constants_internal.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
+#include "content/common/frame_policy.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
@@ -66,8 +67,7 @@
                           const std::string& frame_name,
                           const std::string& frame_unique_name,
                           const base::UnguessableToken& devtools_frame_token,
-                          blink::WebSandboxFlags sandbox_flags,
-                          const ParsedFeaturePolicyHeader& container_policy,
+                          const FramePolicy& frame_policy,
                           const FrameOwnerProperties& frame_owner_properties,
                           int new_routing_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -78,8 +78,7 @@
   if (render_frame_host) {
     render_frame_host->OnCreateChildFrame(
         new_routing_id, scope, frame_name, frame_unique_name,
-        devtools_frame_token, sandbox_flags, container_policy,
-        frame_owner_properties);
+        devtools_frame_token, frame_policy, frame_owner_properties);
   }
 }
 
@@ -350,8 +349,8 @@
       base::BindOnce(&CreateChildFrameOnUI, render_process_id_,
                      params.parent_routing_id, params.scope, params.frame_name,
                      params.frame_unique_name, *devtools_frame_token,
-                     params.sandbox_flags, params.container_policy,
-                     params.frame_owner_properties, *new_routing_id));
+                     params.frame_policy, params.frame_owner_properties,
+                     *new_routing_id));
 }
 
 void RenderFrameMessageFilter::OnCookiesEnabled(int render_frame_id,
diff --git a/content/browser/indexed_db/leveldb/leveldb_database.h b/content/browser/indexed_db/leveldb/leveldb_database.h
index c27dea06..039cccc 100644
--- a/content/browser/indexed_db/leveldb/leveldb_database.h
+++ b/content/browser/indexed_db/leveldb/leveldb_database.h
@@ -136,7 +136,6 @@
   };
 
   // Despite the type name, this object uses LRU eviction.
-  size_t lru_max_size_ = 0;
   base::HashingMRUCache<LevelDBIterator*, DetachIteratorOnDestruct>
       iterator_lru_;
 
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 44207cf..6be9bcf 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -49,6 +49,7 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "cc/base/switches.h"
@@ -3909,6 +3910,10 @@
       resource_coordinator::mojom::PropertyType::kPID,
       base::GetProcId(GetHandle()));
 
+  GetProcessResourceCoordinator()->SetProperty(
+      resource_coordinator::mojom::PropertyType::kLaunchTime,
+      base::Time::Now().ToTimeT());
+
 #if BUILDFLAG(ENABLE_WEBRTC)
   if (WebRTCInternals::GetInstance()->IsAudioDebugRecordingsEnabled()) {
     EnableAudioDebugRecordings(
diff --git a/content/browser/renderer_host/render_process_host_unittest.cc b/content/browser/renderer_host/render_process_host_unittest.cc
index aaecf1cb..754c076 100644
--- a/content/browser/renderer_host/render_process_host_unittest.cc
+++ b/content/browser/renderer_host/render_process_host_unittest.cc
@@ -12,6 +12,8 @@
 #include "base/memory/ptr_util.h"
 #include "build/build_config.h"
 #include "content/common/frame_messages.h"
+#include "content/common/frame_owner_properties.h"
+#include "content/common/frame_policy.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/browser_side_navigation_policy.h"
@@ -24,7 +26,6 @@
 #include "content/test/test_render_frame_host.h"
 #include "content/test/test_render_view_host.h"
 #include "content/test/test_web_contents.h"
-#include "third_party/WebKit/public/web/WebSandboxFlags.h"
 
 namespace content {
 
@@ -131,8 +132,7 @@
   main_test_rfh()->OnCreateChildFrame(
       process()->GetNextRoutingID(), blink::WebTreeScopeType::kDocument,
       std::string(), unique_name, base::UnguessableToken::Create(),
-      blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
-      FrameOwnerProperties());
+      FramePolicy(), FrameOwnerProperties());
   TestRenderFrameHost* subframe = static_cast<TestRenderFrameHost*>(
       contents()->GetFrameTree()->root()->child_at(0)->current_frame_host());
   subframe = static_cast<TestRenderFrameHost*>(
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc
index 41f605f1..6ed5d98 100644
--- a/content/browser/service_manager/service_manager_context.cc
+++ b/content/browser/service_manager/service_manager_context.cc
@@ -269,6 +269,20 @@
         service_manager::Identity(mojom::kPackagedServicesServiceName,
                                   service_manager::mojom::kRootUserID),
         std::move(packaged_services_service), nullptr);
+    service_manager_->SetInstanceQuitCallback(
+        base::Bind(&OnInstanceQuitOnIOThread));
+  }
+
+  static void OnInstanceQuitOnIOThread(const service_manager::Identity& id) {
+    BrowserThread::GetTaskRunnerForThread(BrowserThread::UI)
+        ->PostTask(FROM_HERE, base::BindOnce(&OnInstanceQuit, id));
+  }
+
+  static void OnInstanceQuit(const service_manager::Identity& id) {
+    if (GetContentClient()->browser()->ShouldTerminateOnServiceQuit(id)) {
+      LOG(FATAL) << "Terminating because service '" << id.name()
+                 << "' quit unexpectedly.";
+    }
   }
 
   void ShutDownOnIOThread() {
diff --git a/content/browser/snapshot_browsertest.cc b/content/browser/snapshot_browsertest.cc
index 4525fe4..583c744 100644
--- a/content/browser/snapshot_browsertest.cc
+++ b/content/browser/snapshot_browsertest.cc
@@ -249,13 +249,7 @@
   }
 }
 
-// Seen to time out / fail on debug Mac; crbug.com/771119, crbug.com/774050.
-#if defined(NDEBUG) && !defined(OS_MACOSX)
-#define MAYBE_SyncMultiWindowTest SyncMultiWindowTest
-#else
-#define MAYBE_SyncMultiWindowTest DISABLED_SyncMultiWindowTest
-#endif
-IN_PROC_BROWSER_TEST_F(SnapshotBrowserTest, MAYBE_SyncMultiWindowTest) {
+IN_PROC_BROWSER_TEST_F(SnapshotBrowserTest, SyncMultiWindowTest) {
   SetupTestServer();
 
   for (int i = 0; i < 3; ++i) {
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 7297db4..f985ea2 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1631,12 +1631,7 @@
   render_manager->CreateOuterDelegateProxy(
       outer_contents_frame->GetSiteInstance(), outer_contents_frame_impl);
 
-  render_manager->SetRWHViewForInnerContents(
-      render_manager->GetRenderWidgetHostView());
-
-  static_cast<RenderWidgetHostViewChildFrame*>(
-      render_manager->GetRenderWidgetHostView())
-      ->RegisterFrameSinkId();
+  ReattachToOuterWebContentsFrame();
 
   if (outer_web_contents_impl->frame_tree_.GetFocusedFrame() ==
       outer_contents_frame_impl->frame_tree_node()) {
@@ -1644,12 +1639,6 @@
                     outer_contents_frame->GetSiteInstance());
   }
 
-  // Set up the the guest's AX tree to point back at the embedder's AX tree.
-  auto* parent_frame = outer_contents_frame->GetParent();
-  GetMainFrame()->set_browser_plugin_embedder_ax_tree_id(
-      parent_frame->GetAXTreeID());
-  GetMainFrame()->UpdateAXTreeData();
-
   // At this point, we should destroy the TextInputManager which will notify all
   // the RWHV in this WebContents. The RWHV in this WebContents should use the
   // TextInputManager owned by the outer WebContents.
@@ -1660,6 +1649,24 @@
   text_input_manager_.reset(nullptr);
 }
 
+void WebContentsImpl::ReattachToOuterWebContentsFrame() {
+  DCHECK(node_.outer_web_contents());
+  auto* render_manager = GetRenderManager();
+  auto* parent_frame =
+      node_.OuterContentsFrameTreeNode()->current_frame_host()->GetParent();
+  render_manager->SetRWHViewForInnerContents(
+      render_manager->GetRenderWidgetHostView());
+
+  static_cast<RenderWidgetHostViewChildFrame*>(
+      render_manager->GetRenderWidgetHostView())
+      ->RegisterFrameSinkId();
+
+  // Set up the the guest's AX tree to point back at the embedder's AX tree.
+  GetMainFrame()->set_browser_plugin_embedder_ax_tree_id(
+      parent_frame->GetAXTreeID());
+  GetMainFrame()->UpdateAXTreeData();
+}
+
 void WebContentsImpl::DidChangeVisibleSecurityState() {
   if (delegate_) {
     delegate_->VisibleSecurityStateChanged(this);
@@ -5533,6 +5540,9 @@
     return false;
   }
 
+  if (proxy_routing_id == MSG_ROUTING_NONE && node_.outer_web_contents())
+    ReattachToOuterWebContentsFrame();
+
   SetHistoryOffsetAndLengthForView(render_view_host,
                                    controller_.GetLastCommittedEntryIndex(),
                                    controller_.GetEntryCount());
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index ae7f760f..afd40fc8 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -1318,6 +1318,9 @@
   // is that of the main frame.
   void SetVisibilityForChildViews(bool visible);
 
+  // Reattaches this inner WebContents to its outer WebContents.
+  void ReattachToOuterWebContentsFrame();
+
   // Data for core operation ---------------------------------------------------
 
   // Delegate for notifying our owner about stuff. Not owned by us.
diff --git a/content/browser/webui/web_ui_controller_factory_registry.cc b/content/browser/webui/web_ui_controller_factory_registry.cc
index b151e32..708cf7a 100644
--- a/content/browser/webui/web_ui_controller_factory_registry.cc
+++ b/content/browser/webui/web_ui_controller_factory_registry.cc
@@ -14,15 +14,16 @@
 namespace content {
 
 base::LazyInstance<std::vector<WebUIControllerFactory*>>::DestructorAtExit
-    g_factories = LAZY_INSTANCE_INITIALIZER;
+    g_web_ui_controller_factories = LAZY_INSTANCE_INITIALIZER;
 
 void WebUIControllerFactory::RegisterFactory(WebUIControllerFactory* factory) {
-  g_factories.Pointer()->push_back(factory);
+  g_web_ui_controller_factories.Pointer()->push_back(factory);
 }
 
 void WebUIControllerFactory::UnregisterFactoryForTesting(
     WebUIControllerFactory* factory) {
-  std::vector<WebUIControllerFactory*>* factories = g_factories.Pointer();
+  std::vector<WebUIControllerFactory*>* factories =
+      g_web_ui_controller_factories.Pointer();
   for (size_t i = 0; i < factories->size(); ++i) {
     if ((*factories)[i] == factory) {
       factories->erase(factories->begin() + i);
@@ -38,7 +39,8 @@
 
 WebUIController* WebUIControllerFactoryRegistry::CreateWebUIControllerForURL(
     WebUI* web_ui, const GURL& url) const {
-  std::vector<WebUIControllerFactory*>* factories = g_factories.Pointer();
+  std::vector<WebUIControllerFactory*>* factories =
+      g_web_ui_controller_factories.Pointer();
   for (size_t i = 0; i < factories->size(); ++i) {
     WebUIController* controller = (*factories)[i]->CreateWebUIControllerForURL(
         web_ui, url);
@@ -50,7 +52,8 @@
 
 WebUI::TypeID WebUIControllerFactoryRegistry::GetWebUIType(
     BrowserContext* browser_context, const GURL& url) const {
-  std::vector<WebUIControllerFactory*>* factories = g_factories.Pointer();
+  std::vector<WebUIControllerFactory*>* factories =
+      g_web_ui_controller_factories.Pointer();
   for (size_t i = 0; i < factories->size(); ++i) {
     WebUI::TypeID type = (*factories)[i]->GetWebUIType(browser_context, url);
     if (type != WebUI::kNoWebUI)
@@ -61,7 +64,8 @@
 
 bool WebUIControllerFactoryRegistry::UseWebUIForURL(
     BrowserContext* browser_context, const GURL& url) const {
-  std::vector<WebUIControllerFactory*>* factories = g_factories.Pointer();
+  std::vector<WebUIControllerFactory*>* factories =
+      g_web_ui_controller_factories.Pointer();
   for (size_t i = 0; i < factories->size(); ++i) {
     if ((*factories)[i]->UseWebUIForURL(browser_context, url))
       return true;
@@ -71,7 +75,8 @@
 
 bool WebUIControllerFactoryRegistry::UseWebUIBindingsForURL(
     BrowserContext* browser_context, const GURL& url) const {
-  std::vector<WebUIControllerFactory*>* factories = g_factories.Pointer();
+  std::vector<WebUIControllerFactory*>* factories =
+      g_web_ui_controller_factories.Pointer();
   for (size_t i = 0; i < factories->size(); ++i) {
     if ((*factories)[i]->UseWebUIBindingsForURL(browser_context, url))
       return true;
diff --git a/content/browser/webui/web_ui_url_loader_factory.cc b/content/browser/webui/web_ui_url_loader_factory.cc
index 579df51..61bcfd0 100644
--- a/content/browser/webui/web_ui_url_loader_factory.cc
+++ b/content/browser/webui/web_ui_url_loader_factory.cc
@@ -39,7 +39,7 @@
 
 class WebUIURLLoaderFactory;
 base::LazyInstance<std::map<int, std::unique_ptr<WebUIURLLoaderFactory>>>::Leaky
-    g_factories = LAZY_INSTANCE_INITIALIZER;
+    g_web_ui_url_loader_factories = LAZY_INSTANCE_INITIALIZER;
 
 void CallOnError(mojom::URLLoaderClientPtrInfo client_info, int error_code) {
   mojom::URLLoaderClientPtr client;
@@ -273,7 +273,7 @@
 
   // FrameTreeNode::Observer implementation:
   void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override {
-    g_factories.Get().erase(frame_tree_node_id_);
+    g_web_ui_url_loader_factories.Get().erase(frame_tree_node_id_);
   }
 
  private:
@@ -288,9 +288,10 @@
 
 mojom::URLLoaderFactoryPtr CreateWebUIURLLoader(FrameTreeNode* node) {
   int ftn_id = node->frame_tree_node_id();
-  if (g_factories.Get()[ftn_id].get() == nullptr)
-    g_factories.Get()[ftn_id] = base::MakeUnique<WebUIURLLoaderFactory>(node);
-  return g_factories.Get()[ftn_id]->CreateBinding();
+  if (g_web_ui_url_loader_factories.Get()[ftn_id].get() == nullptr)
+    g_web_ui_url_loader_factories.Get()[ftn_id] =
+        base::MakeUnique<WebUIURLLoaderFactory>(node);
+  return g_web_ui_url_loader_factories.Get()[ftn_id]->CreateBinding();
 }
 
 }  // namespace content
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index d607aae..9fefd53 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -157,6 +157,8 @@
     "frame_messages_forward.h",
     "frame_owner_properties.cc",
     "frame_owner_properties.h",
+    "frame_policy.cc",
+    "frame_policy.h",
     "frame_replication_state.cc",
     "frame_replication_state.h",
     "gin_java_bridge_messages.h",
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 18c4b420..4763d71 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -27,6 +27,7 @@
 #include "content/common/features.h"
 #include "content/common/frame_message_enums.h"
 #include "content/common/frame_owner_properties.h"
+#include "content/common/frame_policy.h"
 #include "content/common/frame_replication_state.h"
 #include "content/common/navigation_gesture.h"
 #include "content/common/navigation_params.h"
@@ -197,6 +198,11 @@
   IPC_STRUCT_TRAITS_MEMBER(required_csp)
 IPC_STRUCT_TRAITS_END()
 
+IPC_STRUCT_TRAITS_BEGIN(content::FramePolicy)
+  IPC_STRUCT_TRAITS_MEMBER(sandbox_flags)
+  IPC_STRUCT_TRAITS_MEMBER(container_policy)
+IPC_STRUCT_TRAITS_END()
+
 IPC_STRUCT_TRAITS_BEGIN(content::PageImportanceSignals)
   IPC_STRUCT_TRAITS_MEMBER(had_form_interaction)
 IPC_STRUCT_TRAITS_END()
@@ -560,8 +566,7 @@
   IPC_STRUCT_MEMBER(blink::WebTreeScopeType, scope)
   IPC_STRUCT_MEMBER(std::string, frame_name)
   IPC_STRUCT_MEMBER(std::string, frame_unique_name)
-  IPC_STRUCT_MEMBER(blink::WebSandboxFlags, sandbox_flags)
-  IPC_STRUCT_MEMBER(content::ParsedFeaturePolicyHeader, container_policy)
+  IPC_STRUCT_MEMBER(content::FramePolicy, frame_policy)
   IPC_STRUCT_MEMBER(content::FrameOwnerProperties, frame_owner_properties)
 IPC_STRUCT_END()
 
@@ -848,9 +853,7 @@
 
 // Notifies the frame that its parent has changed the frame's sandbox flags or
 // container policy.
-IPC_MESSAGE_ROUTED2(FrameMsg_DidUpdateFramePolicy,
-                    blink::WebSandboxFlags,
-                    content::ParsedFeaturePolicyHeader)
+IPC_MESSAGE_ROUTED1(FrameMsg_DidUpdateFramePolicy, content::FramePolicy)
 
 // Update a proxy's window.name property.  Used when the frame's name is
 // changed in another process.
@@ -1224,11 +1227,10 @@
 
 // Notifies the browser that sandbox flags or container policy have changed for
 // a subframe of this frame.
-IPC_MESSAGE_ROUTED3(
+IPC_MESSAGE_ROUTED2(
     FrameHostMsg_DidChangeFramePolicy,
     int32_t /* subframe_routing_id */,
-    blink::WebSandboxFlags /* updated_flags */,
-    content::ParsedFeaturePolicyHeader /* updated container policy */)
+    content::FramePolicy /* updated sandbox flags and container policy */)
 
 // Notifies the browser that frame owner properties have changed for a subframe
 // of this frame.
diff --git a/content/common/frame_policy.cc b/content/common/frame_policy.cc
new file mode 100644
index 0000000..ddf0c22
--- /dev/null
+++ b/content/common/frame_policy.cc
@@ -0,0 +1,22 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/frame_policy.h"
+
+namespace content {
+
+FramePolicy::FramePolicy()
+    : sandbox_flags(blink::WebSandboxFlags::kNone), container_policy({}) {}
+
+FramePolicy::FramePolicy(blink::WebSandboxFlags sandbox_flags,
+                         const ParsedFeaturePolicyHeader& container_policy)
+    : sandbox_flags(sandbox_flags), container_policy(container_policy) {}
+
+FramePolicy::FramePolicy(const FramePolicy& lhs)
+    : sandbox_flags(lhs.sandbox_flags),
+      container_policy(lhs.container_policy) {}
+
+FramePolicy::~FramePolicy() {}
+
+}  // namespace content
diff --git a/content/common/frame_policy.h b/content/common/frame_policy.h
new file mode 100644
index 0000000..b227b45
--- /dev/null
+++ b/content/common/frame_policy.h
@@ -0,0 +1,39 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_FRAME_POLICY_H_
+#define CONTENT_COMMON_FRAME_POLICY_H_
+
+#include "content/common/content_export.h"
+#include "content/common/feature_policy/feature_policy.h"
+#include "third_party/WebKit/public/web/WebSandboxFlags.h"
+
+namespace content {
+
+// This structure contains the attributes of a frame which determine what
+// features are available during the lifetime of the framed document. Currently,
+// this includes the sandbox flags and the feature policy container policy. Used
+// in the frame tree to track sandbox and feature policy in the browser process,
+// and tranferred over IPC during frame replication when site isolation is
+// enabled.
+//
+// Unlike the attributes in FrameOwnerProperties, these attributes are never
+// updated after the framed document has been loaded, so two versions of this
+// structure are kept in the frame tree for each frame -- the effective policy
+// and the pending policy, which will take effect when the frame is next
+// navigated.
+struct CONTENT_EXPORT FramePolicy {
+  FramePolicy();
+  FramePolicy(blink::WebSandboxFlags sandbox_flags,
+              const ParsedFeaturePolicyHeader& container_policy);
+  FramePolicy(const FramePolicy& lhs);
+  ~FramePolicy();
+
+  blink::WebSandboxFlags sandbox_flags;
+  ParsedFeaturePolicyHeader container_policy;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_FRAME_POLICY_H_
diff --git a/content/common/input/input_event_struct_traits.cc b/content/common/input/input_event_struct_traits.cc
index f5af727..a6ab8dc 100644
--- a/content/common/input/input_event_struct_traits.cc
+++ b/content/common/input/input_event_struct_traits.cc
@@ -119,6 +119,9 @@
     gesture_event->y = gesture_data->widget_position.y();
     gesture_event->global_x = gesture_data->screen_position.x();
     gesture_event->global_y = gesture_data->screen_position.y();
+    gesture_event->is_source_touch_event_set_non_blocking =
+        gesture_data->is_source_touch_event_set_non_blocking;
+    gesture_event->primary_pointer_type = gesture_data->primary_pointer_type;
     gesture_event->source_device = gesture_data->source_device;
     gesture_event->unique_touch_event_id = gesture_data->unique_touch_event_id;
     gesture_event->resending_plugin_id = gesture_data->resending_plugin_id;
@@ -424,6 +427,9 @@
   gesture_data->screen_position = gesture_event->PositionInScreen();
   gesture_data->widget_position = gesture_event->PositionInWidget();
   gesture_data->source_device = gesture_event->source_device;
+  gesture_data->is_source_touch_event_set_non_blocking =
+      gesture_event->is_source_touch_event_set_non_blocking;
+  gesture_data->primary_pointer_type = gesture_event->primary_pointer_type;
   gesture_data->unique_touch_event_id = gesture_event->unique_touch_event_id;
   gesture_data->resending_plugin_id = gesture_event->resending_plugin_id;
   switch (gesture_event->GetType()) {
diff --git a/content/common/input/input_handler.mojom b/content/common/input/input_handler.mojom
index b7a8296..45f7aaee 100644
--- a/content/common/input/input_handler.mojom
+++ b/content/common/input/input_handler.mojom
@@ -107,6 +107,8 @@
   gfx.mojom.PointF screen_position;
   gfx.mojom.PointF widget_position;
   GestureDevice source_device;
+  bool is_source_touch_event_set_non_blocking;
+  PointerType primary_pointer_type;
   int32 unique_touch_event_id;
   int32 resending_plugin_id;
   gfx.mojom.Size? contact_size;
diff --git a/content/public/app/content_main_delegate.cc b/content/public/app/content_main_delegate.cc
index ee57df8..dc7c5034 100644
--- a/content/public/app/content_main_delegate.cc
+++ b/content/public/app/content_main_delegate.cc
@@ -5,7 +5,6 @@
 #include "content/public/app/content_main_delegate.h"
 
 #include "build/build_config.h"
-
 #include "content/public/gpu/content_gpu_client.h"
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/public/utility/content_utility_client.h"
@@ -61,12 +60,6 @@
     const service_manager::Identity& identity,
     base::CommandLine* command_line) {}
 
-bool ContentMainDelegate::ShouldTerminateServiceManagerOnInstanceQuit(
-    const service_manager::Identity& identity,
-    int* exit_code) {
-  return false;
-}
-
 void ContentMainDelegate::OnServiceManagerInitialized(
     const base::Closure& quit_closure,
     service_manager::BackgroundServiceManager* service_manager) {}
diff --git a/content/public/app/content_main_delegate.h b/content/public/app/content_main_delegate.h
index b31cf6c..177cc9f6 100644
--- a/content/public/app/content_main_delegate.h
+++ b/content/public/app/content_main_delegate.h
@@ -9,12 +9,19 @@
 #include <string>
 #include <vector>
 
+#include "base/callback_forward.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
-#include "services/service_manager/background/background_service_manager.h"
 #include "services/service_manager/embedder/process_type.h"
-#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/cpp/service.h"
+
+namespace base {
+class CommandLine;
+}
+
+namespace service_manager {
+class BackgroundServiceManager;
+class Identity;
+}  // namespace service_manager
 
 namespace content {
 
@@ -95,13 +102,6 @@
       const service_manager::Identity& identity,
       base::CommandLine* command_line);
 
-  // Indicates if the Service Manager should be terminated in response to a
-  // specific service instance quitting. If this returns |true|, the value in
-  // |*exit_code| will be returned from the Service Manager's process on exit.
-  virtual bool ShouldTerminateServiceManagerOnInstanceQuit(
-      const service_manager::Identity& identity,
-      int* exit_code);
-
   // Allows the embedder to perform arbitrary initialization within the Service
   // Manager process immediately before the Service Manager runs its main loop.
   //
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index d7c965f..6e8d39b 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -73,7 +73,7 @@
         "content_plugin": [ "browser" ],
         "content_renderer": [ "browser" ],
         "content_utility": [ "browser" ],
-        "data_decoder": [ "image_decoder" ],
+        "data_decoder": [ "image_decoder", "json_parser" ],
         "device": [
           "device:battery_monitor",
           "device:generic_sensor",
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 15a13c1..824f0c4 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -373,11 +373,6 @@
   return nullptr;
 }
 
-gpu::GpuChannelEstablishFactory*
-ContentBrowserClient::GetGpuChannelEstablishFactory() {
-  return nullptr;
-}
-
 bool ContentBrowserClient::AllowPepperSocketAPI(
     BrowserContext* browser_context,
     const GURL& url,
@@ -489,6 +484,11 @@
   return nullptr;
 }
 
+bool ContentBrowserClient::ShouldTerminateOnServiceQuit(
+    const service_manager::Identity& id) {
+  return false;
+}
+
 std::vector<ContentBrowserClient::ServiceManifestInfo>
 ContentBrowserClient::GetExtraServiceManifests() {
   return std::vector<ContentBrowserClient::ServiceManifestInfo>();
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 842557d5..9ef3e42e 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -59,10 +59,6 @@
 class ImageSkia;
 }
 
-namespace gpu {
-class GpuChannelEstablishFactory;
-}
-
 namespace media {
 class AudioLogFactory;
 class AudioManager;
@@ -612,9 +608,6 @@
   virtual BrowserPpapiHost* GetExternalBrowserPpapiHost(
       int plugin_child_id);
 
-  // Gets the factory to use to establish a connection to the GPU process.
-  virtual gpu::GpuChannelEstablishFactory* GetGpuChannelEstablishFactory();
-
   // Returns true if the socket operation specified by |params| is allowed from
   // the given |browser_context| and |url|. If |params| is nullptr, this method
   // checks the basic "socket" permission, which is for those operations that
@@ -742,6 +735,11 @@
   // to use for the service's host process when launched.
   virtual void RegisterOutOfProcessServices(OutOfProcessServiceMap* services) {}
 
+  // Allows the embedder to terminate the browser if a specific service instance
+  // quits or crashes.
+  virtual bool ShouldTerminateOnServiceQuit(
+      const service_manager::Identity& id);
+
   // Allow the embedder to provide a dictionary loaded from a JSON file
   // resembling a service manifest whose capabilities section will be merged
   // with content's own for |name|. Additional entries will be appended to their
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index a6bbc2e..973b08f 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -62,6 +62,7 @@
 #include "content/common/edit_command.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
+#include "content/common/frame_policy.h"
 #include "content/common/frame_replication_state.h"
 #include "content/common/input_messages.h"
 #include "content/common/navigation_params.h"
@@ -2310,11 +2311,10 @@
   frame_->SetOpener(opener);
 }
 
-void RenderFrameImpl::OnDidUpdateFramePolicy(
-    blink::WebSandboxFlags flags,
-    const ParsedFeaturePolicyHeader& container_policy) {
-  frame_->SetFrameOwnerPolicy(flags,
-                              FeaturePolicyHeaderToWeb(container_policy));
+void RenderFrameImpl::OnDidUpdateFramePolicy(const FramePolicy& frame_policy) {
+  frame_->SetFrameOwnerPolicy(
+      frame_policy.sandbox_flags,
+      FeaturePolicyHeaderToWeb(frame_policy.container_policy));
 }
 
 void RenderFrameImpl::OnSetFrameOwnerProperties(
@@ -3179,8 +3179,8 @@
   // browsing context name, only unique name generation.
   params.frame_unique_name = unique_name_helper_.GenerateNameForNewChildFrame(
       params.frame_name.empty() ? fallback_name.Utf8() : params.frame_name);
-  params.sandbox_flags = sandbox_flags;
-  params.container_policy = FeaturePolicyHeaderFromWeb(container_policy);
+  params.frame_policy = {sandbox_flags,
+                         FeaturePolicyHeaderFromWeb(container_policy)};
   params.frame_owner_properties =
       ConvertWebFrameOwnerPropertiesToFrameOwnerProperties(
           frame_owner_properties);
@@ -3319,8 +3319,8 @@
     blink::WebSandboxFlags flags,
     const blink::WebParsedFeaturePolicy& container_policy) {
   Send(new FrameHostMsg_DidChangeFramePolicy(
-      routing_id_, RenderFrame::GetRoutingIdForWebFrame(child_frame), flags,
-      FeaturePolicyHeaderFromWeb(container_policy)));
+      routing_id_, RenderFrame::GetRoutingIdForWebFrame(child_frame),
+      {flags, FeaturePolicyHeaderFromWeb(container_policy)}));
 }
 
 void RenderFrameImpl::DidSetFeaturePolicyHeader(
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 203f8d2..8d80083 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -161,6 +161,7 @@
 struct FileChooserFileInfo;
 struct FileChooserParams;
 struct FrameOwnerProperties;
+struct FramePolicy;
 struct FrameReplicationState;
 struct NavigationParams;
 struct RequestNavigationParams;
@@ -984,9 +985,7 @@
   void OnSnapshotAccessibilityTree(int callback_id);
   void OnExtractSmartClipData(uint32_t callback_id, const gfx::Rect& rect);
   void OnUpdateOpener(int opener_routing_id);
-  void OnDidUpdateFramePolicy(
-      blink::WebSandboxFlags flags,
-      const ParsedFeaturePolicyHeader& container_policy);
+  void OnDidUpdateFramePolicy(const FramePolicy& frame_policy);
   void OnSetFrameOwnerProperties(
       const FrameOwnerProperties& frame_owner_properties);
   void OnAdvanceFocus(blink::WebFocusType type, int32_t source_routing_id);
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index 01f3be91..4749b0fd 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -16,6 +16,7 @@
 #include "content/common/content_switches_internal.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
+#include "content/common/frame_policy.h"
 #include "content/common/frame_replication_state.h"
 #include "content/common/input_messages.h"
 #include "content/common/page_messages.h"
@@ -294,12 +295,11 @@
 // properly if this proxy ever parents a local frame.  The proxy's FrameOwner
 // flags are also updated here with the caveat that the FrameOwner won't learn
 // about updates to its flags until they take effect.
-void RenderFrameProxy::OnDidUpdateFramePolicy(
-    blink::WebSandboxFlags flags,
-    const ParsedFeaturePolicyHeader& container_policy) {
-  web_frame_->SetReplicatedSandboxFlags(flags);
-  web_frame_->SetFrameOwnerPolicy(flags,
-                                  FeaturePolicyHeaderToWeb(container_policy));
+void RenderFrameProxy::OnDidUpdateFramePolicy(const FramePolicy& frame_policy) {
+  web_frame_->SetReplicatedSandboxFlags(frame_policy.sandbox_flags);
+  web_frame_->SetFrameOwnerPolicy(
+      frame_policy.sandbox_flags,
+      FeaturePolicyHeaderToWeb(frame_policy.container_policy));
 }
 
 void RenderFrameProxy::MaybeUpdateCompositingHelper() {
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index 96095b413..9200a89 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -35,6 +35,7 @@
 class RenderWidget;
 struct ContentSecurityPolicyHeader;
 struct FrameOwnerProperties;
+struct FramePolicy;
 struct FrameReplicationState;
 
 #if defined(USE_AURA)
@@ -185,9 +186,7 @@
   void OnUpdateOpener(int opener_routing_id);
   void OnViewChanged(const viz::FrameSinkId& frame_sink_id);
   void OnDidStopLoading();
-  void OnDidUpdateFramePolicy(
-      blink::WebSandboxFlags flags,
-      const ParsedFeaturePolicyHeader& container_policy);
+  void OnDidUpdateFramePolicy(const FramePolicy& frame_policy);
   void OnDispatchLoad();
   void OnCollapse(bool collapsed);
   void OnDidUpdateName(const std::string& name, const std::string& unique_name);
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index 6b30112d5..e3e6748 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -15,6 +15,7 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
+#include "content/common/frame_policy.h"
 #include "content/public/browser/navigation_throttle.h"
 #include "content/public/browser/stream_handle.h"
 #include "content/public/common/browser_side_navigation_policy.h"
@@ -29,7 +30,6 @@
 #include "third_party/WebKit/public/platform/WebMixedContentContextType.h"
 #include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
 #include "third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom.h"
-#include "third_party/WebKit/public/web/WebSandboxFlags.h"
 #include "third_party/WebKit/public/web/WebTreeScopeType.h"
 #include "ui/base/page_transition_types.h"
 
@@ -98,8 +98,7 @@
   OnCreateChildFrame(GetProcess()->GetNextRoutingID(),
                      blink::WebTreeScopeType::kDocument, frame_name,
                      frame_unique_name, base::UnguessableToken::Create(),
-                     blink::WebSandboxFlags::kNone, ParsedFeaturePolicyHeader(),
-                     FrameOwnerProperties());
+                     FramePolicy(), FrameOwnerProperties());
   return static_cast<TestRenderFrameHost*>(
       child_creation_observer_.last_created_frame());
 }
diff --git a/device/bluetooth/bluetooth_init_win.h b/device/bluetooth/bluetooth_init_win.h
index 3d75b2a5..ee58658 100644
--- a/device/bluetooth/bluetooth_init_win.h
+++ b/device/bluetooth/bluetooth_init_win.h
@@ -5,12 +5,15 @@
 #ifndef DEVICE_BLUETOOTH_BLUETOOTH_INIT_WIN_H_
 #define DEVICE_BLUETOOTH_BLUETOOTH_INIT_WIN_H_
 
-// windows.h needs to be included before BluetoothAPIs.h.
+// windows.h needs to be included before bluetoothapis.h.
 #include <windows.h>
 
-#include <BluetoothAPIs.h>
+#include <bluetoothapis.h>
 #include <delayimp.h>
+
+// ws2def.h needs to be included before ws2bth.h.
 #include <ws2def.h>
+
 #include <ws2bth.h>
 
 #include "device/bluetooth/bluetooth_export.h"
diff --git a/docs/win_cross.md b/docs/win_cross.md
new file mode 100644
index 0000000..678d4d4
--- /dev/null
+++ b/docs/win_cross.md
@@ -0,0 +1,55 @@
+# Cross-compiling Chrome/win
+
+It's possible to build parts of the codebase on a Linux (and soon, Mac) host
+while targeting Windows.  This document describes how to set that up, and
+current restrictions.
+
+What does *not* work:
+
+* goma. Sorry. ([internal bug](b/64390790))
+* targets depending on crashpad ([bug](https://crbug.com/762167))
+* targets using .rc files ([bug](https://crbug.com/774193))
+* linking on Mac ([bug](https://crbug.com/774209)), should change soon
+
+This disqualifies most interesting targets for now, but a few smaller ones
+(`base_unittests`, ...) do work.  Over time, more things should work.
+
+## .gclient setup
+
+1. Tell gclient that you need Windows build dependencies by adding
+   `target_os = ['win']` to the end of your `.gclient`.  (If you already
+   have a `target_os` line in there, just add `'win'` to the list.)
+1. `gclient sync`, follow instructions on screen.
+
+If you're at Google, this will automatically download the Windows SDK for you.
+If you are not at Google, you'll have to figure out how to get the SDK, and
+you'll need to put a JSON file describing the SDK layout in a certain location.
+
+# GN setup
+
+Add `target_os = "win"` to your args.gn.  Then just build, e.g.
+
+    ninja -C out/gnwin base_unittests.exe
+
+# Running tests on swarming
+
+You can run the Windows binaries you built on swarming, like so:
+
+    tools/mb/mb.py isolate //out/gnwin base_unittests
+    tools/swarming_client/isolate.py archive \
+        -I https://isolateserver.appspot.com \
+        -i out/gnwin/base_unittests.isolate \
+        -s out/gnwin/base_unittests.isolated
+    tools/swarming_client/swarming.py trigger \
+        -S https://chromium-swarm.appspot.com \
+        -I https://isolateserver.appspot.com \
+        -d os Windows -d pool Chrome -s <hash printed by previous command>
+
+Most tests that build should pass.  However, the cross build uses
+the lld linker, and a couple of tests fail when using lld. You can look at
+https://build.chromium.org/p/chromium.clang/builders/CrWinClangLLD%20tester
+to get an idea of which tests fail with lld.
+
+TODO(thakis): It'd be nice if there was a script for doing this. Maybe make
+tools/fuchsa/run-swarmed.py work for win cross builds too, or create
+`run_base_unittests` script targets during the build (like Android).
diff --git a/extensions/README.md b/extensions/README.md
index db752871..d04c5a9 100644
--- a/extensions/README.md
+++ b/extensions/README.md
@@ -13,3 +13,5 @@
 * [Features System](/chrome/common/extensions/api/_features.md)
 
 * [Bindings System](/extensions/renderer/bindings.md)
+
+* [Extension events](/extensions/common/events.md)
diff --git a/extensions/browser/extension_system.h b/extensions/browser/extension_system.h
index fe42fc2..36804a78 100644
--- a/extensions/browser/extension_system.h
+++ b/extensions/browser/extension_system.h
@@ -46,6 +46,9 @@
 // their own right.
 class ExtensionSystem : public KeyedService {
  public:
+  // A callback to be executed when InstallUpdate finishes.
+  using InstallUpdateCallback = base::OnceCallback<void(bool success)>;
+
   ExtensionSystem();
   ~ExtensionSystem() override;
 
@@ -125,11 +128,11 @@
       const Extension* extension) = 0;
 
   // Install an updated version of |extension_id| with the version given in
-  // temp_dir. Ownership of |temp_dir| in the filesystem is transferred and
-  // implementors of this function are responsible for cleaning it up on
-  // errors, etc.
+  // |unpacked_dir|. Ownership of |unpacked_dir| in the filesystem is
+  // transferred and implementors of this function are responsible for cleaning
+  // it up on errors, etc.
   virtual void InstallUpdate(const std::string& extension_id,
-                             const base::FilePath& temp_dir) = 0;
+                             const base::FilePath& unpacked_dir) = 0;
 };
 
 }  // namespace extensions
diff --git a/extensions/docs/events.md b/extensions/docs/events.md
new file mode 100644
index 0000000..96a9940
--- /dev/null
+++ b/extensions/docs/events.md
@@ -0,0 +1,124 @@
+# Extension events
+
+The Chrome extensions system has its own implementation of events (typically
+exposed as `chrome.<api>.onFoo`, e.g. `chrome.tabs.onUpdated`). This doc
+provides some notes about its implementation, specifically how event listeners
+are registered and how they are dispatched.
+
+## High level overview of extension event dispatching
+
+An event listener registered in the renderer process is sent to the browser
+process (via IPC). The browser process stores the listener information in
+`EventListenerMap`. Events are dispatched from the browser process to the
+renderer process via IPC. If browser process requires to persist any listener,
+it does so by storing the listener information in the prefs.
+
+## Relevant concepts
+
+* __Listener contexts__:
+Typically denotes the page/script where the listener is registered from, e.g.
+an extension's background page or an extension's service worker script.
+
+* __Lazy contexts__:
+Contexts that are not persistent and typically shut down when inactive, e.g. an
+event page's background script or an extension service worker script. Non-lazy
+contexts are often called "persistent" contexts.
+
+* __Persistent listeners / Non-lazy listeners__:
+Listeners from contexts that are not lazy.
+
+* __Lazy listeners__:
+Listeners from lazy context.
+See the scenario description (_Case 1_ and _Case 2_) below for quick explanation
+of how registration of a listener from a lazy context can result in two (a lazy
+and a non-lazy) listeners. An event can be dispatched to these listeners while
+the corresponding lazy context is not running.
+
+* __Filtered events__:
+A listener can specify additional matching criterea that we call event filters.
+Some events support filters. IPCs (along with most but not all of the browser/
+or renderer/ code) use `DictionaryValue` to represent an event filter.
+
+
+## Event listener registration
+
+Event listeners are registered in JavaScript in the renderer process. The
+event bindings code handles this registration and the browser process is made
+aware of it via IPC.
+
+In particular, a message filter (`ExtensionMessageFilter`) receives event
+registration IPCs and it passes them to `EventRouter` to be stored in
+`EventListenerMap`. If the listener is required to be persisted (for lazy
+events), they are also recorded in `ExtensionPrefs`.
+
+Note that when the renderer context is shut down, it removes the listener. The
+exception is lazy event listener, which is not removed.
+
+
+### Additional notes about lazy listeners
+
+When a lazy listener is added for an event, a regular (non-lazy) listener
+(call it `L1`) is added for it and in addition to that, a lazy variant of the
+listener (call it `L2`) is also added. `L2` helps browser process remember that
+the listener should be persisted and it should have lazy behavior.
+
+## Event dispatching
+
+`EventRouter` is responsible for dispatching events from the browser process.
+When an event is required to be dispatched, `EventRouter` fetches EventListeners
+from `EventListenerMap` and dispatches them to appropriate contexts (renderer
+or service worker scripts)
+
+### Additional notes about lazy event dispatching
+
+Recall that a lazy listener is like a regular listeners, except that it is
+registered from a lazy context. A lazy context can be shut down. If an
+interesting event ocurrs while a lazy context (with a listener to that event)
+is no longer running, then the lazy context is woken up to dispatch the event.
+
+The following (simplified) steps describe how dispatch is performed.
+
+#### Case 1: Event dispatched while context (lazy or non-lazy) is running
+
+* Because `EventListenerMap` will contain an entry for the listener (`L1`), it
+will dispatch the event in normal fashion: by sending an IPC to the renderer
+through `ExtensionMessageFilter`.
+
+#### Case 2: Event dispatched while (lazy) context is not running
+
+* If the context is not running, then `EventListenerMap` will not have any entry
+for `L1` (because context shutdown will remove `L1`), but it will have an entry
+for the lazy version of it, `L2`. Note that `L2` will exist even if the browser
+process is restarted, `EventRouter::OnExtensionLoaded` will have loaded these
+lazy events through `EventListenerMap::Load(Un)FilteredLazyListeners`.
+
+* Realize that `L2` is lazy, so wake up its lazy context. Waking up an event
+page context entails spinning up its background page, while waking up a service
+worker context means starting the service worker.
+
+* The lazy context will register `L1` and `L2` again, because the same code that
+added the initial listeners will run again. This is an important step that
+isn't intuitive. Note that `L2`, since it already exists in the browser process,
+is not re-added.
+
+* Dispatch `L1` (same as _Case 1_ above).
+
+## Notes about extension service worker (ESW) events
+
+* ESW events behave similar to event page events, i.e. lazy events.
+
+* ESW events are registered from worker threads, instead of main renderer
+threads.
+
+* Similarly, event dispatch target is worker thread instead of main renderer
+thread. Therefore, at dispatch time, browser process knows about the worker
+thread
+id in a RenderProcessHost. This is why worker event listener IPCs have
+`worker_thread_id` param in them.
+
+## TODOs
+
+* Explain filters a bit more, where filter matching is performed and how much of
+it lives in the renderer/ process.
+
+* Describe what "manual" removal of event listeners means.
diff --git a/google_apis/google_api_keys.cc b/google_apis/google_api_keys.cc
index 1ba1d296..2e8437ed 100644
--- a/google_apis/google_api_keys.cc
+++ b/google_apis/google_api_keys.cc
@@ -360,8 +360,4 @@
 #endif
 }
 
-bool IsClientIdOverridden() {
-  return GetOAuth2ClientID(CLIENT_MAIN) != GOOGLE_CLIENT_ID_MAIN;
-}
-
 }  // namespace google_apis
diff --git a/google_apis/google_api_keys.h b/google_apis/google_api_keys.h
index b99112e..20d896e 100644
--- a/google_apis/google_api_keys.h
+++ b/google_apis/google_api_keys.h
@@ -120,9 +120,6 @@
 // Google Chrome.
 bool IsGoogleChromeAPIKeyUsed();
 
-// Returns true if client id is overridden.
-bool IsClientIdOverridden();
-
 }  // namespace google_apis
 
 #endif  // GOOGLE_APIS_GOOGLE_API_KEYS_H_
diff --git a/ios/chrome/browser/context_menu/context_menu_egtest.mm b/ios/chrome/browser/context_menu/context_menu_egtest.mm
index aa43043..3648802d 100644
--- a/ios/chrome/browser/context_menu/context_menu_egtest.mm
+++ b/ios/chrome/browser/context_menu/context_menu_egtest.mm
@@ -194,83 +194,4 @@
   [ChromeEarlGrey waitForMainTabCount:2];
 }
 
-// Tests "Open in New Tab" on context menu  on a link that requires scrolling
-// on the page to verify that context menu can be properly triggered in the
-// current screen view.
-- (void)testContextMenuOpenInNewTabFromTallPage {
-// TODO(crbug.com/755888): Reenable this test.
-  if (!IsIPadIdiom()) {
-    EARL_GREY_TEST_DISABLED(@"Failing constently on iPhone devices.");
-  }
-
-  // Set up test simple http server.
-  std::map<GURL, std::string> responses;
-  GURL initialURL =
-      web::test::HttpServer::MakeUrl("http://scenarioContextMenuOpenInNewTab");
-  GURL destinationURL = web::test::HttpServer::MakeUrl("http://destination");
-
-  // The initial page contains a link to the destination page that is below a
-  // really tall div so that scrolling is required.
-  responses[initialURL] =
-      "<div style='height:4000px'></div>"
-      "<a style='margin-left:50px' href='" +
-      destinationURL.spec() + "' id='link'>link</a>";
-  responses[destinationURL] = kDestinationHtml;
-
-  web::test::SetUpSimpleHttpServer(responses);
-  [ChromeEarlGrey loadURL:initialURL];
-  [ChromeEarlGrey waitForMainTabCount:1];
-
-  // Scroll down on the web view to make the link visible.
-  // grey_swipeFastInDirecton will quickly scroll towards the bottom, and then
-  // grey_scrollToContentEdge guarantees the content edge is reached. Two
-  // methods are used because the first one is much faster, but doesn't
-  // guarantee the link becomes visible.
-  // TODO(crbug.com/702272): Try to replace this with one EarlGrey method call.
-  [[EarlGrey
-      selectElementWithMatcher:WebViewScrollView(
-                                   chrome_test_util::GetCurrentWebState())]
-      performAction:grey_swipeFastInDirection(kGREYDirectionUp)];
-  [[EarlGrey
-      selectElementWithMatcher:WebViewScrollView(
-                                   chrome_test_util::GetCurrentWebState())]
-      performAction:grey_scrollToContentEdge(kGREYContentEdgeBottom)];
-
-  [ChromeEarlGrey waitForWebViewContainingText:kDestinationLinkID];
-
-  LongPressElementAndTapOnButton(kDestinationLinkID, OpenLinkInNewTabButton());
-
-  // Earl Grey cannot preperly synchronize some animations, so adding a
-  // WaitUntilCondition to wait for the new tab opening animation to finish
-  // and the scroll view to become interactable.
-  ConditionBlock condition = ^{
-    NSError* error = nil;
-    [[EarlGrey
-        selectElementWithMatcher:WebViewScrollView(
-                                     chrome_test_util::GetCurrentWebState())]
-        assertWithMatcher:grey_interactable()
-                    error:&error];
-    return !error;
-  };
-  GREYAssert(testing::WaitUntilConditionOrTimeout(
-                 testing::kWaitForUIElementTimeout, condition),
-             @"Web view did not become interactable");
-
-  // Make the toolbar visible by scrolling up on the web view to select the
-  // newly opened tab.
-  [[EarlGrey
-      selectElementWithMatcher:WebViewScrollView(
-                                   chrome_test_util::GetCurrentWebState())]
-      performAction:grey_swipeFastInDirection(kGREYDirectionDown)];
-  [ChromeEarlGreyUI waitForToolbarVisible:YES];
-
-  SelectTabAtIndexInCurrentMode(1U);
-
-  // Verify url and tab count.
-  [[EarlGrey selectElementWithMatcher:chrome_test_util::OmniboxText(
-                                          destinationURL.GetContent())]
-      assertWithMatcher:grey_notNil()];
-  [ChromeEarlGrey waitForMainTabCount:2];
-}
-
 @end
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder.h b/ios/chrome/browser/metrics/tab_usage_recorder.h
index b00b5f7..8bef4bd 100644
--- a/ios/chrome/browser/metrics/tab_usage_recorder.h
+++ b/ios/chrome/browser/metrics/tab_usage_recorder.h
@@ -124,38 +124,41 @@
   ~TabUsageRecorder() override;
 
   // Called during startup when the tab model is created, or shortly after a
-  // post-crash launch if the tabs are restored.  |tabs| is an array containing
-  // the tabs being restored in the current tab model. |active_tab| is the tab
-  // currently in the foreground.
-  void InitialRestoredTabs(web::WebState* active_tab,
-                           const std::vector<web::WebState*>& tabs);
+  // post-crash launch if the tabs are restored.  |web_states| is an array
+  // containing/ the tabs being restored in the current tab model.
+  // |active_web_state| is the tab currently in the foreground.
+  void InitialRestoredTabs(web::WebState* active_web_state,
+                           const std::vector<web::WebState*>& web_states);
 
   // Called when a tab switch is made.  Determines what value to record, and
   // when to reset the page load counter.
-  void RecordTabSwitched(web::WebState* old_tab, web::WebState* new_tab);
+  void RecordTabSwitched(web::WebState* old_web_state,
+                         web::WebState* new_web_state);
 
   // Called when the tab model which the user is primarily interacting with has
-  // changed. The |active_tab| is the current tab of the tab model. If the user
-  // began interacting with |active_tab|, |primary| should be true. If the user
-  // stopped interacting with |active_tab|, |primary| should be false.
-  void RecordPrimaryTabModelChange(bool primary, web::WebState* active_tab);
+  // changed. The |active_web_state| is the current tab of the tab model. If the
+  // user began interacting with |active_web_state|, |primary_tab_model| should
+  // be true. If the user stopped interacting with |active_web_state|,
+  // |primary_tab_model| should be false.
+  void RecordPrimaryTabModelChange(bool primary_tab_model,
+                                   web::WebState* active_web_state);
 
   // Called when a page load begins, to keep track of how many page loads
   // happen before an evicted tab is seen.
-  void RecordPageLoadStart(web::WebState* tab);
+  void RecordPageLoadStart(web::WebState* web_state);
 
   // Called when a page load finishes, to track the load time for evicted tabs.
-  void RecordPageLoadDone(web::WebState* tab, bool success);
+  void RecordPageLoadDone(web::WebState* web_state, bool success);
 
   // Called when there is a user-initiated reload.
-  void RecordReload(web::WebState* tab);
+  void RecordReload(web::WebState* web_state);
 
   // Called when WKWebView's renderer is terminated. |tab| contains the tab
   // whose renderer was terminated, |tab_visible| indicates whether or not
   // the tab was visible when the renderer terminated and |application_active|
   // indicates whether the application was in the foreground or background.
-  void RendererTerminated(web::WebState* tab,
-                          bool tab_visible,
+  void RendererTerminated(web::WebState* web_state,
+                          bool web_state_visible,
                           bool application_active);
 
   // Called when the app has been backgrounded.
@@ -167,7 +170,7 @@
   // Resets the page load count.
   void ResetPageLoads();
 
-  // Size of |evicted_tabs_|.  Used for testing.
+  // Size of |evicted_web_states_|.  Used for testing.
   int EvictedTabsMapSize();
 
   // Resets all tracked data.  Used for testing.
@@ -187,20 +190,20 @@
   void ResetEvictedTab();
 
   // Whether or not a tab can be disregarded by the metrics.
-  bool ShouldIgnoreTab(web::WebState* tab);
+  bool ShouldIgnoreWebState(web::WebState* web_state);
 
   // Whether or not the tab has already been evicted.
-  bool TabAlreadyEvicted(web::WebState* tab);
+  bool WebStateAlreadyEvicted(web::WebState* web_state);
 
   // Returns the state of the given tab.  Call only once per tab, as it removes
-  // the tab from |evicted_tabs_|.
-  TabStateWhenSelected ExtractTabState(web::WebState* tab);
+  // the tab from |evicted_web_states_|.
+  TabStateWhenSelected ExtractWebStateState(web::WebState* web_state);
 
   // Records various time metrics when a restore of an evicted tab begins.
   void RecordRestoreStartTime();
 
   // Returns the number of WebState that are still alive (in-memory).
-  int GetLiveTabsCount() const;
+  int GetLiveWebStatesCount() const;
 
   // Called after a WebState is added to the WebStateList; will create the
   // observer used to track the WebState's events.
@@ -242,26 +245,26 @@
 
   // Keep track of the current tab, but only if it has been evicted.
   // This is kept as a pointer value only - it should never be dereferenced.
-  web::WebState* evicted_tab_ = nullptr;
+  web::WebState* evicted_web_state_ = nullptr;
 
-  // State of |evicted_tab_| at the time it became the current tab.
-  TabStateWhenSelected evicted_tab_state_ = IN_MEMORY;
+  // State of |evicted_web_state_| at the time it became the current tab.
+  TabStateWhenSelected evicted_web_state_state_ = IN_MEMORY;
 
   // Keep track of the tab last selected when this tab model was switched
   // away from to another mode (e.g. to incognito).
   // Kept as a pointer value only - it should never be dereferenced.
-  web::WebState* mode_switch_tab_ = nullptr;
+  web::WebState* mode_switch_web_state_ = nullptr;
 
   // Keep track of a tab that was created to be immediately selected.  It should
   // not contribute to the "StatusWhenSwitchedBackToForeground" metric.
-  web::WebState* tab_created_selected_ = nullptr;
+  web::WebState* web_state_created_selected_ = nullptr;
 
   // Keep track of when the evicted tab starts to reload, so that the total
   // time it takes to reload can be recorded.
-  base::TimeTicks evicted_tab_reload_start_time_;
+  base::TimeTicks evicted_web_state_reload_start_time_;
 
   // Keep track of the tabs that have a known eviction cause.
-  std::map<web::WebState*, TabStateWhenSelected> evicted_tabs_;
+  std::map<web::WebState*, TabStateWhenSelected> evicted_web_states_;
 
   // Maps WebStates to the WebStateObserver used to track its events.
   std::map<web::WebState*, std::unique_ptr<WebStateObserver>>
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder.mm b/ios/chrome/browser/metrics/tab_usage_recorder.mm
index 2351c64..db25611 100644
--- a/ios/chrome/browser/metrics/tab_usage_recorder.mm
+++ b/ios/chrome/browser/metrics/tab_usage_recorder.mm
@@ -167,8 +167,8 @@
 }
 
 void TabUsageRecorder::InitialRestoredTabs(
-    web::WebState* active_tab,
-    const std::vector<web::WebState*>& tabs) {
+    web::WebState* active_web_state,
+    const std::vector<web::WebState*>& web_states) {
 #if !defined(NDEBUG)
   // Debugging check to ensure this is called at most once per run.
   // Specifically, this function is called in either of two cases:
@@ -188,97 +188,99 @@
 
   // Do not set eviction reason on active tab since it will be reloaded without
   // being processed as a switch to the foreground tab.
-  for (web::WebState* web_state : tabs) {
-    if (web_state != active_tab) {
-      evicted_tabs_[web_state] = EVICTED_DUE_TO_COLD_START;
+  for (web::WebState* web_state : web_states) {
+    if (web_state != active_web_state) {
+      evicted_web_states_[web_state] = EVICTED_DUE_TO_COLD_START;
     }
   }
 }
 
-void TabUsageRecorder::RecordTabSwitched(web::WebState* old_tab,
-                                         web::WebState* new_tab) {
+void TabUsageRecorder::RecordTabSwitched(web::WebState* old_web_state,
+                                         web::WebState* new_web_state) {
   // If a tab was created to be selected, and is selected shortly thereafter,
   // it should not add its state to the "kSelectedTabHistogramName" metric.
-  // |tab_created_selected_| is reset at the first tab switch seen after it was
-  // created, regardless of whether or not it was the tab selected.
-  const bool was_just_created = new_tab == tab_created_selected_;
-  tab_created_selected_ = nullptr;
+  // |web_state_created_selected_| is reset at the first tab switch seen after
+  // it was created, regardless of whether or not it was the tab selected.
+  const bool was_just_created = new_web_state == web_state_created_selected_;
+  web_state_created_selected_ = nullptr;
 
   // Disregard reselecting the same tab, but only if the mode has not changed
   // since the last time this tab was selected.  I.e. going to incognito and
   // back to normal mode is an event we want to track, but simply going into
   // stack view and back out, without changing modes, isn't.
-  if (new_tab == old_tab && new_tab != mode_switch_tab_)
+  if (new_web_state == old_web_state && new_web_state != mode_switch_web_state_)
     return;
-  mode_switch_tab_ = nullptr;
+  mode_switch_web_state_ = nullptr;
 
   // Disregard opening a new tab with no previous tab. Or closing the last tab.
-  if (!old_tab || !new_tab)
+  if (!old_web_state || !new_web_state)
     return;
 
-  // Before knowledge of the previous tab, |old_tab|, is lost, see if it is a
-  // previously-evicted tab still reloading.  If it is, record that the
+  // Before knowledge of the previous tab, |old_web_state|, is lost, see if it
+  // is a previously-evicted tab still reloading.  If it is, record that the
   // user did not wait for the evicted tab to finish reloading.
-  if (old_tab == evicted_tab_ && old_tab != new_tab &&
-      evicted_tab_reload_start_time_ != base::TimeTicks()) {
+  if (old_web_state == evicted_web_state_ && old_web_state != new_web_state &&
+      evicted_web_state_reload_start_time_ != base::TimeTicks()) {
     UMA_HISTOGRAM_ENUMERATION(kDidUserWaitForEvictedTabReload,
                               USER_DID_NOT_WAIT, USER_BEHAVIOR_COUNT);
   }
   ResetEvictedTab();
 
-  if (ShouldIgnoreTab(new_tab) || was_just_created)
+  if (ShouldIgnoreWebState(new_web_state) || was_just_created)
     return;
 
   // Should never happen.  Keeping the check to ensure that the prerender logic
   // is never overlooked, should behavior at the tab_model level change.
   DCHECK(!prerender_service_ ||
-         !prerender_service_->IsWebStatePrerendered(new_tab));
+         !prerender_service_->IsWebStatePrerendered(new_web_state));
 
-  TabStateWhenSelected tab_state = ExtractTabState(new_tab);
-  if (tab_state != IN_MEMORY) {
+  TabStateWhenSelected web_state_state = ExtractWebStateState(new_web_state);
+  if (web_state_state != IN_MEMORY) {
     // Keep track of the current 'evicted' tab.
-    evicted_tab_ = new_tab;
-    evicted_tab_state_ = tab_state;
+    evicted_web_state_ = new_web_state;
+    evicted_web_state_state_ = web_state_state;
     UMA_HISTOGRAM_COUNTS(kPageLoadsBeforeEvictedTabSelected, page_loads_);
     ResetPageLoads();
   }
 
-  UMA_HISTOGRAM_ENUMERATION(kSelectedTabHistogramName, tab_state,
+  UMA_HISTOGRAM_ENUMERATION(kSelectedTabHistogramName, web_state_state,
                             TAB_STATE_COUNT);
 }
 
-void TabUsageRecorder::RecordPrimaryTabModelChange(bool primary_tab_model,
-                                                   web::WebState* active_tab) {
+void TabUsageRecorder::RecordPrimaryTabModelChange(
+    bool primary_tab_model,
+    web::WebState* active_web_state) {
   if (primary_tab_model) {
     // User just came back to this tab model, so record a tab selection even
     // though the current tab was reselected.
-    if (mode_switch_tab_ == active_tab)
-      RecordTabSwitched(active_tab, active_tab);
+    if (mode_switch_web_state_ == active_web_state)
+      RecordTabSwitched(active_web_state, active_web_state);
   } else {
     // Keep track of the selected tab when this tab model is moved to
     // background. This way when the tab model is moved to the foreground, and
     // the current tab reselected, it is handled as a tab selection rather than
     // a no-op.
-    mode_switch_tab_ = active_tab;
+    mode_switch_web_state_ = active_web_state;
   }
 }
 
-void TabUsageRecorder::RecordPageLoadStart(web::WebState* tab) {
-  if (!ShouldIgnoreTab(tab)) {
+void TabUsageRecorder::RecordPageLoadStart(web::WebState* web_state) {
+  if (!ShouldIgnoreWebState(web_state)) {
     page_loads_++;
-    if (tab->IsEvicted()) {
+    if (web_state->IsEvicted()) {
       // On the iPad, there is no notification that a tab is being re-selected
       // after changing modes.  This catches the case where the pre-incognito
       // selected tab is selected again when leaving incognito mode.
-      if (mode_switch_tab_ == tab)
-        RecordTabSwitched(tab, tab);
-      if (evicted_tab_ == tab)
+      if (mode_switch_web_state_ == web_state)
+        RecordTabSwitched(web_state, web_state);
+      if (evicted_web_state_ == web_state)
         RecordRestoreStartTime();
     }
   } else {
     // If there is a currently-evicted tab reloading, make sure it is recorded
     // that the user did not wait for it to load.
-    if (evicted_tab_ && evicted_tab_reload_start_time_ != base::TimeTicks()) {
+    if (evicted_web_state_ &&
+        evicted_web_state_reload_start_time_ != base::TimeTicks()) {
       UMA_HISTOGRAM_ENUMERATION(kDidUserWaitForEvictedTabReload,
                                 USER_DID_NOT_WAIT, USER_BEHAVIOR_COUNT);
     }
@@ -286,14 +288,15 @@
   }
 }
 
-void TabUsageRecorder::RecordPageLoadDone(web::WebState* tab, bool success) {
-  if (!tab)
+void TabUsageRecorder::RecordPageLoadDone(web::WebState* web_state,
+                                          bool success) {
+  if (!web_state)
     return;
-  if (tab == evicted_tab_) {
+  if (web_state == evicted_web_state_) {
     if (success) {
       LOCAL_HISTOGRAM_TIMES(
           kEvictedTabReloadTime,
-          base::TimeTicks::Now() - evicted_tab_reload_start_time_);
+          base::TimeTicks::Now() - evicted_web_state_reload_start_time_);
     }
     UMA_HISTOGRAM_ENUMERATION(kEvictedTabReloadSuccessRate,
                               success ? LOAD_SUCCESS : LOAD_FAILURE,
@@ -305,29 +308,30 @@
   }
 }
 
-void TabUsageRecorder::RecordReload(web::WebState* tab) {
-  if (!ShouldIgnoreTab(tab)) {
+void TabUsageRecorder::RecordReload(web::WebState* web_state) {
+  if (!ShouldIgnoreWebState(web_state)) {
     page_loads_++;
   }
 }
 
-void TabUsageRecorder::RendererTerminated(web::WebState* terminated_tab,
-                                          bool tab_visible,
+void TabUsageRecorder::RendererTerminated(web::WebState* terminated_web_state,
+                                          bool web_state_visible,
                                           bool application_active) {
   // Log the tab state for the termination.
-  const RendererTerminationTabState tab_state =
-      application_active ? (tab_visible ? FOREGROUND_TAB_FOREGROUND_APP
-                                        : BACKGROUND_TAB_FOREGROUND_APP)
-                         : (tab_visible ? FOREGROUND_TAB_BACKGROUND_APP
-                                        : BACKGROUND_TAB_BACKGROUND_APP);
+  const RendererTerminationTabState web_state_state =
+      application_active ? (web_state_visible ? FOREGROUND_TAB_FOREGROUND_APP
+                                              : BACKGROUND_TAB_FOREGROUND_APP)
+                         : (web_state_visible ? FOREGROUND_TAB_BACKGROUND_APP
+                                              : BACKGROUND_TAB_BACKGROUND_APP);
 
   UMA_HISTOGRAM_ENUMERATION(kRendererTerminationStateHistogram,
-                            static_cast<int>(tab_state),
+                            static_cast<int>(web_state_state),
                             static_cast<int>(TERMINATION_TAB_STATE_COUNT));
 
-  if (!tab_visible) {
-    DCHECK(!TabAlreadyEvicted(terminated_tab));
-    evicted_tabs_[terminated_tab] = EVICTED_DUE_TO_RENDERER_TERMINATION;
+  if (!web_state_visible) {
+    DCHECK(!WebStateAlreadyEvicted(terminated_web_state));
+    evicted_web_states_[terminated_web_state] =
+        EVICTED_DUE_TO_RENDERER_TERMINATION;
   }
   base::TimeTicks now = base::TimeTicks::Now();
   termination_timestamps_.push_back(now);
@@ -341,9 +345,10 @@
                         saw_memory_warning);
 
   // Log number of live tabs after the renderer termination. This count does not
-  // include |terminated_tab|.
-  int live_tabs_count = GetLiveTabsCount();
-  UMA_HISTOGRAM_COUNTS_100(kRendererTerminationAliveRenderers, live_tabs_count);
+  // include |terminated_web_state|.
+  int live_web_states_count = GetLiveWebStatesCount();
+  UMA_HISTOGRAM_COUNTS_100(kRendererTerminationAliveRenderers,
+                           live_web_states_count);
 
   // Clear |termination_timestamps_| of timestamps older than
   // |kSecondsBeforeRendererTermination| ago.
@@ -356,17 +361,18 @@
 
   // Log number of recently alive tabs, where recently alive is defined to mean
   // alive within the past |kSecondsBeforeRendererTermination|.
-  NSUInteger recently_live_tabs_count =
-      live_tabs_count + termination_timestamps_.size();
+  NSUInteger recently_live_web_states_count =
+      live_web_states_count + termination_timestamps_.size();
   UMA_HISTOGRAM_COUNTS_100(kRendererTerminationRecentlyAliveRenderers,
-                           recently_live_tabs_count);
+                           recently_live_web_states_count);
 }
 
 void TabUsageRecorder::AppDidEnterBackground() {
   base::TimeTicks time_now = base::TimeTicks::Now();
   LOCAL_HISTOGRAM_TIMES(kTimeAfterLastRestore, time_now - restore_start_time_);
 
-  if (evicted_tab_ && evicted_tab_reload_start_time_ != base::TimeTicks()) {
+  if (evicted_web_state_ &&
+      evicted_web_state_reload_start_time_ != base::TimeTicks()) {
     UMA_HISTOGRAM_ENUMERATION(kDidUserWaitForEvictedTabReload, USER_LEFT_CHROME,
                               USER_BEHAVIOR_COUNT);
     ResetEvictedTab();
@@ -382,52 +388,52 @@
 }
 
 int TabUsageRecorder::EvictedTabsMapSize() {
-  return evicted_tabs_.size();
+  return evicted_web_states_.size();
 }
 
 void TabUsageRecorder::ResetAll() {
   ResetEvictedTab();
   ResetPageLoads();
-  evicted_tabs_.clear();
+  evicted_web_states_.clear();
 }
 
 void TabUsageRecorder::ResetEvictedTab() {
-  evicted_tab_ = nullptr;
-  evicted_tab_state_ = IN_MEMORY;
-  evicted_tab_reload_start_time_ = base::TimeTicks();
+  evicted_web_state_ = nullptr;
+  evicted_web_state_state_ = IN_MEMORY;
+  evicted_web_state_reload_start_time_ = base::TimeTicks();
 }
 
-bool TabUsageRecorder::ShouldIgnoreTab(web::WebState* tab) {
+bool TabUsageRecorder::ShouldIgnoreWebState(web::WebState* web_state) {
   // Do not count chrome:// urls to avoid data noise.  For example, if they were
   // counted, every new tab created would add noise to the page load count.
   web::NavigationItem* pending_item =
-      tab->GetNavigationManager()->GetPendingItem();
+      web_state->GetNavigationManager()->GetPendingItem();
   if (pending_item)
     return pending_item->GetURL().SchemeIs(kChromeUIScheme);
 
   web::NavigationItem* last_committed_item =
-      tab->GetNavigationManager()->GetLastCommittedItem();
+      web_state->GetNavigationManager()->GetLastCommittedItem();
   if (last_committed_item)
     return last_committed_item->GetVirtualURL().SchemeIs(kChromeUIScheme);
 
   return false;
 }
 
-bool TabUsageRecorder::TabAlreadyEvicted(web::WebState* tab) {
-  auto iter = evicted_tabs_.find(tab);
-  return iter != evicted_tabs_.end();
+bool TabUsageRecorder::WebStateAlreadyEvicted(web::WebState* web_state) {
+  auto iter = evicted_web_states_.find(web_state);
+  return iter != evicted_web_states_.end();
 }
 
-TabUsageRecorder::TabStateWhenSelected TabUsageRecorder::ExtractTabState(
-    web::WebState* tab) {
-  if (!tab->IsEvicted())
+TabUsageRecorder::TabStateWhenSelected TabUsageRecorder::ExtractWebStateState(
+    web::WebState* web_state) {
+  if (!web_state->IsEvicted())
     return IN_MEMORY;
 
-  auto iter = evicted_tabs_.find(tab);
-  if (iter != evicted_tabs_.end()) {
-    TabStateWhenSelected tab_state = iter->second;
-    evicted_tabs_.erase(iter);
-    return tab_state;
+  auto iter = evicted_web_states_.find(web_state);
+  if (iter != evicted_web_states_.end()) {
+    TabStateWhenSelected web_state_state = iter->second;
+    evicted_web_states_.erase(iter);
+    return web_state_state;
   }
 
   return EVICTED;
@@ -438,10 +444,10 @@
   // Record the time delta since the last eviction reload was seen.
   LOCAL_HISTOGRAM_TIMES(kTimeBetweenRestores, time_now - restore_start_time_);
   restore_start_time_ = time_now;
-  evicted_tab_reload_start_time_ = time_now;
+  evicted_web_state_reload_start_time_ = time_now;
 }
 
-int TabUsageRecorder::GetLiveTabsCount() const {
+int TabUsageRecorder::GetLiveWebStatesCount() const {
   int count = 0;
   for (int index = 0; index < web_state_list_->count(); ++index) {
     if (!web_state_list_->GetWebStateAt(index)->IsEvicted())
@@ -458,18 +464,18 @@
 }
 
 void TabUsageRecorder::OnWebStateDestroyed(web::WebState* web_state) {
-  if (web_state == tab_created_selected_)
-    tab_created_selected_ = nullptr;
+  if (web_state == web_state_created_selected_)
+    web_state_created_selected_ = nullptr;
 
-  if (web_state == evicted_tab_)
-    evicted_tab_ = nullptr;
+  if (web_state == evicted_web_state_)
+    evicted_web_state_ = nullptr;
 
-  if (web_state == mode_switch_tab_)
-    mode_switch_tab_ = nullptr;
+  if (web_state == mode_switch_web_state_)
+    mode_switch_web_state_ = nullptr;
 
-  auto evicted_tabs_iter = evicted_tabs_.find(web_state);
-  if (evicted_tabs_iter != evicted_tabs_.end())
-    evicted_tabs_.erase(evicted_tabs_iter);
+  auto evicted_web_states_iter = evicted_web_states_.find(web_state);
+  if (evicted_web_states_iter != evicted_web_states_.end())
+    evicted_web_states_.erase(evicted_web_states_iter);
 
   auto web_state_observers_iter = web_state_observers_.find(web_state);
   if (web_state_observers_iter != web_state_observers_.end())
@@ -481,7 +487,7 @@
                                           int index,
                                           bool activating) {
   if (activating)
-    tab_created_selected_ = web_state;
+    web_state_created_selected_ = web_state;
 
   OnWebStateInserted(web_state);
 }
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index 73bd6d0..d9262d9 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -178,9 +178,6 @@
 
   OpenInController* _openInController;
 
-  // Whether or not this tab is currently being displayed.
-  BOOL _visible;
-
   // Holds entries that need to be added to the history DB.  Prerender tabs do
   // not write navigation data to the history DB.  Instead, they cache history
   // data in this vector and add it to the DB when the prerender status is
@@ -1306,8 +1303,9 @@
 }
 
 - (void)renderProcessGoneForWebState:(web::WebState*)webState {
+  DCHECK(webState == _webStateImpl);
   UIApplicationState state = [UIApplication sharedApplication].applicationState;
-  if (_visible && state == UIApplicationStateActive) {
+  if (webState->IsVisible() && state == UIApplicationStateActive) {
     [_fullScreenController disableFullScreen];
   }
   [self.dialogDelegate cancelDialogForTab:self];
@@ -1389,14 +1387,12 @@
 }
 
 - (void)wasShown {
-  _visible = YES;
   [self updateFullscreenWithToolbarVisible:YES];
   if (self.webState)
     self.webState->WasShown();
 }
 
 - (void)wasHidden {
-  _visible = NO;
   [self updateFullscreenWithToolbarVisible:YES];
   if (self.webState)
     self.webState->WasHidden();
diff --git a/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.mm b/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.mm
index b275058..8d3772d 100644
--- a/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.mm
+++ b/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.mm
@@ -184,8 +184,7 @@
 // call. The cached value is reset when the webview proxy is set.
 @property(nonatomic, readonly) CGFloat initialHeaderInset;
 // Initial height of the header view.
-// This property is set from the delegate headerHeight and cached on first
-// call. The cached value is reset when the webview proxy is set.
+// This property is set everytime the user starts pulling.
 @property(nonatomic, readonly) CGFloat initialHeaderHeight;
 // Redefined to be read-write.
 @property(nonatomic, assign, readwrite) OverscrollState overscrollState;
@@ -348,6 +347,7 @@
       // Set the contentInset to remove the bounce that would fight with drag.
       [self setScrollViewContentInset:insets];
       [self scrollView].scrollIndicatorInsets = insets;
+      _initialHeaderHeight = [[self delegate] overscrollHeaderHeight];
       self.overscrollState = OverscrollState::STARTED_PULLING;
     }
     [self updateWithVerticalOffset:-contentOffsetFromExpandedHeader];
@@ -511,7 +511,6 @@
              controller:(CRWWebController*)webController {
   DCHECK([webViewProxy scrollViewProxy]);
   _initialHeaderInset = 0;
-  _initialHeaderHeight = 0;
   _webViewProxy = webViewProxy;
   [_webViewScrollViewProxy removeObserver:self];
   _webViewScrollViewProxy = [webViewProxy scrollViewProxy];
@@ -819,13 +818,6 @@
   return _initialHeaderInset;
 }
 
-- (CGFloat)initialHeaderHeight {
-  if (_initialHeaderHeight == 0) {
-    _initialHeaderHeight = [[self delegate] overscrollHeaderHeight];
-  }
-  return _initialHeaderHeight;
-}
-
 #pragma mark - Bounce dynamic
 
 - (void)startBounceWithInitialVelocity:(CGPoint)velocity {
diff --git a/ios/chrome/browser/ui/webui/web_ui_egtest.mm b/ios/chrome/browser/ui/webui/web_ui_egtest.mm
index 9363400..98068a4 100644
--- a/ios/chrome/browser/ui/webui/web_ui_egtest.mm
+++ b/ios/chrome/browser/ui/webui/web_ui_egtest.mm
@@ -108,9 +108,9 @@
   [ChromeEarlGrey waitForWebViewContainingText:pageTitle];
 }
 
-// Tests that clicking on a link for a native page from chrome://chrome-urls
-// navigates to that page.
-- (void)testChromeURLNavigateToNativePage {
+// Tests that clicking on a chrome://terms link from chrome://chrome-urls
+// navigates to terms page.
+- (void)testChromeURLNavigateToTerms {
   LoadWebUIUrl(kChromeUIChromeURLsHost);
 
   // Tap on chrome://terms link on the page.
diff --git a/ios/third_party/ochamcrest/BUILD.gn b/ios/third_party/ochamcrest/BUILD.gn
index 815a85d..7b99321e 100644
--- a/ios/third_party/ochamcrest/BUILD.gn
+++ b/ios/third_party/ochamcrest/BUILD.gn
@@ -29,6 +29,8 @@
     "src/Source/Core/Helpers/HCInvocationMatcher.m",
     "src/Source/Core/Helpers/HCRequireNonNilObject.h",
     "src/Source/Core/Helpers/HCRequireNonNilObject.m",
+    "src/Source/Core/Helpers/HCRunloopRunner.h",
+    "src/Source/Core/Helpers/HCRunloopRunner.m",
     "src/Source/Core/Helpers/HCWrapInMatcher.h",
     "src/Source/Core/Helpers/HCWrapInMatcher.m",
     "src/Source/Core/Helpers/NSInvocation+OCHamcrest.h",
@@ -147,10 +149,10 @@
     "src/Source/Library/Object/HCIsTypeOf.m",
     "src/Source/Library/Object/HCThrowsException.h",
     "src/Source/Library/Object/HCThrowsException.m",
+    "src/Source/Library/Text/HCIsEqualCompressingWhiteSpace.h",
+    "src/Source/Library/Text/HCIsEqualCompressingWhiteSpace.m",
     "src/Source/Library/Text/HCIsEqualIgnoringCase.h",
     "src/Source/Library/Text/HCIsEqualIgnoringCase.m",
-    "src/Source/Library/Text/HCIsEqualIgnoringWhiteSpace.h",
-    "src/Source/Library/Text/HCIsEqualIgnoringWhiteSpace.m",
     "src/Source/Library/Text/HCStringContains.h",
     "src/Source/Library/Text/HCStringContains.m",
     "src/Source/Library/Text/HCStringContainsInOrder.h",
@@ -175,10 +177,31 @@
     "src/Source/Core/Helpers/HCCollect.h",
     "src/Source/Core/Helpers/HCInvocationMatcher.h",
     "src/Source/Core/Helpers/HCRequireNonNilObject.h",
+    "src/Source/Core/Helpers/HCRunloopRunner.h",
     "src/Source/Core/Helpers/HCWrapInMatcher.h",
+    "src/Source/Core/Helpers/NSInvocation+OCHamcrest.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCBoolReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCCharReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCDoubleReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCFloatReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCIntReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCLongLongReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCLongReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCObjectReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCReturnTypeHandlerChain.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCReturnValueGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCShortReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedCharReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedIntReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedLongLongReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedLongReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedShortReturnGetter.h",
+    "src/Source/Core/Helpers/TestFailureReporters/HCGenericTestFailureReporter.h",
+    "src/Source/Core/Helpers/TestFailureReporters/HCSenTestFailureReporter.h",
     "src/Source/Core/Helpers/TestFailureReporters/HCTestFailure.h",
     "src/Source/Core/Helpers/TestFailureReporters/HCTestFailureReporter.h",
     "src/Source/Core/Helpers/TestFailureReporters/HCTestFailureReporterChain.h",
+    "src/Source/Core/Helpers/TestFailureReporters/HCXCTestFailureReporter.h",
     "src/Source/Library/Collection/HCEvery.h",
     "src/Source/Library/Collection/HCHasCount.h",
     "src/Source/Library/Collection/HCIsCollectionContaining.h",
@@ -214,8 +237,8 @@
     "src/Source/Library/Object/HCIsSame.h",
     "src/Source/Library/Object/HCIsTypeOf.h",
     "src/Source/Library/Object/HCThrowsException.h",
+    "src/Source/Library/Text/HCIsEqualCompressingWhiteSpace.h",
     "src/Source/Library/Text/HCIsEqualIgnoringCase.h",
-    "src/Source/Library/Text/HCIsEqualIgnoringWhiteSpace.h",
     "src/Source/Library/Text/HCStringContains.h",
     "src/Source/Library/Text/HCStringContainsInOrder.h",
     "src/Source/Library/Text/HCStringEndsWith.h",
diff --git a/ipc/BUILD.gn b/ipc/BUILD.gn
index a6390702..3d020c5 100644
--- a/ipc/BUILD.gn
+++ b/ipc/BUILD.gn
@@ -22,7 +22,6 @@
 
 component("ipc") {
   sources = [
-    "export_template.h",
     "ipc_channel.cc",
     "ipc_channel.h",
     "ipc_channel_common.cc",
diff --git a/ipc/ipc_message_macros.h b/ipc/ipc_message_macros.h
index ccb7ce4a..2cab6fb 100644
--- a/ipc/ipc_message_macros.h
+++ b/ipc/ipc_message_macros.h
@@ -201,7 +201,7 @@
 
 #include <tuple>
 
-#include "ipc/export_template.h"
+#include "base/export_template.h"
 #include "ipc/ipc_message_templates.h"
 #include "ipc/ipc_message_utils.h"
 #include "ipc/param_traits_macros.h"
diff --git a/media/filters/blocking_url_protocol.cc b/media/filters/blocking_url_protocol.cc
index 08be12e..c21a7c98 100644
--- a/media/filters/blocking_url_protocol.cc
+++ b/media/filters/blocking_url_protocol.cc
@@ -8,7 +8,7 @@
 
 #include "base/bind.h"
 #include "base/macros.h"
-#include "base/threading/scoped_blocking_call.h"
+#include "base/threading/thread_restrictions.h"
 #include "media/base/data_source.h"
 #include "media/ffmpeg/ffmpeg_common.h"
 
@@ -63,8 +63,7 @@
   base::WaitableEvent* events[] = { &aborted_, &read_complete_ };
   size_t index;
   {
-    base::ScopedBlockingCall scoped_blocking_call(
-        base::BlockingType::MAY_BLOCK);
+    base::ScopedAllowBaseSyncPrimitives allow_base_sync_primitives;
     index = base::WaitableEvent::WaitMany(events, arraysize(events));
   }
 
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index 4510a29..574e38a9 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -841,8 +841,7 @@
       // the BlockingUrlProtocol to handle hops to the render thread for network
       // reads and seeks.
       blocking_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
-          {base::MayBlock(), base::WithBaseSyncPrimitives(),
-           base::TaskPriority::USER_BLOCKING})),
+          {base::MayBlock(), base::TaskPriority::USER_BLOCKING})),
       stopped_(false),
       pending_read_(false),
       data_source_(data_source),
diff --git a/mojo/edk/system/mach_port_relay.cc b/mojo/edk/system/mach_port_relay.cc
index f05cf22..1ff46f7 100644
--- a/mojo/edk/system/mach_port_relay.cc
+++ b/mojo/edk/system/mach_port_relay.cc
@@ -65,7 +65,7 @@
 }  // namespace
 
 // static
-bool MachPortRelay::ReceivePorts(PlatformHandleVector* handles) {
+void MachPortRelay::ReceivePorts(PlatformHandleVector* handles) {
   DCHECK(handles);
 
   for (size_t i = 0; i < handles->size(); i++) {
@@ -74,10 +74,11 @@
     if (handle->type != PlatformHandle::Type::MACH_NAME)
       continue;
 
-    if (handle->port == MACH_PORT_NULL) {
-      handle->type = PlatformHandle::Type::MACH;
+    handle->type = PlatformHandle::Type::MACH;
+
+    // MACH_PORT_NULL doesn't need translation.
+    if (handle->port == MACH_PORT_NULL)
       continue;
-    }
 
     base::mac::ScopedMachReceiveRight message_port(handle->port);
     base::mac::ScopedMachSendRight received_port(
@@ -85,16 +86,13 @@
     if (received_port.get() == MACH_PORT_NULL) {
       ReportChildError(ChildUMAError::ERROR_RECEIVE_MACH_MESSAGE);
       handle->port = MACH_PORT_NULL;
-      LOG(ERROR) << "Error receiving mach port";
-      return false;
+      DLOG(ERROR) << "Error receiving mach port";
+      continue;
     }
 
     ReportChildError(ChildUMAError::SUCCESS);
     handle->port = received_port.release();
-    handle->type = PlatformHandle::Type::MACH;
   }
-
-  return true;
 }
 
 MachPortRelay::MachPortRelay(base::PortProvider* port_provider)
@@ -107,20 +105,11 @@
   port_provider_->RemoveObserver(this);
 }
 
-bool MachPortRelay::SendPortsToProcess(Channel::Message* message,
+void MachPortRelay::SendPortsToProcess(Channel::Message* message,
                                        base::ProcessHandle process) {
   DCHECK(message);
   mach_port_t task_port = port_provider_->TaskForPid(process);
-  if (task_port == MACH_PORT_NULL) {
-    // Callers check the port provider for the task port before calling this
-    // function, in order to queue pending messages. Therefore, if this fails,
-    // it should be considered a genuine, bona fide, electrified, six-car error.
-    ReportBrokerError(BrokerUMAError::ERROR_TASK_FOR_PID);
-    return false;
-  }
 
-  size_t num_sent = 0;
-  bool error = false;
   ScopedPlatformHandleVectorPtr handles = message->TakeHandles();
   // Message should have handles, otherwise there's no point in calling this
   // function.
@@ -133,7 +122,19 @@
 
     if (handle->port == MACH_PORT_NULL) {
       handle->type = PlatformHandle::Type::MACH_NAME;
-      num_sent++;
+      continue;
+    }
+
+    if (task_port == MACH_PORT_NULL) {
+      // Callers check the port provider for the task port before calling this
+      // function, in order to queue pending messages. Therefore, if this fails,
+      // it should be considered a genuine, bona fide, electrified, six-car
+      // error.
+      ReportBrokerError(BrokerUMAError::ERROR_TASK_FOR_PID);
+
+      // For MACH_PORT_NULL, use Type::MACH to indicate that no extraction is
+      // necessary.
+      handle->port = MACH_PORT_NULL;
       continue;
     }
 
@@ -159,72 +160,47 @@
       }
       ReportBrokerError(uma_error);
       handle->port = MACH_PORT_NULL;
-      error = true;
-      break;
+      continue;
     }
 
     ReportBrokerError(BrokerUMAError::SUCCESS);
     handle->port = intermediate_port;
     handle->type = PlatformHandle::Type::MACH_NAME;
-    num_sent++;
   }
-  DCHECK(error || num_sent);
   message->SetHandles(std::move(handles));
-
-  return !error;
 }
 
-bool MachPortRelay::ExtractPortRights(Channel::Message* message,
-                                      base::ProcessHandle process) {
-  DCHECK(message);
+void MachPortRelay::ExtractPort(PlatformHandle* handle,
+                                base::ProcessHandle process) {
+  DCHECK_EQ(handle->type, PlatformHandle::Type::MACH_NAME);
+  handle->type = PlatformHandle::Type::MACH;
+
+  // No extraction necessary for MACH_PORT_NULL.
+  if (handle->port == MACH_PORT_NULL)
+    return;
 
   mach_port_t task_port = port_provider_->TaskForPid(process);
   if (task_port == MACH_PORT_NULL) {
     ReportBrokerError(BrokerUMAError::ERROR_TASK_FOR_PID);
-    return false;
+    handle->port = MACH_PORT_NULL;
+    return;
   }
 
-  size_t num_received = 0;
-  bool error = false;
-  ScopedPlatformHandleVectorPtr handles = message->TakeHandles();
-  // Message should have handles, otherwise there's no point in calling this
-  // function.
-  DCHECK(handles);
-  for (size_t i = 0; i < handles->size(); i++) {
-    PlatformHandle* handle = handles->data() + i;
-    DCHECK(handle->type != PlatformHandle::Type::MACH);
-    if (handle->type != PlatformHandle::Type::MACH_NAME)
-      continue;
-
-    if (handle->port == MACH_PORT_NULL) {
-      handle->type = PlatformHandle::Type::MACH;
-      num_received++;
-      continue;
-    }
-
-    mach_port_t extracted_right = MACH_PORT_NULL;
-    mach_msg_type_name_t extracted_right_type;
-    kern_return_t kr =
-        mach_port_extract_right(task_port, handle->port,
-                                MACH_MSG_TYPE_MOVE_SEND,
-                                &extracted_right, &extracted_right_type);
-    if (kr != KERN_SUCCESS) {
-      ReportBrokerError(BrokerUMAError::ERROR_EXTRACT_SOURCE_RIGHT);
-      error = true;
-      break;
-    }
-
-    ReportBrokerError(BrokerUMAError::SUCCESS);
-    DCHECK_EQ(static_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND),
-              extracted_right_type);
-    handle->port = extracted_right;
-    handle->type = PlatformHandle::Type::MACH;
-    num_received++;
+  mach_port_t extracted_right = MACH_PORT_NULL;
+  mach_msg_type_name_t extracted_right_type;
+  kern_return_t kr =
+      mach_port_extract_right(task_port, handle->port, MACH_MSG_TYPE_MOVE_SEND,
+                              &extracted_right, &extracted_right_type);
+  if (kr != KERN_SUCCESS) {
+    ReportBrokerError(BrokerUMAError::ERROR_EXTRACT_SOURCE_RIGHT);
+    handle->port = MACH_PORT_NULL;
+    return;
   }
-  DCHECK(error || num_received);
-  message->SetHandles(std::move(handles));
 
-  return !error;
+  ReportBrokerError(BrokerUMAError::SUCCESS);
+  DCHECK_EQ(static_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND),
+            extracted_right_type);
+  handle->port = extracted_right;
 }
 
 void MachPortRelay::AddObserver(Observer* observer) {
diff --git a/mojo/edk/system/mach_port_relay.h b/mojo/edk/system/mach_port_relay.h
index 87bc56cf..f72f7a7d 100644
--- a/mojo/edk/system/mach_port_relay.h
+++ b/mojo/edk/system/mach_port_relay.h
@@ -39,12 +39,11 @@
   // port and gives ownership of the final Mach port to the caller. Any handles
   // that are not Mach ports will remain unchanged, and the number and ordering
   // of handles is preserved.
-  // Returns |false| on failure and there is no guarantee about whether a Mach
-  // port is intermediate or final.
+  // On failure, the Mach port is replaced with MACH_PORT_NULL.
   //
   // See SendPortsToProcess() for the definition of intermediate and final Mach
   // ports.
-  static bool ReceivePorts(PlatformHandleVector* handles);
+  static void ReceivePorts(PlatformHandleVector* handles);
 
   explicit MachPortRelay(base::PortProvider* port_provider);
   ~MachPortRelay() override;
@@ -55,20 +54,15 @@
   // this intermediate port and the message is modified to refer to the name of
   // the intermediate port. The Mach port received over the intermediate port in
   // the child is referred to as the final Mach port.
-  // Returns |false| on failure and |message| may contain a mix of actual Mach
-  // ports and names.
-  bool SendPortsToProcess(Channel::Message* message,
+  // Ports that cannot be brokered are replaced with MACH_PORT_NULL.
+  void SendPortsToProcess(Channel::Message* message,
                           base::ProcessHandle process);
 
-  // Extracts the Mach ports attached to |message| from |process|.
-  // Any Mach ports attached to |message| are names and not actual Mach ports
-  // that are valid in this process. For each of those Mach port names, a send
-  // right is extracted from |process| and the port name is replaced with the
-  // send right.
-  // Returns |false| on failure and |message| may contain a mix of actual Mach
-  // ports and names.
-  bool ExtractPortRights(Channel::Message* message,
-                         base::ProcessHandle process);
+  // Given a PlatformHandle of Type::MACH_NAME, extracts the Mach port, and
+  // updates the contents of the PlatformHandle to have Type::MACH and have the
+  // actual Mach port. On failure, replaces the contents with Type::MACH and
+  // MACH_PORT_NULL.
+  void ExtractPort(PlatformHandle* handle, base::ProcessHandle process);
 
   // Observer interface.
   void AddObserver(Observer* observer);
diff --git a/mojo/edk/system/node_channel.cc b/mojo/edk/system/node_channel.cc
index 963fa338..c9a34951 100644
--- a/mojo/edk/system/node_channel.cc
+++ b/mojo/edk/system/node_channel.cc
@@ -518,11 +518,8 @@
   // RELAY_EVENT_MESSAGE.
   {
     MachPortRelay* relay = delegate_->GetMachPortRelay();
-    if (handles && !relay) {
-      if (!MachPortRelay::ReceivePorts(handles.get())) {
-        LOG(ERROR) << "Error receiving mach ports.";
-      }
-    }
+    if (handles && !relay)
+      MachPortRelay::ReceivePorts(handles.get());
   }
 #endif  // defined(OS_WIN)
 
@@ -819,11 +816,7 @@
   while (!pending_writes.empty()) {
     Channel::MessagePtr message = std::move(pending_writes.front());
     pending_writes.pop();
-    if (!relay->SendPortsToProcess(message.get(), remote_process_handle)) {
-      LOG(ERROR) << "Error on sending mach ports. Remote process is likely "
-                 << "gone. Dropping message.";
-      return;
-    }
+    relay->SendPortsToProcess(message.get(), remote_process_handle);
 
     base::AutoLock lock(channel_lock_);
     if (!channel_) {
@@ -899,11 +892,7 @@
         }
       }
 
-      if (!relay->SendPortsToProcess(message.get(), remote_process_handle)) {
-        LOG(ERROR) << "Error on sending mach ports. Remote process is likely "
-                   << "gone. Dropping message.";
-        return;
-      }
+      relay->SendPortsToProcess(message.get(), remote_process_handle);
     }
   }
 #endif
diff --git a/mojo/edk/system/node_controller.cc b/mojo/edk/system/node_controller.cc
index ee5ffd1b..af9a4951 100644
--- a/mojo/edk/system/node_controller.cc
+++ b/mojo/edk/system/node_controller.cc
@@ -1155,20 +1155,22 @@
   }
   message->SetHandles(std::move(handles));
 #else
-  MachPortRelay* relay = GetMachPortRelay();
-  if (!relay) {
-    LOG(ERROR) << "Receiving Mach ports without a port relay from "
-               << from_node << ". Dropping message.";
-    return;
+  ScopedPlatformHandleVectorPtr handles = message->TakeHandles();
+  for (size_t i = 0; i < handles->size(); ++i) {
+    PlatformHandle* handle = &(*handles)[i];
+    if (handle->type == PlatformHandle::Type::MACH_NAME) {
+      MachPortRelay* relay = GetMachPortRelay();
+      if (!relay) {
+        handle->type = PlatformHandle::Type::MACH;
+        handle->port = MACH_PORT_NULL;
+        DLOG(ERROR) << "Receiving Mach ports without a port relay from "
+                    << from_node << ".";
+        continue;
+      }
+      relay->ExtractPort(handle, from_process);
+    }
   }
-  if (!relay->ExtractPortRights(message.get(), from_process)) {
-    // NodeChannel should ensure that MachPortRelay is ready for the remote
-    // process. At this point, if the port extraction failed, either something
-    // went wrong in the mach stuff, or the remote process died.
-    LOG(ERROR) << "Error on receiving Mach ports " << from_node
-               << ". Dropping message.";
-    return;
-  }
+  message->SetHandles(std::move(handles));
 #endif  // defined(OS_WIN)
 
   if (destination == name_) {
diff --git a/mojo/public/cpp/system/platform_handle.cc b/mojo/public/cpp/system/platform_handle.cc
index 5e6c710f..a2fdd9df 100644
--- a/mojo/public/cpp/system/platform_handle.cc
+++ b/mojo/public/cpp/system/platform_handle.cc
@@ -172,7 +172,8 @@
   if (result != MOJO_RESULT_OK)
     return result;
 
-  CHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT);
+  CHECK(platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT ||
+        platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_INVALID);
   *port = static_cast<mach_port_t>(platform_handle.value);
   return MOJO_RESULT_OK;
 }
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 168bcb80..fb6e48c8 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -190,22 +190,22 @@
     {
       "name": "yahoo",
       "static_spki_hashes": [
+         "DigiCertAssuredIDRoot",
+         "DigiCertGlobalRoot",
+         "DigiCertGlobalRootG2",
+         "DigiCertGlobalRootG3",
+         "DigiCertTrustedRootG4",
+         "DigiCertEVRoot",
          "VeriSignClass2_G2",
          "VeriSignClass2_G3",
          "VeriSignClass3_G3",
          "VeriSignClass3_G4",
          "VeriSignClass3_G5",
          "VeriSignUniversal",
-         "GeoTrustGlobal",
-         "GeoTrustPrimary",
-         "GeoTrustPrimary_G2",
-         "GeoTrustPrimary_G3",
-         "GeoTrustUniversal",
-         "DigiCertGlobalRoot",
-         "DigiCertEVRoot",
          "YahooBackup1",
          "YahooBackup2"
-      ]
+      ],
+      "report_uri": "http://csp.yahoo.com/beacon/csp?src=yahoocom-hpkp-report-only"
     },
     {
       "name": "swehackCom",
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins
index 1972b8c2..23216f0 100644
--- a/net/http/transport_security_state_static.pins
+++ b/net/http/transport_security_state_static.pins
@@ -1650,3 +1650,85 @@
 3zdFfyi/c3LKxf6ZkKYRNCSCL3UXZcLZZhHBwwC9kMMJQohmxwkV7t2imWWbtnTX
 jQIDAQAB
 -----END PUBLIC KEY-----
+
+# DigiCert Global Root G2
+# https://www.digicert.com/CACerts/DigiCertGlobalRootG2.crt
+DigiCertGlobalRootG2
+-----BEGIN CERTIFICATE-----
+MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
+MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
+2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
+1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
+q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
+tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
+vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
+5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
+1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
+NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
+Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
+8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
+pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
+MrY=
+-----END CERTIFICATE-----
+
+# DigiCert Global Root G3
+# https://www.digicert.com/CACerts/DigiCertGlobalRootG3.crt
+DigiCertGlobalRootG3
+-----BEGIN CERTIFICATE-----
+MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw
+CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
+ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe
+Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw
+EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x
+IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF
+K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG
+fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO
+Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd
+BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx
+AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/
+oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8
+sycX
+-----END CERTIFICATE-----
+
+# DigiCert Trusted Root G4
+# https://www.digicert.com/CACerts/DigiCertTrustedRootG4.crt
+DigiCertTrustedRootG4
+-----BEGIN CERTIFICATE-----
+MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg
+RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV
+UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu
+Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y
+ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If
+xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV
+ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO
+DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ
+jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/
+CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi
+EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM
+fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY
+uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK
+chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t
+9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
+ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2
+SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd
++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc
+fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa
+sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N
+cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N
+0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie
+4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI
+r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1
+/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm
+gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+
+-----END CERTIFICATE-----
+
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 7ee992e6..be53b99 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -32,6 +32,7 @@
 #include "net/log/net_log_event_type.h"
 #include "net/log/net_log_source_type.h"
 #include "net/ssl/ssl_cert_request_info.h"
+#include "net/url_request/network_error_logging_delegate.h"
 #include "net/url_request/redirect_info.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_error_job.h"
@@ -1175,6 +1176,8 @@
   if (network_delegate_)
     network_delegate_->NotifyCompleted(this, job_.get() != NULL,
                                        status_.error());
+
+  MaybeGenerateNetworkErrorLoggingReport();
 }
 
 void URLRequest::OnCallToDelegate() {
@@ -1193,6 +1196,39 @@
   net_log_.EndEvent(NetLogEventType::URL_REQUEST_DELEGATE);
 }
 
+void URLRequest::MaybeGenerateNetworkErrorLoggingReport() {
+  NetworkErrorLoggingDelegate* delegate =
+      context()->network_error_logging_delegate();
+  if (!delegate)
+    return;
+
+  // TODO(juliatuttle): Figure out whether we should be ignoring errors from
+  // non-HTTPS origins.
+
+  // TODO(juliatuttle): Remove this and reconsider interface once there's a
+  // better story for reporting successes.
+  if (status().ToNetError() == OK)
+    return;
+
+  NetworkErrorLoggingDelegate::ErrorDetails details;
+
+  details.uri = url();
+  details.referrer = GURL(referrer());
+  IPEndPoint endpoint;
+  if (GetRemoteEndpoint(&endpoint))
+    details.server_ip = endpoint.address();
+  // TODO(juliatuttle): Plumb this.
+  details.protocol = kProtoUnknown;
+  details.status_code = GetResponseCode();
+  if (details.status_code == -1)
+    details.status_code = 0;
+  details.elapsed_time =
+      base::TimeTicks::Now() - load_timing_info_.request_start;
+  details.type = status().ToNetError();
+
+  delegate->OnNetworkError(details);
+}
+
 void URLRequest::GetConnectionAttempts(ConnectionAttempts* out) const {
   if (job_)
     job_->GetConnectionAttempts(out);
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index 378fe78..658523a 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -772,6 +772,8 @@
   // cancellation.
   void OnCallToDelegateComplete();
 
+  void MaybeGenerateNetworkErrorLoggingReport();
+
   // Contextual information used for this request. Cannot be NULL. This contains
   // most of the dependencies which are shared between requests (disk cache,
   // cookie store, socket pool, etc.)
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 04fee52c..5e55598 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -7143,7 +7143,9 @@
   EXPECT_TRUE(IsCertStatusError(request->ssl_info().cert_status));
   EXPECT_TRUE(reporting_service.headers().empty());
 }
-#endif  // BUILDFLAG(ENABLE_REPORTING)
+
+// Network Error Logging is dependent on the Reporting API, so only run NEL
+// tests if Reporting is enabled in the build.
 
 namespace {
 
@@ -7284,6 +7286,81 @@
   EXPECT_TRUE(nel_delegate.headers().empty());
 }
 
+TEST_F(URLRequestTestHTTP, DontForwardErrorToNelNoDelegate) {
+  URLRequestFailedJob::AddUrlHandler();
+
+  GURL request_url =
+      URLRequestFailedJob::GetMockHttpsUrl(ERR_CONNECTION_REFUSED);
+
+  TestNetworkDelegate network_delegate;
+  TestURLRequestContext context(true);
+  context.set_network_delegate(&network_delegate);
+  context.Init();
+
+  TestDelegate d;
+  std::unique_ptr<URLRequest> request(context.CreateRequest(
+      request_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
+  request->Start();
+  base::RunLoop().Run();
+
+  URLRequestFilter::GetInstance()->ClearHandlers();
+}
+
+// TODO(juliatuttle): Figure out whether this restriction should be in place,
+// and either implement it or remove this test.
+TEST_F(URLRequestTestHTTP, DISABLED_DontForwardErrorToNelHttp) {
+  URLRequestFailedJob::AddUrlHandler();
+
+  GURL request_url =
+      URLRequestFailedJob::GetMockHttpUrl(ERR_CONNECTION_REFUSED);
+
+  TestNetworkDelegate network_delegate;
+  TestNetworkErrorLoggingDelegate nel_delegate;
+  TestURLRequestContext context(true);
+  context.set_network_delegate(&network_delegate);
+  context.set_network_error_logging_delegate(&nel_delegate);
+  context.Init();
+
+  TestDelegate d;
+  std::unique_ptr<URLRequest> request(context.CreateRequest(
+      request_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
+  request->Start();
+  base::RunLoop().Run();
+
+  EXPECT_TRUE(nel_delegate.errors().empty());
+
+  URLRequestFilter::GetInstance()->ClearHandlers();
+}
+
+TEST_F(URLRequestTestHTTP, ForwardErrorToNelHttps) {
+  URLRequestFailedJob::AddUrlHandler();
+
+  GURL request_url =
+      URLRequestFailedJob::GetMockHttpsUrl(ERR_CONNECTION_REFUSED);
+
+  TestNetworkDelegate network_delegate;
+  TestNetworkErrorLoggingDelegate nel_delegate;
+  TestURLRequestContext context(true);
+  context.set_network_delegate(&network_delegate);
+  context.set_network_error_logging_delegate(&nel_delegate);
+  context.Init();
+
+  TestDelegate d;
+  std::unique_ptr<URLRequest> request(context.CreateRequest(
+      request_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
+  request->Start();
+  base::RunLoop().Run();
+
+  ASSERT_EQ(1u, nel_delegate.errors().size());
+  EXPECT_EQ(request_url, nel_delegate.errors()[0].uri);
+  EXPECT_EQ(0, nel_delegate.errors()[0].status_code);
+  EXPECT_EQ(ERR_CONNECTION_REFUSED, nel_delegate.errors()[0].type);
+
+  URLRequestFilter::GetInstance()->ClearHandlers();
+}
+
+#endif  // BUILDFLAG(ENABLE_REPORTING)
+
 TEST_F(URLRequestTestHTTP, ContentTypeNormalizationTest) {
   ASSERT_TRUE(http_test_server()->Start());
 
diff --git a/sandbox/win/src/nt_internals.h b/sandbox/win/src/nt_internals.h
index d89c9b1..2b2dc0f 100644
--- a/sandbox/win/src/nt_internals.h
+++ b/sandbox/win/src/nt_internals.h
@@ -794,6 +794,11 @@
 
 const unsigned int NtProcessInformationAccessToken = 9;
 
+typedef NTSTATUS(WINAPI* RtlDeriveCapabilitySidsFromNameFunction)(
+    PCUNICODE_STRING SourceString,
+    PSID CapabilityGroupSid,
+    PSID CapabilitySid);
+
 // -----------------------------------------------------------------------
 // GDI OPM API and Supported Calls
 
diff --git a/sandbox/win/src/sid.cc b/sandbox/win/src/sid.cc
index 5c77548..3507ad7 100644
--- a/sandbox/win/src/sid.cc
+++ b/sandbox/win/src/sid.cc
@@ -16,49 +16,36 @@
 
 namespace {
 
-typedef decltype(
-    ::DeriveCapabilitySidsFromName) DeriveCapabilitySidsFromNameFunc;
-
-class SidArray {
- public:
-  SidArray() : count_(0), sids_(nullptr) {}
-
-  ~SidArray() {
-    if (sids_) {
-      for (size_t index = 0; index < count_; ++index) {
-        ::LocalFree(sids_[index]);
-      }
-      ::LocalFree(sids_);
-    }
-  }
-
-  DWORD count() { return count_; }
-  PSID* sids() { return sids_; }
-  PDWORD count_ptr() { return &count_; }
-  PSID** sids_ptr() { return &sids_; }
-
- private:
-  DWORD count_;
-  PSID* sids_;
-};
-
-const wchar_t* WellKnownCapabilityToName(WellKnownCapabilities capability) {
+DWORD WellKnownCapabilityToRid(WellKnownCapabilities capability) {
   switch (capability) {
     case kInternetClient:
-      return L"internetClient";
+      return SECURITY_CAPABILITY_INTERNET_CLIENT;
     case kInternetClientServer:
-      return L"internetClientServer";
-    case kRegistryRead:
-      return L"registryRead";
-    case kLpacCryptoServices:
-      return L"lpacCryptoServices";
-    case kEnterpriseAuthentication:
-      return L"enterpriseAuthentication";
+      return SECURITY_CAPABILITY_INTERNET_CLIENT_SERVER;
     case kPrivateNetworkClientServer:
-      return L"privateNetworkClientServer";
+      return SECURITY_CAPABILITY_PRIVATE_NETWORK_CLIENT_SERVER;
+    case kPicturesLibrary:
+      return SECURITY_CAPABILITY_PICTURES_LIBRARY;
+    case kVideosLibrary:
+      return SECURITY_CAPABILITY_VIDEOS_LIBRARY;
+    case kMusicLibrary:
+      return SECURITY_CAPABILITY_MUSIC_LIBRARY;
+    case kDocumentsLibrary:
+      return SECURITY_CAPABILITY_DOCUMENTS_LIBRARY;
+    case kEnterpriseAuthentication:
+      return SECURITY_CAPABILITY_ENTERPRISE_AUTHENTICATION;
+    case kSharedUserCertificates:
+      return SECURITY_CAPABILITY_SHARED_USER_CERTIFICATES;
+    case kRemovableStorage:
+      return SECURITY_CAPABILITY_REMOVABLE_STORAGE;
+    case kAppointments:
+      return SECURITY_CAPABILITY_APPOINTMENTS;
+    case kContacts:
+      return SECURITY_CAPABILITY_CONTACTS;
     default:
-      return nullptr;
+      break;
   }
+  return 0;
 }
 
 }  // namespace
@@ -81,33 +68,39 @@
 }
 
 Sid Sid::FromKnownCapability(WellKnownCapabilities capability) {
-  return Sid::FromNamedCapability(WellKnownCapabilityToName(capability));
+  DWORD capability_rid = WellKnownCapabilityToRid(capability);
+  if (!capability_rid)
+    return Sid();
+  SID_IDENTIFIER_AUTHORITY capability_authority = {
+      SECURITY_APP_PACKAGE_AUTHORITY};
+  DWORD sub_authorities[] = {SECURITY_CAPABILITY_BASE_RID, capability_rid};
+  return FromSubAuthorities(&capability_authority, 2, sub_authorities);
 }
 
 Sid Sid::FromNamedCapability(const wchar_t* capability_name) {
-  DeriveCapabilitySidsFromNameFunc* derive_capablity_sids =
-      (DeriveCapabilitySidsFromNameFunc*)GetProcAddress(
-          GetModuleHandle(L"kernelbase"), "DeriveCapabilitySidsFromName");
-  if (!derive_capablity_sids)
+  RtlDeriveCapabilitySidsFromNameFunction derive_capability_sids = nullptr;
+  ResolveNTFunctionPtr("RtlDeriveCapabilitySidsFromName",
+                       &derive_capability_sids);
+  RtlInitUnicodeStringFunction init_unicode_string = nullptr;
+  ResolveNTFunctionPtr("RtlInitUnicodeString", &init_unicode_string);
+
+  if (!derive_capability_sids || !init_unicode_string)
     return Sid();
 
   if (!capability_name || ::wcslen(capability_name) == 0)
     return Sid();
 
-  SidArray capability_group_sids;
-  SidArray capability_sids;
+  UNICODE_STRING name = {};
+  init_unicode_string(&name, capability_name);
+  Sid capability_sid;
+  Sid group_sid;
 
-  if (!derive_capablity_sids(capability_name, capability_group_sids.sids_ptr(),
-                             capability_group_sids.count_ptr(),
-                             capability_sids.sids_ptr(),
-                             capability_sids.count_ptr())) {
-    return Sid();
-  }
-
-  if (capability_sids.count() < 1)
+  NTSTATUS status =
+      derive_capability_sids(&name, group_sid.sid_, capability_sid.sid_);
+  if (!NT_SUCCESS(status))
     return Sid();
 
-  return Sid(capability_sids.sids()[0]);
+  return capability_sid;
 }
 
 Sid Sid::FromSddlString(const wchar_t* sddl_sid) {
diff --git a/sandbox/win/src/sid.h b/sandbox/win/src/sid.h
index acaaa74..4ef22e5 100644
--- a/sandbox/win/src/sid.h
+++ b/sandbox/win/src/sid.h
@@ -11,13 +11,20 @@
 
 namespace sandbox {
 
+// Known capabilities defined in Windows 8.
 enum WellKnownCapabilities {
   kInternetClient,
   kInternetClientServer,
-  kRegistryRead,
-  kLpacCryptoServices,
-  kEnterpriseAuthentication,
   kPrivateNetworkClientServer,
+  kPicturesLibrary,
+  kVideosLibrary,
+  kMusicLibrary,
+  kDocumentsLibrary,
+  kEnterpriseAuthentication,
+  kSharedUserCertificates,
+  kRemovableStorage,
+  kAppointments,
+  kContacts,
   kMaxWellKnownCapability
 };
 
@@ -34,7 +41,8 @@
   // Create a Sid from an AppContainer capability name. The name can be
   // completely arbitrary.
   static Sid FromNamedCapability(const wchar_t* capability_name);
-  // Create a Sid from a known capability enumeration value.
+  // Create a Sid from a known capability enumeration value. The Sids
+  // match with the list defined in Windows 8.
   static Sid FromKnownCapability(WellKnownCapabilities capability);
   // Create a Sid from a SDDL format string, such as S-1-1-0.
   static Sid FromSddlString(const wchar_t* sddl_sid);
diff --git a/sandbox/win/src/sid_unittest.cc b/sandbox/win/src/sid_unittest.cc
index 0f4fc9bb..5b01d592 100644
--- a/sandbox/win/src/sid_unittest.cc
+++ b/sandbox/win/src/sid_unittest.cc
@@ -35,10 +35,14 @@
   return equal;
 }
 
-struct CapabilityTestEntry {
-  WellKnownCapabilities capability_;
-  const wchar_t* capability_name_;
-  const wchar_t* sddl_sid_;
+struct KnownCapabilityTestEntry {
+  WellKnownCapabilities capability;
+  const wchar_t* sddl_sid;
+};
+
+struct NamedCapabilityTestEntry {
+  const wchar_t* capability_name;
+  const wchar_t* sddl_sid;
 };
 
 }  // namespace
@@ -95,22 +99,38 @@
   ASSERT_TRUE(EqualSid(Sid(::WinProxySid), ATL::Sids::Proxy()));
 }
 
-TEST(SidTest, AppContainer) {
-  const CapabilityTestEntry capabilities[] = {
-      {kInternetClient, L"internetClient", L"S-1-15-3-1"},
-      {kInternetClientServer, L"internetClientServer", L"S-1-15-3-2"},
-      {kRegistryRead, L"registryRead",
-       L"S-1-15-3-1024-1065365936-1281604716-3511738428-"
-       "1654721687-432734479-3232135806-4053264122-3456934681"},
-      {kLpacCryptoServices, L"lpacCryptoServices",
-       L"S-1-15-3-1024-3203351429-2120443784-2872670797-"
-       "1918958302-2829055647-4275794519-765664414-2751773334"},
-      {kEnterpriseAuthentication, L"enterpriseAuthentication", L"S-1-15-3-8"},
-      {kPrivateNetworkClientServer, L"privateNetworkClientServer",
-       L"S-1-15-3-3"}};
+TEST(SidTest, KnownCapability) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
 
-  // No support for AppContainer less than Win10 RS2.
-  if (base::win::GetVersion() < base::win::VERSION_WIN10_RS2)
+  Sid sid_invalid_well_known =
+      Sid::FromKnownCapability(kMaxWellKnownCapability);
+  EXPECT_FALSE(sid_invalid_well_known.IsValid());
+
+  const KnownCapabilityTestEntry capabilities[] = {
+      {kInternetClient, L"S-1-15-3-1"},
+      {kInternetClientServer, L"S-1-15-3-2"},
+      {kPrivateNetworkClientServer, L"S-1-15-3-3"},
+      {kPicturesLibrary, L"S-1-15-3-4"},
+      {kVideosLibrary, L"S-1-15-3-5"},
+      {kMusicLibrary, L"S-1-15-3-6"},
+      {kDocumentsLibrary, L"S-1-15-3-7"},
+      {kEnterpriseAuthentication, L"S-1-15-3-8"},
+      {kSharedUserCertificates, L"S-1-15-3-9"},
+      {kRemovableStorage, L"S-1-15-3-10"},
+      {kAppointments, L"S-1-15-3-11"},
+      {kContacts, L"S-1-15-3-12"},
+  };
+
+  for (auto capability : capabilities) {
+    EXPECT_TRUE(EqualSid(Sid::FromKnownCapability(capability.capability),
+                         capability.sddl_sid))
+        << "Known Capability: " << capability.sddl_sid;
+  }
+}
+
+TEST(SidTest, NamedCapability) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN10)
     return;
 
   Sid sid_nullptr = Sid::FromNamedCapability(nullptr);
@@ -119,18 +139,22 @@
   Sid sid_empty = Sid::FromNamedCapability(L"");
   EXPECT_FALSE(sid_empty.IsValid());
 
-  WellKnownCapabilities invalid_well_known =
-      static_cast<WellKnownCapabilities>(kMaxWellKnownCapability + 1);
-  Sid sid_invalid_well_known = Sid::FromKnownCapability(invalid_well_known);
-  EXPECT_FALSE(sid_invalid_well_known.IsValid());
+  const NamedCapabilityTestEntry capabilities[] = {
+      {L"internetClient", L"S-1-15-3-1"},
+      {L"internetClientServer", L"S-1-15-3-2"},
+      {L"registryRead",
+       L"S-1-15-3-1024-1065365936-1281604716-3511738428-"
+       "1654721687-432734479-3232135806-4053264122-3456934681"},
+      {L"lpacCryptoServices",
+       L"S-1-15-3-1024-3203351429-2120443784-2872670797-"
+       "1918958302-2829055647-4275794519-765664414-2751773334"},
+      {L"enterpriseAuthentication", L"S-1-15-3-8"},
+      {L"privateNetworkClientServer", L"S-1-15-3-3"}};
 
   for (auto capability : capabilities) {
-    EXPECT_TRUE(EqualSid(Sid::FromNamedCapability(capability.capability_name_),
-                         capability.sddl_sid_))
-        << "Named Capability: " << capability.sddl_sid_;
-    EXPECT_TRUE(EqualSid(Sid::FromKnownCapability(capability.capability_),
-                         capability.sddl_sid_))
-        << "Known Capability: " << capability.sddl_sid_;
+    EXPECT_TRUE(EqualSid(Sid::FromNamedCapability(capability.capability_name),
+                         capability.sddl_sid))
+        << "Named Capability: " << capability.sddl_sid;
   }
 }
 
diff --git a/services/BUILD.gn b/services/BUILD.gn
index 471cda3..c34651b 100644
--- a/services/BUILD.gn
+++ b/services/BUILD.gn
@@ -59,6 +59,7 @@
 
   if (is_android) {
     deps += [
+      "//services/data_decoder/public/cpp/android:safe_json_java",
       "//services/device:java",
 
       # Some tests need to initialize V8.
diff --git a/services/data_decoder/BUILD.gn b/services/data_decoder/BUILD.gn
index 6f347b95..e10cd16 100644
--- a/services/data_decoder/BUILD.gn
+++ b/services/data_decoder/BUILD.gn
@@ -11,6 +11,8 @@
     "data_decoder_service.h",
     "image_decoder_impl.cc",
     "image_decoder_impl.h",
+    "json_parser_impl.cc",
+    "json_parser_impl.h",
   ]
 
   deps = [
@@ -33,6 +35,8 @@
 
   sources = [
     "image_decoder_impl_unittest.cc",
+    "public/cpp/json_sanitizer_unittest.cc",
+    "public/cpp/testing_json_parser_unittest.cc",
   ]
 
   deps = [
@@ -40,6 +44,8 @@
     "//base",
     "//gin",
     "//gin:gin_test",
+    "//services/data_decoder/public/cpp",
+    "//services/data_decoder/public/cpp:test_support",
     "//skia",
     "//testing/gtest",
     "//third_party/WebKit/public:blink",
diff --git a/services/data_decoder/DEPS b/services/data_decoder/DEPS
index d15dcafe..e1f42c99 100644
--- a/services/data_decoder/DEPS
+++ b/services/data_decoder/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+gin",
+  "+jni",
   "+skia",
   "+third_party/WebKit/public",
   "+third_party/skia",
diff --git a/services/data_decoder/OWNERS b/services/data_decoder/OWNERS
index 59dfd4b3..e86a404 100644
--- a/services/data_decoder/OWNERS
+++ b/services/data_decoder/OWNERS
@@ -1,2 +1,6 @@
 per-file manifest.json=set noparent
 per-file manifest.json=file://ipc/SECURITY_OWNERS
+
+bauerb@chromium.org
+jcivelli@chromium.org
+rsesek@chromium.org
diff --git a/services/data_decoder/data_decoder_service.cc b/services/data_decoder/data_decoder_service.cc
index c42316f..63df926 100644
--- a/services/data_decoder/data_decoder_service.cc
+++ b/services/data_decoder/data_decoder_service.cc
@@ -10,6 +10,7 @@
 #include "base/time/time.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/data_decoder/image_decoder_impl.h"
+#include "services/data_decoder/json_parser_impl.h"
 #include "services/data_decoder/public/interfaces/image_decoder.mojom.h"
 #include "services/service_manager/public/cpp/service_context.h"
 
@@ -25,6 +26,13 @@
       std::move(request));
 }
 
+void OnJsonParserRequest(service_manager::ServiceContextRefFactory* ref_factory,
+                         mojom::JsonParserRequest request) {
+  mojo::MakeStrongBinding(
+      base::MakeUnique<JsonParserImpl>(ref_factory->CreateRef()),
+      std::move(request));
+}
+
 }  // namespace
 
 DataDecoderService::DataDecoderService() : weak_factory_(this) {}
@@ -41,6 +49,7 @@
       &DataDecoderService::MaybeRequestQuitDelayed, base::Unretained(this))));
   registry_.AddInterface(
       base::Bind(&OnImageDecoderRequest, ref_factory_.get()));
+  registry_.AddInterface(base::Bind(&OnJsonParserRequest, ref_factory_.get()));
 }
 
 void DataDecoderService::OnBindInterface(
diff --git a/services/data_decoder/image_decoder_impl_unittest.cc b/services/data_decoder/image_decoder_impl_unittest.cc
index 88429d7..a3a929bf 100644
--- a/services/data_decoder/image_decoder_impl_unittest.cc
+++ b/services/data_decoder/image_decoder_impl_unittest.cc
@@ -129,7 +129,7 @@
 
     // Check that image has been shrunk appropriately
     EXPECT_LT(request.bitmap().computeByteSize() + base_msg_size,
-              (uint64_t)kTestMaxImageSize);
+              static_cast<uint64_t>(kTestMaxImageSize));
 // Android does its own image shrinking for memory conservation deeper in
 // the decode, so more specific tests here won't work.
 #if !defined(OS_ANDROID)
diff --git a/services/data_decoder/json_parser_impl.cc b/services/data_decoder/json_parser_impl.cc
new file mode 100644
index 0000000..7c19f423
--- /dev/null
+++ b/services/data_decoder/json_parser_impl.cc
@@ -0,0 +1,34 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/data_decoder/json_parser_impl.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/json/json_reader.h"
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+
+namespace data_decoder {
+
+JsonParserImpl::JsonParserImpl(
+    std::unique_ptr<service_manager::ServiceContextRef> service_ref)
+    : service_ref_(std::move(service_ref)) {}
+
+JsonParserImpl::~JsonParserImpl() = default;
+
+void JsonParserImpl::Parse(const std::string& json, ParseCallback callback) {
+  int error_code;
+  std::string error;
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
+      json, base::JSON_PARSE_RFC, &error_code, &error);
+  if (value) {
+    std::move(callback).Run(std::move(value), base::nullopt);
+  } else {
+    std::move(callback).Run(nullptr, base::make_optional(std::move(error)));
+  }
+}
+
+}  // namespace data_decoder
diff --git a/services/data_decoder/json_parser_impl.h b/services/data_decoder/json_parser_impl.h
new file mode 100644
index 0000000..9656d04
--- /dev/null
+++ b/services/data_decoder/json_parser_impl.h
@@ -0,0 +1,33 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_DATA_DECODER_JSON_PARSER_IMPL_H_
+#define SERVICES_DATA_DECODER_JSON_PARSER_IMPL_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "services/data_decoder/public/interfaces/json_parser.mojom.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
+
+namespace data_decoder {
+
+class JsonParserImpl : public mojom::JsonParser {
+ public:
+  explicit JsonParserImpl(
+      std::unique_ptr<service_manager::ServiceContextRef> service_ref);
+  ~JsonParserImpl() override;
+
+ private:
+  const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
+
+  // mojom::JsonParser implementation.
+  void Parse(const std::string& json, ParseCallback callback) override;
+
+  DISALLOW_COPY_AND_ASSIGN(JsonParserImpl);
+};
+
+}  // namespace data_decoder
+
+#endif  // SERVICES_DATA_DECODER_JSON_PARSER_IMPL_H_
diff --git a/services/data_decoder/manifest.json b/services/data_decoder/manifest.json
index bc0335b..954d104 100644
--- a/services/data_decoder/manifest.json
+++ b/services/data_decoder/manifest.json
@@ -4,7 +4,8 @@
   "interface_provider_specs": {
     "service_manager:connector": {
       "provides": {
-        "image_decoder": [ "data_decoder::mojom::ImageDecoder" ]
+        "image_decoder": [ "data_decoder::mojom::ImageDecoder" ],
+        "json_parser": [ "data_decoder::mojom::JsonParser" ]
       },
       "requires": {
         "service_manager": [ "service_manager:all_users" ]
diff --git a/services/data_decoder/public/cpp/BUILD.gn b/services/data_decoder/public/cpp/BUILD.gn
index ebab3dc..142508a 100644
--- a/services/data_decoder/public/cpp/BUILD.gn
+++ b/services/data_decoder/public/cpp/BUILD.gn
@@ -8,10 +8,43 @@
   sources = [
     "decode_image.cc",
     "decode_image.h",
+    "json_sanitizer.cc",
+    "json_sanitizer.h",
+    "safe_json_parser.cc",
+    "safe_json_parser.h",
+    "safe_json_parser_impl.cc",
+    "safe_json_parser_impl.h",
+    "safe_json_parser_impl.h",
   ]
 
   public_deps = [
     "//services/data_decoder/public/interfaces",
     "//services/service_manager/public/cpp",
   ]
+
+  if (is_android) {
+    sources -= [ "json_sanitizer.cc" ]
+    sources += [
+      "json_sanitizer_android.cc",
+      "safe_json_parser_android.cc",
+      "safe_json_parser_android.h",
+    ]
+    deps = [
+      "android:safe_json_java($default_toolchain)",
+      "android:safe_json_jni_headers",
+    ]
+  }
+}
+
+static_library("test_support") {
+  testonly = true
+  sources = [
+    "testing_json_parser.cc",
+    "testing_json_parser.h",
+  ]
+
+  deps = [
+    ":cpp",
+    "//base",
+  ]
 }
diff --git a/services/data_decoder/public/cpp/android/BUILD.gn b/services/data_decoder/public/cpp/android/BUILD.gn
new file mode 100644
index 0000000..4a07518
--- /dev/null
+++ b/services/data_decoder/public/cpp/android/BUILD.gn
@@ -0,0 +1,22 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+
+_jni_sources =
+    [ "java/src/org/chromium/services/data_decoder/JsonSanitizer.java" ]
+
+generate_jni("safe_json_jni_headers") {
+  sources = _jni_sources
+  jni_package = "data_decoder"
+}
+
+if (current_toolchain == default_toolchain) {
+  android_library("safe_json_java") {
+    deps = [
+      "//base:base_java",
+    ]
+    java_files = [] + _jni_sources
+  }
+}
diff --git a/components/safe_json/android/java/src/org/chromium/components/safejson/JsonSanitizer.java b/services/data_decoder/public/cpp/android/java/src/org/chromium/services/data_decoder/JsonSanitizer.java
similarity index 98%
rename from components/safe_json/android/java/src/org/chromium/components/safejson/JsonSanitizer.java
rename to services/data_decoder/public/cpp/android/java/src/org/chromium/services/data_decoder/JsonSanitizer.java
index 641d4ed8..b3c4bfa 100644
--- a/components/safe_json/android/java/src/org/chromium/components/safejson/JsonSanitizer.java
+++ b/services/data_decoder/public/cpp/android/java/src/org/chromium/services/data_decoder/JsonSanitizer.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.components.safejson;
+package org.chromium.services.data_decoder;
 
 import android.util.JsonReader;
 import android.util.JsonToken;
@@ -21,12 +21,10 @@
  * Sanitizes and normalizes a JSON string by parsing it, checking for wellformedness, and
  * serializing it again. This class is meant to be used from native code.
  */
-@JNINamespace("safe_json")
+@JNINamespace("data_decoder")
 public class JsonSanitizer {
-
     // Disallow instantiating the class.
-    private JsonSanitizer() {
-    }
+    private JsonSanitizer() {}
 
     /**
      * The maximum nesting depth to which the native JSON parser restricts input in order to avoid
diff --git a/components/safe_json/json_sanitizer.cc b/services/data_decoder/public/cpp/json_sanitizer.cc
similarity index 72%
rename from components/safe_json/json_sanitizer.cc
rename to services/data_decoder/public/cpp/json_sanitizer.cc
index b98283f..9a730c4 100644
--- a/components/safe_json/json_sanitizer.cc
+++ b/services/data_decoder/public/cpp/json_sanitizer.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/safe_json/json_sanitizer.h"
+#include "services/data_decoder/public/cpp/json_sanitizer.h"
 
 #if defined(OS_ANDROID)
 #error Build json_sanitizer_android.cc instead of this file on Android.
@@ -18,15 +18,16 @@
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "components/safe_json/safe_json_parser.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 
-namespace safe_json {
+namespace data_decoder {
 
 namespace {
 
 class OopJsonSanitizer : public JsonSanitizer {
  public:
-  OopJsonSanitizer(const std::string& unsafe_json,
+  OopJsonSanitizer(service_manager::Connector* connector,
+                   const std::string& unsafe_json,
                    const StringCallback& success_callback,
                    const StringCallback& error_callback);
 
@@ -43,15 +44,15 @@
   DISALLOW_COPY_AND_ASSIGN(OopJsonSanitizer);
 };
 
-OopJsonSanitizer::OopJsonSanitizer(const std::string& unsafe_json,
+OopJsonSanitizer::OopJsonSanitizer(service_manager::Connector* connector,
+                                   const std::string& unsafe_json,
                                    const StringCallback& success_callback,
                                    const StringCallback& error_callback)
     : success_callback_(success_callback), error_callback_(error_callback) {
-  SafeJsonParser::Parse(unsafe_json,
-                        base::Bind(&OopJsonSanitizer::OnParseSuccess,
-                                   base::Unretained(this)),
-                        base::Bind(&OopJsonSanitizer::OnParseError,
-                                   base::Unretained(this)));
+  SafeJsonParser::Parse(
+      connector, unsafe_json,
+      base::Bind(&OopJsonSanitizer::OnParseSuccess, base::Unretained(this)),
+      base::Bind(&OopJsonSanitizer::OnParseError, base::Unretained(this)));
 }
 
 void OopJsonSanitizer::OnParseSuccess(std::unique_ptr<base::Value> value) {
@@ -84,11 +85,13 @@
 }  // namespace
 
 // static
-void JsonSanitizer::Sanitize(const std::string& unsafe_json,
+void JsonSanitizer::Sanitize(service_manager::Connector* connector,
+                             const std::string& unsafe_json,
                              const StringCallback& success_callback,
                              const StringCallback& error_callback) {
   // OopJsonSanitizer destroys itself when it is finished.
-  new OopJsonSanitizer(unsafe_json, success_callback, error_callback);
+  new OopJsonSanitizer(connector, unsafe_json, success_callback,
+                       error_callback);
 }
 
-}  // namespace safe_json
+}  // namespace data_decoder
diff --git a/components/safe_json/json_sanitizer.h b/services/data_decoder/public/cpp/json_sanitizer.h
similarity index 67%
rename from components/safe_json/json_sanitizer.h
rename to services/data_decoder/public/cpp/json_sanitizer.h
index 434f4be..df467978 100644
--- a/components/safe_json/json_sanitizer.h
+++ b/services/data_decoder/public/cpp/json_sanitizer.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_SAFE_JSON_JSON_SANITIZER_H_
-#define COMPONENTS_SAFE_JSON_JSON_SANITIZER_H_
+#ifndef SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_JSON_SANITIZER_H_
+#define SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_JSON_SANITIZER_H_
 
 #include <string>
 
@@ -16,7 +16,11 @@
 #include <jni.h>
 #endif
 
-namespace safe_json {
+namespace service_manager {
+class Connector;
+}
+
+namespace data_decoder {
 
 // Sanitizes and normalizes JSON by parsing it in a safe environment and
 // re-serializing it. Parsing the sanitized JSON should result in a value
@@ -32,7 +36,11 @@
   // |success_callback| or the |error_callback| will be called with the result
   // of the sanitization or an error message, respectively, but not before the
   // method returns.
-  static void Sanitize(const std::string& unsafe_json,
+  // |connector| is the connector provided by the service manager and is used
+  // to retrieve the JSON decoder service. It's commonly retrieved from a
+  // service manager connection context object that the embedder provides.
+  static void Sanitize(service_manager::Connector* connector,
+                       const std::string& unsafe_json,
                        const StringCallback& success_callback,
                        const StringCallback& error_callback);
 
@@ -44,6 +52,6 @@
   DISALLOW_COPY_AND_ASSIGN(JsonSanitizer);
 };
 
-}  // namespace safe_json
+}  // namespace data_decoder
 
-#endif  // COMPONENTS_SAFE_JSON_JSON_SANITIZER_H_
+#endif  // SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_JSON_SANITIZER_H_
diff --git a/components/safe_json/json_sanitizer_android.cc b/services/data_decoder/public/cpp/json_sanitizer_android.cc
similarity index 94%
rename from components/safe_json/json_sanitizer_android.cc
rename to services/data_decoder/public/cpp/json_sanitizer_android.cc
index 82d9506..6dea4d2 100644
--- a/components/safe_json/json_sanitizer_android.cc
+++ b/services/data_decoder/public/cpp/json_sanitizer_android.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/safe_json/json_sanitizer.h"
+#include "services/data_decoder/public/cpp/json_sanitizer.h"
 
 #include "base/android/jni_string.h"
 #include "base/bind.h"
@@ -16,7 +16,7 @@
 
 using base::android::JavaParamRef;
 
-namespace safe_json {
+namespace data_decoder {
 
 namespace {
 
@@ -106,7 +106,8 @@
 }
 
 // static
-void JsonSanitizer::Sanitize(const std::string& unsafe_json,
+void JsonSanitizer::Sanitize(service_manager::Connector* connector,
+                             const std::string& unsafe_json,
                              const StringCallback& success_callback,
                              const StringCallback& error_callback) {
   // JsonSanitizerAndroid does all its work synchronously, but posts any
@@ -116,4 +117,4 @@
   sanitizer.Sanitize(unsafe_json);
 }
 
-}  // namespace safe_json
+}  // namespace data_decoder
diff --git a/components/safe_json/json_sanitizer_unittest.cc b/services/data_decoder/public/cpp/json_sanitizer_unittest.cc
similarity index 91%
rename from components/safe_json/json_sanitizer_unittest.cc
rename to services/data_decoder/public/cpp/json_sanitizer_unittest.cc
index aac3a49..dbb9824 100644
--- a/components/safe_json/json_sanitizer_unittest.cc
+++ b/services/data_decoder/public/cpp/json_sanitizer_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/safe_json/json_sanitizer.h"
+#include "services/data_decoder/public/cpp/json_sanitizer.h"
 
 #include <memory>
 
@@ -13,14 +13,14 @@
 #include "base/run_loop.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "components/safe_json/safe_json_parser.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if !defined(OS_ANDROID)
-#include "components/safe_json/testing_json_parser.h"
+#include "services/data_decoder/public/cpp/testing_json_parser.h"
 #endif
 
-namespace safe_json {
+namespace data_decoder {
 
 class JsonSanitizerTest : public ::testing::Test {
  public:
@@ -49,7 +49,7 @@
   base::MessageLoop message_loop_;
 
 #if !defined(OS_ANDROID)
-  safe_json::TestingJsonParser::ScopedFactoryOverride factory_override_;
+  TestingJsonParser::ScopedFactoryOverride factory_override_;
 #endif
 
   std::string result_;
@@ -71,8 +71,7 @@
   std::string error;
   std::unique_ptr<base::Value> reparsed = base::JSONReader::ReadAndReturnError(
       result_, base::JSON_PARSE_RFC, &error_code, &error);
-  EXPECT_TRUE(reparsed)
-      << "Invalid result: " << error;
+  EXPECT_TRUE(reparsed) << "Invalid result: " << error;
 
   // The parsed values should be equal.
   EXPECT_TRUE(reparsed->Equals(parsed.get()));
@@ -90,7 +89,7 @@
   error_.clear();
   run_loop_.reset(new base::RunLoop);
   JsonSanitizer::Sanitize(
-      json,
+      nullptr, json,
       base::Bind(&JsonSanitizerTest::OnSuccess, base::Unretained(this)),
       base::Bind(&JsonSanitizerTest::OnError, base::Unretained(this)));
 
@@ -184,4 +183,4 @@
   CheckError("[\"\\ud83f\\udffe\"]");
 }
 
-}  // namespace safe_json
+}  // namespace data_decoder
diff --git a/services/data_decoder/public/cpp/safe_json_parser.cc b/services/data_decoder/public/cpp/safe_json_parser.cc
new file mode 100644
index 0000000..94070c4f
--- /dev/null
+++ b/services/data_decoder/public/cpp/safe_json_parser.cc
@@ -0,0 +1,54 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
+
+#include "build/build_config.h"
+
+#if defined(OS_ANDROID)
+#include "services/data_decoder/public/cpp/safe_json_parser_android.h"
+#else
+#include "services/data_decoder/public/cpp/safe_json_parser_impl.h"
+#endif
+
+namespace data_decoder {
+
+namespace {
+
+SafeJsonParser::Factory g_factory = nullptr;
+
+SafeJsonParser* Create(service_manager::Connector* connector,
+                       const std::string& unsafe_json,
+                       const SafeJsonParser::SuccessCallback& success_callback,
+                       const SafeJsonParser::ErrorCallback& error_callback) {
+  if (g_factory)
+    return g_factory(unsafe_json, success_callback, error_callback);
+
+#if defined(OS_ANDROID)
+  return new SafeJsonParserAndroid(unsafe_json, success_callback,
+                                   error_callback);
+#else
+  return new SafeJsonParserImpl(connector, unsafe_json, success_callback,
+                                error_callback);
+#endif
+}
+
+}  // namespace
+
+// static
+void SafeJsonParser::SetFactoryForTesting(Factory factory) {
+  g_factory = factory;
+}
+
+// static
+void SafeJsonParser::Parse(service_manager::Connector* connector,
+                           const std::string& unsafe_json,
+                           const SuccessCallback& success_callback,
+                           const ErrorCallback& error_callback) {
+  SafeJsonParser* parser =
+      Create(connector, unsafe_json, success_callback, error_callback);
+  parser->Start();
+}
+
+}  // namespace data_decoder
diff --git a/components/safe_json/safe_json_parser.h b/services/data_decoder/public/cpp/safe_json_parser.h
similarity index 68%
rename from components/safe_json/safe_json_parser.h
rename to services/data_decoder/public/cpp/safe_json_parser.h
index 6b66ba43..c1fee50 100644
--- a/components/safe_json/safe_json_parser.h
+++ b/services/data_decoder/public/cpp/safe_json_parser.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_SAFE_JSON_SAFE_JSON_PARSER_H_
-#define COMPONENTS_SAFE_JSON_SAFE_JSON_PARSER_H_
+#ifndef SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_PARSER_H_
+#define SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_PARSER_H_
 
 #include <memory>
 #include <string>
@@ -14,7 +14,11 @@
 class Value;
 }
 
-namespace safe_json {
+namespace service_manager {
+class Connector;
+}
+
+namespace data_decoder {
 
 // SafeJsonParser parses a given JSON safely via a platform-dependent mechanism
 // (like parsing it in a utility process or in a memory-safe environment).
@@ -32,7 +36,11 @@
 
   // Starts parsing the passed in |unsafe_json| and calls either
   // |success_callback| or |error_callback| when finished.
-  static void Parse(const std::string& unsafe_json,
+  // |connector| is the connector provided by the service manager and is used
+  // to retrieve the JSON decoder service. It's commonly retrieved from a
+  // service manager connection context object that the embedder provides.
+  static void Parse(service_manager::Connector* connector,
+                    const std::string& unsafe_json,
                     const SuccessCallback& success_callback,
                     const ErrorCallback& error_callback);
 
@@ -45,6 +53,6 @@
   virtual void Start() = 0;
 };
 
-}  // namespace safe_json
+}  // namespace data_decoder
 
-#endif  // COMPONENTS_SAFE_JSON_SAFE_JSON_PARSER_H_
+#endif  // SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_PARSER_H_
diff --git a/components/safe_json/safe_json_parser_android.cc b/services/data_decoder/public/cpp/safe_json_parser_android.cc
similarity index 85%
rename from components/safe_json/safe_json_parser_android.cc
rename to services/data_decoder/public/cpp/safe_json_parser_android.cc
index 0994ef5..22cd156 100644
--- a/components/safe_json/safe_json_parser_android.cc
+++ b/services/data_decoder/public/cpp/safe_json_parser_android.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/safe_json/safe_json_parser_android.h"
+#include "services/data_decoder/public/cpp/safe_json_parser_android.h"
 
 #include <utility>
 
 #include "base/bind.h"
 #include "base/json/json_reader.h"
 #include "base/values.h"
-#include "components/safe_json/json_sanitizer.h"
+#include "services/data_decoder/public/cpp/json_sanitizer.h"
 
-namespace safe_json {
+namespace data_decoder {
 
 SafeJsonParserAndroid::SafeJsonParserAndroid(
     const std::string& unsafe_json,
@@ -25,6 +25,7 @@
 
 void SafeJsonParserAndroid::Start() {
   JsonSanitizer::Sanitize(
+      /*connector=*/nullptr,  // connector is unused on Android.
       unsafe_json_,
       base::Bind(&SafeJsonParserAndroid::OnSanitizationSuccess,
                  base::Unretained(this)),
@@ -55,4 +56,4 @@
   delete this;
 }
 
-}  // namespace safe_json
+}  // namespace data_decoder
diff --git a/components/safe_json/safe_json_parser_android.h b/services/data_decoder/public/cpp/safe_json_parser_android.h
similarity index 73%
rename from components/safe_json/safe_json_parser_android.h
rename to services/data_decoder/public/cpp/safe_json_parser_android.h
index 520a2db..8c94019 100644
--- a/components/safe_json/safe_json_parser_android.h
+++ b/services/data_decoder/public/cpp/safe_json_parser_android.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_SAFE_JSON_SAFE_JSON_PARSER_ANDROID_H_
-#define COMPONENTS_SAFE_JSON_SAFE_JSON_PARSER_ANDROID_H_
+#ifndef SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_PARSER_ANDROID_H_
+#define SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_PARSER_ANDROID_H_
 
 #include <memory>
 
 #include "base/macros.h"
-#include "components/safe_json/safe_json_parser.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 
-namespace safe_json {
+namespace data_decoder {
 
 class SafeJsonParserAndroid : public SafeJsonParser {
  public:
@@ -36,6 +36,6 @@
   DISALLOW_COPY_AND_ASSIGN(SafeJsonParserAndroid);
 };
 
-}  // namespace safe_json
+}  // namespace data_decoder
 
-#endif   // COMPONENTS_SAFE_JSON_SAFE_JSON_PARSER_ANDROID_H_
+#endif  // SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_PARSER_ANDROID_H_
diff --git a/components/safe_json/safe_json_parser_impl.cc b/services/data_decoder/public/cpp/safe_json_parser_impl.cc
similarity index 73%
rename from components/safe_json/safe_json_parser_impl.cc
rename to services/data_decoder/public/cpp/safe_json_parser_impl.cc
index 9694dad8..c7efaa59 100644
--- a/components/safe_json/safe_json_parser_impl.cc
+++ b/services/data_decoder/public/cpp/safe_json_parser_impl.cc
@@ -2,38 +2,35 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/safe_json/safe_json_parser_impl.h"
+#include "services/data_decoder/public/cpp/safe_json_parser_impl.h"
 
 #include "base/callback.h"
 #include "base/sequenced_task_runner.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/values.h"
-#include "components/strings/grit/components_strings.h"
-#include "content/public/browser/browser_thread.h"
-#include "ui/base/l10n/l10n_util.h"
+#include "services/data_decoder/public/interfaces/constants.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
 
-namespace safe_json {
+namespace data_decoder {
 
-SafeJsonParserImpl::SafeJsonParserImpl(const std::string& unsafe_json,
+SafeJsonParserImpl::SafeJsonParserImpl(service_manager::Connector* connector,
+                                       const std::string& unsafe_json,
                                        const SuccessCallback& success_callback,
                                        const ErrorCallback& error_callback)
     : unsafe_json_(unsafe_json),
       success_callback_(success_callback),
-      error_callback_(error_callback) {}
+      error_callback_(error_callback) {
+  connector->BindInterface(mojom::kServiceName, &json_parser_ptr_);
+}
 
 SafeJsonParserImpl::~SafeJsonParserImpl() = default;
 
 void SafeJsonParserImpl::Start() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  mojo_json_parser_.reset(
-      new content::UtilityProcessMojoClient<mojom::SafeJsonParser>(
-          l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_JSON_PARSER_NAME)));
 
-  mojo_json_parser_->set_error_callback(base::Bind(
+  json_parser_ptr_.set_connection_error_handler(base::Bind(
       &SafeJsonParserImpl::OnConnectionError, base::Unretained(this)));
-  mojo_json_parser_->Start();
-
-  mojo_json_parser_->service()->Parse(
+  json_parser_ptr_->Parse(
       std::move(unsafe_json_),
       base::Bind(&SafeJsonParserImpl::OnParseDone, base::Unretained(this)));
 }
@@ -42,7 +39,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Shut down the utility process.
-  mojo_json_parser_.reset();
+  json_parser_ptr_.reset();
 
   ReportResults(nullptr, "Connection error with the json parser process.");
 }
@@ -52,7 +49,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Shut down the utility process.
-  mojo_json_parser_.reset();
+  json_parser_ptr_.reset();
 
   ReportResults(std::move(result), error.value_or(""));
 }
@@ -73,4 +70,4 @@
   delete this;
 }
 
-}  // namespace safe_json
+}  // namespace data_decoder
diff --git a/components/safe_json/safe_json_parser_impl.h b/services/data_decoder/public/cpp/safe_json_parser_impl.h
similarity index 68%
rename from components/safe_json/safe_json_parser_impl.h
rename to services/data_decoder/public/cpp/safe_json_parser_impl.h
index 54da8dc..a17a91ae 100644
--- a/components/safe_json/safe_json_parser_impl.h
+++ b/services/data_decoder/public/cpp/safe_json_parser_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_SAFE_JSON_SAFE_JSON_PARSER_IMPL_H_
-#define COMPONENTS_SAFE_JSON_SAFE_JSON_PARSER_IMPL_H_
+#ifndef SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_PARSER_IMPL_H_
+#define SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_PARSER_IMPL_H_
 
 #include <memory>
 #include <string>
@@ -12,19 +12,23 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread_checker.h"
-#include "components/safe_json/public/interfaces/safe_json.mojom.h"
-#include "components/safe_json/safe_json_parser.h"
-#include "content/public/browser/utility_process_mojo_client.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
+#include "services/data_decoder/public/interfaces/json_parser.mojom.h"
 
 namespace base {
 class Value;
 }
 
-namespace safe_json {
+namespace service_manager {
+class Connector;
+}
+
+namespace data_decoder {
 
 class SafeJsonParserImpl : public SafeJsonParser {
  public:
-  SafeJsonParserImpl(const std::string& unsafe_json,
+  SafeJsonParserImpl(service_manager::Connector* connector,
+                     const std::string& unsafe_json,
                      const SuccessCallback& success_callback,
                      const ErrorCallback& error_callback);
 
@@ -50,14 +54,13 @@
   SuccessCallback success_callback_;
   ErrorCallback error_callback_;
 
-  std::unique_ptr<content::UtilityProcessMojoClient<mojom::SafeJsonParser>>
-      mojo_json_parser_;
+  mojom::JsonParserPtr json_parser_ptr_;
 
   SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(SafeJsonParserImpl);
 };
 
-}  // namespace safe_json
+}  // namespace data_decoder
 
-#endif  // COMPONENTS_SAFE_JSON_SAFE_JSON_PARSER_IMPL_H_
+#endif  // SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_PARSER_IMPL_H_
diff --git a/components/safe_json/testing_json_parser.cc b/services/data_decoder/public/cpp/testing_json_parser.cc
similarity index 93%
rename from components/safe_json/testing_json_parser.cc
rename to services/data_decoder/public/cpp/testing_json_parser.cc
index c2f9639a..c3eac72 100644
--- a/components/safe_json/testing_json_parser.cc
+++ b/services/data_decoder/public/cpp/testing_json_parser.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/safe_json/testing_json_parser.h"
+#include "services/data_decoder/public/cpp/testing_json_parser.h"
 
 #include <memory>
 
@@ -14,7 +14,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 
-namespace safe_json {
+namespace data_decoder {
 
 namespace {
 
@@ -58,4 +58,4 @@
                        : base::Bind(error_callback_, error));
 }
 
-}  // namespace
+}  // namespace data_decoder
diff --git a/components/safe_json/testing_json_parser.h b/services/data_decoder/public/cpp/testing_json_parser.h
similarity index 79%
rename from components/safe_json/testing_json_parser.h
rename to services/data_decoder/public/cpp/testing_json_parser.h
index 4acde1f..f75b9f7 100644
--- a/components/safe_json/testing_json_parser.h
+++ b/services/data_decoder/public/cpp/testing_json_parser.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_SAFE_JSON_TESTING_JSON_PARSER_H_
-#define COMPONENTS_SAFE_JSON_TESTING_JSON_PARSER_H_
+#ifndef SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_TESTING_JSON_PARSER_H_
+#define SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_TESTING_JSON_PARSER_H_
 
 #include "base/macros.h"
-#include "components/safe_json/safe_json_parser.h"
+#include "services/data_decoder/public/cpp/safe_json_parser.h"
 
-namespace safe_json {
+namespace data_decoder {
 
 // An implementation of SafeJsonParser that parses JSON in process. This can be
 // used in unit tests to avoid having to set up the multiprocess infrastructure
@@ -44,6 +44,6 @@
   DISALLOW_COPY_AND_ASSIGN(TestingJsonParser);
 };
 
-}  // namespace
+}  // namespace data_decoder
 
-#endif  // COMPONENTS_SAFE_JSON_TESTING_JSON_PARSER_H_
+#endif  // SERVICES_DATA_DECODER_PUBLIC_CPP_SAFE_JSON_TESTING_JSON_PARSER_H_
diff --git a/components/safe_json/testing_json_parser_unittest.cc b/services/data_decoder/public/cpp/testing_json_parser_unittest.cc
similarity index 87%
rename from components/safe_json/testing_json_parser_unittest.cc
rename to services/data_decoder/public/cpp/testing_json_parser_unittest.cc
index 63f638fa..f6df1e8 100644
--- a/components/safe_json/testing_json_parser_unittest.cc
+++ b/services/data_decoder/public/cpp/testing_json_parser_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/safe_json/testing_json_parser.h"
+#include "services/data_decoder/public/cpp/testing_json_parser.h"
 
 #include <memory>
 
@@ -13,7 +13,7 @@
 #include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace safe_json {
+namespace data_decoder {
 namespace {
 
 const char kTestJson[] = "{\"key\":2}";
@@ -22,7 +22,7 @@
  public:
   void Parse(const std::string& input) {
     base::RunLoop run_loop;
-    SafeJsonParser::Parse(input,
+    SafeJsonParser::Parse(/* connector=*/nullptr, input,
                           base::Bind(&SuccessCallback, base::Unretained(this),
                                      run_loop.QuitClosure()),
                           base::Bind(&ErrorCallback, base::Unretained(this),
@@ -30,8 +30,8 @@
     run_loop.Run();
   }
 
-  bool did_success() { return did_success_; }
-  bool did_error() { return did_error_; }
+  bool did_success() const { return did_success_; }
+  bool did_error() const { return did_error_; }
 
  private:
   static void SuccessCallback(TestingJsonParserTest* test,
@@ -76,4 +76,4 @@
 }
 
 }  // namespace
-}  // namespace safe_json
+}  // namespace data_decoder
diff --git a/services/data_decoder/public/interfaces/BUILD.gn b/services/data_decoder/public/interfaces/BUILD.gn
index 9d79f22e..7af99699 100644
--- a/services/data_decoder/public/interfaces/BUILD.gn
+++ b/services/data_decoder/public/interfaces/BUILD.gn
@@ -7,6 +7,7 @@
 mojom("interfaces") {
   sources = [
     "image_decoder.mojom",
+    "json_parser.mojom",
   ]
 
   public_deps = [
diff --git a/components/safe_json/public/interfaces/safe_json.mojom b/services/data_decoder/public/interfaces/json_parser.mojom
similarity index 84%
rename from components/safe_json/public/interfaces/safe_json.mojom
rename to services/data_decoder/public/interfaces/json_parser.mojom
index c5c5d74..502a16b 100644
--- a/components/safe_json/public/interfaces/safe_json.mojom
+++ b/services/data_decoder/public/interfaces/json_parser.mojom
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module safe_json.mojom;
+module data_decoder.mojom;
 
 import "mojo/common/values.mojom";
 
-interface SafeJsonParser {
+interface JsonParser {
   Parse(string json) => (mojo.common.mojom.Value? result, string? error);
 };
diff --git a/services/resource_coordinator/coordination_unit/coordination_unit_introspector_impl.cc b/services/resource_coordinator/coordination_unit/coordination_unit_introspector_impl.cc
index f5d2b53..5890753f 100644
--- a/services/resource_coordinator/coordination_unit/coordination_unit_introspector_impl.cc
+++ b/services/resource_coordinator/coordination_unit/coordination_unit_introspector_impl.cc
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "base/process/process_handle.h"
+#include "base/time/time.h"
 #include "services/resource_coordinator/coordination_unit/coordination_unit_base.h"
 #include "services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h"
 #include "services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h"
@@ -33,6 +34,12 @@
     process_info->pid = pid;
     DCHECK_NE(base::kNullProcessId, process_info->pid);
 
+    int64_t launch_time;
+    if (process_cu->GetProperty(mojom::PropertyType::kLaunchTime,
+                                &launch_time)) {
+      process_info->launch_time = base::Time::FromTimeT(launch_time);
+    }
+
     std::set<CoordinationUnitBase*> page_cus =
         process_cu->GetAssociatedCoordinationUnitsOfType(
             CoordinationUnitType::kPage);
diff --git a/services/resource_coordinator/public/interfaces/coordination_unit_introspector.mojom b/services/resource_coordinator/public/interfaces/coordination_unit_introspector.mojom
index e3bdac4b..3767566c 100644
--- a/services/resource_coordinator/public/interfaces/coordination_unit_introspector.mojom
+++ b/services/resource_coordinator/public/interfaces/coordination_unit_introspector.mojom
@@ -18,6 +18,7 @@
 struct ProcessInfo {
   mojo.common.mojom.ProcessId pid;
   array<PageInfo> page_infos;
+  mojo.common.mojom.Time? launch_time;
 };
 
 interface CoordinationUnitIntrospector {
diff --git a/services/resource_coordinator/public/interfaces/signals.mojom b/services/resource_coordinator/public/interfaces/signals.mojom
index 11f3ad76..36d3e97 100644
--- a/services/resource_coordinator/public/interfaces/signals.mojom
+++ b/services/resource_coordinator/public/interfaces/signals.mojom
@@ -23,6 +23,7 @@
   kAudible,
   kCPUUsage,
   kExpectedTaskQueueingDuration,
+  kLaunchTime,
   // Network is considered almost idle when there's no more than 2 network
   // connections.
   kNetworkAlmostIdle,
diff --git a/services/service_manager/background/background_service_manager.cc b/services/service_manager/background/background_service_manager.cc
index 50c4953..0a71196 100644
--- a/services/service_manager/background/background_service_manager.cc
+++ b/services/service_manager/background/background_service_manager.cc
@@ -25,19 +25,6 @@
 #include "services/service_manager/standalone/context.h"
 
 namespace service_manager {
-namespace {
-
-// Calls |callback| on |callback_task_runner|'s thread.
-void CallCallbackWithIdentity(
-    const scoped_refptr<base::TaskRunner> callback_task_runner,
-    const base::Callback<void(const Identity&)>& callback,
-    const Identity& identity) {
-  DCHECK(callback);
-  DCHECK(identity.IsValid());
-  callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, identity));
-}
-
-}  // namespace
 
 BackgroundServiceManager::BackgroundServiceManager(
     service_manager::ServiceProcessLauncherDelegate* launcher_delegate,
@@ -82,29 +69,6 @@
                  base::Passed(&pid_receiver_request)));
 }
 
-void BackgroundServiceManager::SetInstanceQuitCallback(
-    base::Callback<void(const Identity&)> callback) {
-  DCHECK(callback);
-  // Hop to the background thread. The provided callback will be called on
-  // whichever thread called this function.
-  background_thread_.task_runner()->PostTask(
-      FROM_HERE,
-      base::Bind(
-          &BackgroundServiceManager::SetInstanceQuitCallbackOnBackgroundThread,
-          base::Unretained(this), base::ThreadTaskRunnerHandle::Get(),
-          callback));
-}
-
-void BackgroundServiceManager::SetInstanceQuitCallbackOnBackgroundThread(
-    const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner,
-    const base::Callback<void(const Identity&)>& callback) {
-  DCHECK(callback_task_runner);
-  DCHECK(callback);
-  // Calls |callback| with the identity of the service that is quitting.
-  context_->service_manager()->SetInstanceQuitCallback(
-      base::Bind(&CallCallbackWithIdentity, callback_task_runner, callback));
-}
-
 void BackgroundServiceManager::InitializeOnBackgroundThread(
     service_manager::ServiceProcessLauncherDelegate* launcher_delegate,
     std::unique_ptr<base::Value> catalog_contents) {
diff --git a/services/service_manager/background/background_service_manager.h b/services/service_manager/background/background_service_manager.h
index 551f673..ef62ffa3 100644
--- a/services/service_manager/background/background_service_manager.h
+++ b/services/service_manager/background/background_service_manager.h
@@ -7,18 +7,15 @@
 
 #include <memory>
 
-#include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/threading/thread.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "services/service_manager/public/cpp/identity.h"
 #include "services/service_manager/public/interfaces/connector.mojom.h"
 #include "services/service_manager/public/interfaces/service.mojom.h"
 #include "services/service_manager/runner/host/service_process_launcher_delegate.h"
 
 namespace base {
-class SingleThreadTaskRunner;
 class WaitableEvent;
 }
 
@@ -50,12 +47,6 @@
                        mojom::ServicePtr service,
                        mojom::PIDReceiverRequest pid_receiver_request);
 
-  // Provide a callback to be notified whenever a service is destroyed.
-  // Typically the creator of BackgroundServiceManager will use this to shut
-  // down when some set of services it created is destroyed. The |callback| is
-  // called on whichever thread called this function.
-  void SetInstanceQuitCallback(base::Callback<void(const Identity&)> callback);
-
  private:
   void InitializeOnBackgroundThread(
       service_manager::ServiceProcessLauncherDelegate* launcher_delegate,
@@ -66,10 +57,6 @@
       const Identity& identity,
       mojom::ServicePtrInfo service_info,
       mojom::PIDReceiverRequest pid_receiver_request);
-  void SetInstanceQuitCallbackOnBackgroundThread(
-      const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
-      const base::Callback<void(const Identity&)>& callback);
-  void OnInstanceQuitOnBackgroundThread(const Identity& identity);
 
   base::Thread background_thread_;
 
diff --git a/services/service_manager/background/tests/background_service_manager_unittest.cc b/services/service_manager/background/tests/background_service_manager_unittest.cc
index a9de8b9..c1514a3 100644
--- a/services/service_manager/background/tests/background_service_manager_unittest.cc
+++ b/services/service_manager/background/tests/background_service_manager_unittest.cc
@@ -66,41 +66,5 @@
   EXPECT_TRUE(got_result);
 }
 
-// The out param cannot be last due to base::Bind() currying.
-void QuitCallback(bool* callback_called,
-                  const base::Closure& quit_closure,
-                  const Identity& identity) {
-  EXPECT_EQ(kAppName, identity.name());
-  *callback_called = true;
-  quit_closure.Run();
-}
-
-// Verifies that quitting a service invokes the quit callback.
-TEST(BackgroundServiceManagerTest, SetInstanceQuitCallback) {
-  BackgroundServiceManager background_service_manager(nullptr, nullptr);
-  base::MessageLoop message_loop;
-  mojom::ServicePtr service;
-  ServiceContext service_context(base::MakeUnique<ServiceImpl>(),
-                                 mojo::MakeRequest(&service));
-  background_service_manager.RegisterService(
-      Identity(kTestName, mojom::kRootUserID), std::move(service), nullptr);
-
-  mojom::TestServicePtr test_service;
-  service_context.connector()->BindInterface(kAppName, &test_service);
-
-  // Set a callback for when the service quits that will quit |run_loop|.
-  base::RunLoop run_loop;
-  bool callback_called = false;
-  background_service_manager.SetInstanceQuitCallback(
-      base::Bind(&QuitCallback, &callback_called, run_loop.QuitClosure()));
-
-  // Ask the service to quit itself.
-  test_service->Quit();
-  run_loop.Run();
-
-  // The run loop was quit by the callback and not by something else.
-  EXPECT_TRUE(callback_called);
-}
-
 }  // namespace
 }  // namespace service_manager
diff --git a/services/service_manager/embedder/main.cc b/services/service_manager/embedder/main.cc
index 87ac6f0..cd6e88f5 100644
--- a/services/service_manager/embedder/main.cc
+++ b/services/service_manager/embedder/main.cc
@@ -219,18 +219,6 @@
   base::debug::WaitForDebugger(120, true);
 }
 
-// Quits |run_loop| if the |identity| of the quitting service is critical to the
-// system (e.g. the window manager). Used in the main process.
-void OnInstanceQuit(MainDelegate* delegate,
-                    base::RunLoop* run_loop,
-                    int* exit_code,
-                    const service_manager::Identity& identity) {
-  if (delegate->ShouldTerminateServiceManagerOnInstanceQuit(identity,
-                                                            exit_code)) {
-    run_loop->Quit();
-  }
-}
-
 int RunServiceManager(MainDelegate* delegate) {
   NonEmbedderProcessInit();
 
@@ -251,10 +239,6 @@
       &service_process_launcher_delegate, delegate->CreateServiceCatalog());
 
   base::RunLoop run_loop;
-  int exit_code = 0;
-  background_service_manager.SetInstanceQuitCallback(
-      base::Bind(&OnInstanceQuit, delegate, &run_loop, &exit_code));
-
   delegate->OnServiceManagerInitialized(run_loop.QuitClosure(),
                                         &background_service_manager);
   run_loop.Run();
@@ -262,7 +246,7 @@
   ipc_thread.Stop();
   base::TaskScheduler::GetInstance()->Shutdown();
 
-  return exit_code;
+  return 0;
 }
 
 void InitializeResources() {
diff --git a/services/service_manager/embedder/main_delegate.cc b/services/service_manager/embedder/main_delegate.cc
index 08804b4..11b7c3fa 100644
--- a/services/service_manager/embedder/main_delegate.cc
+++ b/services/service_manager/embedder/main_delegate.cc
@@ -39,12 +39,6 @@
     const Identity& identity,
     base::CommandLine* command_line) {}
 
-bool MainDelegate::ShouldTerminateServiceManagerOnInstanceQuit(
-    const Identity& identity,
-    int* exit_code) {
-  return false;
-}
-
 void MainDelegate::OnServiceManagerInitialized(
     const base::Closure& quit_closure,
     BackgroundServiceManager* service_manager) {}
diff --git a/services/service_manager/embedder/main_delegate.h b/services/service_manager/embedder/main_delegate.h
index 4b29a413..0c6d11a 100644
--- a/services/service_manager/embedder/main_delegate.h
+++ b/services/service_manager/embedder/main_delegate.h
@@ -85,13 +85,6 @@
   virtual void AdjustServiceProcessCommandLine(const Identity& identity,
                                                base::CommandLine* command_line);
 
-  // Allows the embedder to terminate its Service Manager if any specific
-  // service instances quit. If this returns |true|, |*exit_code| will be
-  // returned from the Service Manager's process on exit.
-  virtual bool ShouldTerminateServiceManagerOnInstanceQuit(
-      const Identity& identity,
-      int* exit_code);
-
   // Allows the embedder to perform arbitrary initialization within the Service
   // Manager process immediately before the Service Manager runs its main loop.
   //
diff --git a/services/service_manager/sandbox/mac/renderer.sb b/services/service_manager/sandbox/mac/renderer.sb
index 88ea7847..4a5d5cc 100644
--- a/services/service_manager/sandbox/mac/renderer.sb
+++ b/services/service_manager/sandbox/mac/renderer.sb
@@ -40,6 +40,9 @@
   (allow file-read-data (subpath "/usr/share/zoneinfo.default"))
   (allow file-read-data (subpath "/usr/share/zoneinfo")))
 
+; Allow access to the metadata of the /etc symlink.
+(allow file-read-metadata (path "/etc"))
+; Allow access to the symlink target as well.
 (allow file-read-metadata (path "/private/etc"))
 
 ; https://crbug.com/605840
diff --git a/services/ui/ime/ime_unittest.cc b/services/ui/ime/ime_unittest.cc
index 4c68af5d..9586a97 100644
--- a/services/ui/ime/ime_unittest.cc
+++ b/services/ui/ime/ime_unittest.cc
@@ -44,7 +44,6 @@
       DispatchKeyEventPostIMECallback callback) override {
     std::move(callback).Run(false);
   }
-  void SetCandidateWindowVisible(bool visible) override {}
 
   mojo::Binding<ui::mojom::TextInputClient> binding_;
   std::unique_ptr<base::RunLoop> run_loop_;
diff --git a/services/ui/public/interfaces/ime/ime.mojom b/services/ui/public/interfaces/ime/ime.mojom
index a71fb1b..b9b8169e 100644
--- a/services/ui/public/interfaces/ime/ime.mojom
+++ b/services/ui/public/interfaces/ime/ime.mojom
@@ -177,9 +177,6 @@
   // Dispatch a key event skipping IME. Returns true if event was consumed.
   DispatchKeyEventPostIME(ui.mojom.Event event) => (bool stopped_propagation);
 
-  // Sending visibility status of candidate pop up window to client.
-  SetCandidateWindowVisible(bool visible);
-
   // TODO(moshayedi): Add functions corresponding to ui::TextInputClient for:
   // - Input context information
   // - Document content operations
diff --git a/testing/buildbot/filters/ash_unittests_mash.filter b/testing/buildbot/filters/ash_unittests_mash.filter
index dce8a67..1174b57d 100644
--- a/testing/buildbot/filters/ash_unittests_mash.filter
+++ b/testing/buildbot/filters/ash_unittests_mash.filter
@@ -342,6 +342,9 @@
 -WorkspaceLayoutManagerKeyboardTest.IgnoreWorkAreaChangeinNonStickyMode
 # TODO: fix these. They fail because DeviceDataManager isn't created.
 # http://crbug.com/734812.
+-PaletteTrayTestWithInternalStylus.WelcomeBubbleShownOnEject
+-PaletteTrayTestWithInternalStylus.WelcomeBubbleNotShownIfShownBefore
+-PaletteTrayTestWithInternalStylus.WelcomeBubbleNotShownIfAutoOpenPaletteTrue
 -TrayIMETest.HidesOnA11yEnabled
 -TrayIMETest.PerformActionOnDetailedView
 -VirtualKeyboardAlwaysOnTopControllerTest.NotifyKeyboardBoundsChanged
diff --git a/testing/buildbot/filters/ash_unittests_mus.filter b/testing/buildbot/filters/ash_unittests_mus.filter
index 97fcb0b..3a5287f0 100644
--- a/testing/buildbot/filters/ash_unittests_mus.filter
+++ b/testing/buildbot/filters/ash_unittests_mus.filter
@@ -1,5 +1,8 @@
 # TODO: fix these. They fail because DeviceDataManager isn't created.
 # http://crbug.com/734812.
+-PaletteTrayTestWithInternalStylus.WelcomeBubbleShownOnEject
+-PaletteTrayTestWithInternalStylus.WelcomeBubbleNotShownIfShownBefore
+-PaletteTrayTestWithInternalStylus.WelcomeBubbleNotShownIfAutoOpenPaletteTrue
 -TouchCalibratorControllerTest.CustomCalibration
 -TouchCalibratorControllerTest.CustomCalibrationInvalidTouchId
 -TouchCalibratorControllerTest.TouchDeviceIdIsSet
diff --git a/testing/buildbot/filters/mus.browser_tests.filter b/testing/buildbot/filters/mus.browser_tests.filter
index 46ead00a..777bc35 100644
--- a/testing/buildbot/filters/mus.browser_tests.filter
+++ b/testing/buildbot/filters/mus.browser_tests.filter
@@ -34,3 +34,6 @@
 -WebViewTests/WebViewSizeTest.Shim_TestAutosizeRemoveAttributes/0
 -WebViewTests/WebViewSizeTest.Shim_TestAutosizeRemoveAttributes/1
 -WebViewTests/WebViewTest.InterstitialPageFocusedWidget/1
+
+# content::WaitForChildFrameSurfaceReady unsupported, https://crbug.com/774269.
+-WebViewTests/WebViewTest.ReloadAfterCrash/1
diff --git a/testing/buildbot/filters/site-per-process.browser_tests.filter b/testing/buildbot/filters/site-per-process.browser_tests.filter
index 06787d05..43e7746 100644
--- a/testing/buildbot/filters/site-per-process.browser_tests.filter
+++ b/testing/buildbot/filters/site-per-process.browser_tests.filter
@@ -6,21 +6,10 @@
 -PrerenderBrowserTest.PrerenderLocationReplaceGWSHistograms
 -ProcessManagementTest.ExtensionProcessBalancing
 -ProcessManagementTest.ProcessOverflow
--RedirectTest.ClientEmptyReferer
--ReferrerPolicyTest.HttpsRedirect
 
 # crbug.com/671734: WebNavigationApiTest.ServerRedirectSingleProcess from
 # fails with --site-per-process
 -WebNavigationApiTest.ServerRedirectSingleProcess
 
-# crbug.com/671712: All 4 IsolatedAppTest tests time out with --site-per-process
+# crbug.com/671712: CookieIsolation test fails with --site-per-process
 -IsolatedAppTest.CookieIsolation
--IsolatedAppTest.CrossProcessClientRedirect
--IsolatedAppTest.IsolatedAppProcessModel
--IsolatedAppTest.SubresourceCookieIsolation
-
-# crbug.com/669299: Wrong view frame source with --site-per-process
--ChromeNavigationBrowserTest.TestViewFrameSource
-
-# crbug.com/670362: Flaky failure (expected MouseDown not found)
--DevToolsPixelOutputTests.TestLatencyInfoInstrumentation
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index fa61f3ad..907b21d 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -305,6 +305,21 @@
             ]
         }
     ],
+    "AndroidSigninPromos": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "AndroidSigninPromos"
+                    ]
+                }
+            ]
+        }
+    ],
     "AndroidSpellChecker": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index caf91fe..7534d9d1 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -3766,5 +3766,4 @@
 
 # Sheriff failures 2017-10-13
 crbug.com/774437 [ Win10 ] paint/invalidation/selection-partial-invalidation-between-blocks.html [ Pass Failure ]
-crbug.com/773957 paint/invalidation/raster-under-invalidation-checking.html [ Failure Pass ]
 crbug.com/774463 [ Win7 Debug ] fast/events/autoscroll-should-not-stop-on-keypress.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLength-px-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLength-px-expected.txt
new file mode 100644
index 0000000..c5846bc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLength-px-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+PASS SVGLength, converting from 'px' to other units (detached), unitless
+FAIL SVGLength, converting from 'px' to other units (detached), percentage Failed to execute 'convertToSpecifiedUnits' on 'SVGLength': Could not resolve relative length.
+FAIL SVGLength, converting from 'px' to other units (detached), ems Failed to execute 'convertToSpecifiedUnits' on 'SVGLength': Could not resolve relative length.
+FAIL SVGLength, converting from 'px' to other units (detached), exs Failed to execute 'convertToSpecifiedUnits' on 'SVGLength': Could not resolve relative length.
+PASS SVGLength, converting from 'px' to other units (detached), cm
+PASS SVGLength, converting from 'px' to other units (detached), mm
+PASS SVGLength, converting from 'px' to other units (detached), in
+PASS SVGLength, converting from 'px' to other units (detached), pt
+PASS SVGLength, converting from 'px' to other units (detached), pc
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGLength-px-with-context.html b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLength-px-with-context.html
similarity index 62%
rename from third_party/WebKit/LayoutTests/svg/dom/SVGLength-px-with-context.html
rename to third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLength-px-with-context.html
index f2ed394c..c92ec7c 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGLength-px-with-context.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLength-px-with-context.html
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML>
 <title>SVGLength, converting from 'px' to other units (attached)</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <p></p>
 <script>
 var cssPixelsPerInch = 96;
@@ -20,9 +20,7 @@
   window.length = rectElement.x.baseVal;
   window.svgWidth = svgElement.width.baseVal.value;
   window.svgHeight = svgElement.height.baseVal.value;
-  window.fontSize = parseInt(rectElement.style.fontSize);
-  // TODO(shanmuga.m) : // Since calculateXHeight() triggers force layout, relative length units are resolved.
-  // So make convertToSpecifiedUnits to update pending style sheet and do relayout if needed.
+  window.fontSize = 12;
   window.xHeight = calculateXHeight();
 
   function calculateXHeight() {
@@ -47,82 +45,82 @@
 }, document.title + ", unitless");
 
 test(function() {
-  length.valueAsString = "2px";
+  length.valueAsString = "3px";
   length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PERCENTAGE);
-  var referenceValue = Number(2 / svgWidth * 100).toFixed(5);
+  var referenceValue = 3 / svgWidth * 100;
   assert_equals(length.valueAsString, referenceValue + "%");
-  assert_equals(length.valueInSpecifiedUnits.toFixed(5), referenceValue);
-  assert_equals(length.value.toFixed(1), "2.0");
+  assert_equals(length.valueInSpecifiedUnits, referenceValue);
+  assert_equals(length.value, 3);
   assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_PERCENTAGE);
 }, document.title + ", percentage");
 
 test(function() {
-  length.valueAsString = "2px";
+  length.valueAsString = "6px";
   length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_EMS);
-  var referenceValue = Number(2 / fontSize).toFixed(6);
+  var referenceValue = 6 / fontSize;
   assert_equals(length.valueAsString, referenceValue + "em");
-  assert_equals(length.valueInSpecifiedUnits.toFixed(6), referenceValue);
-  assert_equals(length.value.toFixed(1), "2.0");
+  assert_equals(length.valueInSpecifiedUnits, referenceValue);
+  assert_equals(length.value, 6);
   assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_EMS);
 }, document.title + ", ems");
 
 test(function() {
   length.valueAsString = "2px";
   length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_EXS);
-  var referenceValue = Number(2 / xHeight).toFixed(1);
+  var referenceValue = 2 / xHeight;
   // Don't check valueAsString here, it's unreliable across browsers.
-  assert_equals(length.valueInSpecifiedUnits.toFixed(1), referenceValue);
-  assert_equals(length.value.toFixed(1), "2.0");
+  assert_approx_equals(length.valueInSpecifiedUnits, referenceValue, 0.1);
+  assert_approx_equals(length.value, 2.0, 0.1);
   assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_EXS);
 }, document.title + " , exs");
 
 test(function() {
-  length.valueAsString = "2px";
+  length.valueAsString = "48px";
   length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_CM);
-  var referenceValue = Number(2 * 2.54 / cssPixelsPerInch).toFixed(7);
-  assert_equals(length.valueAsString, referenceValue + "cm");
-  assert_equals(length.valueInSpecifiedUnits.toFixed(7), referenceValue);
-  assert_equals(length.value.toFixed(1), "2.0");
+  var referenceValue = 48 * 2.54 / cssPixelsPerInch;
+  assert_equals(length.valueAsString, referenceValue.toFixed(2) + "cm");
+  assert_approx_equals(length.valueInSpecifiedUnits, referenceValue, 0.001);
+  assert_equals(length.value, 48);
   assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_CM);
 }, document.title + ", cm");
 
 test(function() {
-  length.valueAsString = "2px";
+  length.valueAsString = "48px";
   length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_MM);
-  var referenceValue = Number(2 * 25.4 / cssPixelsPerInch).toFixed(6);
-  assert_equals(length.valueAsString, referenceValue + "mm");
-  assert_equals(length.valueInSpecifiedUnits.toFixed(6), referenceValue);
-  assert_equals(length.value.toFixed(1), "2.0");
+  var referenceValue = 48 * 25.4 / cssPixelsPerInch;
+  assert_equals(length.valueAsString, referenceValue.toFixed(1) + "mm");
+  assert_approx_equals(length.valueInSpecifiedUnits, referenceValue, 0.001);
+  assert_equals(length.value, 48);
   assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_MM);
 }, document.title + ", mm");
 
 test(function() {
-  length.valueAsString = "2px";
+  length.valueAsString = "48px";
   length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_IN);
-  var referenceValue = Number(2 / cssPixelsPerInch).toFixed(7);
+  var referenceValue = 48 / cssPixelsPerInch;
   assert_equals(length.valueAsString, referenceValue + "in");
-  assert_equals(length.valueInSpecifiedUnits.toFixed(7), referenceValue);
-  assert_equals(length.value.toFixed(1), "2.0");
+  assert_equals(length.valueInSpecifiedUnits, referenceValue);
+  assert_equals(length.value, 48);
   assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_IN);
 }, document.title + ", in");
 
 test(function() {
-  length.valueAsString = "2px";
+  length.valueAsString = "4px";
   length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PT);
-  var referenceValue = Number(2 / cssPixelsPerInch * 72);
+  var referenceValue = 4 / cssPixelsPerInch * 72;
   assert_equals(length.valueAsString, referenceValue + "pt");
   assert_equals(length.valueInSpecifiedUnits, referenceValue);
-  assert_equals(length.value.toFixed(1), "2.0");
+  assert_equals(length.value, 4);
   assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_PT);
 }, document.title + ", pt");
 
 test(function() {
-  length.valueAsString = "2px";
+  length.valueAsString = "16px";
   length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PC);
-  var referenceValue = Number(2 / cssPixelsPerInch * 6).toFixed(3);
+  var referenceValue = 16 / cssPixelsPerInch * 6;
   // Don't check valueAsString here, it's unreliable across browsers.
-  assert_equals(length.valueInSpecifiedUnits.toFixed(3), referenceValue);
-  assert_equals(length.value.toFixed(1), "2.0");
+  assert_equals(length.valueInSpecifiedUnits, referenceValue);
+  assert_equals(length.value, 16);
   assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_PC);
 }, document.title + ", pc");
 </script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLength-px.html b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLength-px.html
new file mode 100644
index 0000000..a91e4e9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLength-px.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML>
+<title>SVGLength, converting from 'px' to other units (detached)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<p></p>
+<script>
+var cssPixelsPerInch = 96;
+setup(function() {
+  window.svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
+  svgElement.setAttribute("style", "visibility: hidden; font-size: initial; font-family: initial;");
+  window.fontSize = parseInt(getComputedStyle(svgElement).fontSize);
+  window.xHeight = calculateXHeight();
+
+  function calculateXHeight() {
+    // Crude hack to calculate the x-height
+    var divElement = document.createElement("div");
+    divElement.setAttribute("style", "height: 1ex; font-size: initial; font-family: initial;");
+    var pElement = document.querySelector("p");
+    pElement.appendChild(divElement);
+    var xHeight = divElement.offsetHeight;
+    pElement.removeChild(divElement);
+    return xHeight;
+  }
+});
+
+test(function() {
+  var length = svgElement.createSVGLength();
+  length.valueAsString = "2px";
+  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_NUMBER);
+  assert_equals(length.valueAsString, "2");
+  assert_equals(length.value, 2);
+  assert_equals(length.valueInSpecifiedUnits, 2);
+  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
+}, document.title + ", unitless");
+
+test(function() {
+  var length = svgElement.createSVGLength();
+  length.valueAsString = "2px";
+  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PERCENTAGE);
+  assert_equals(length.valueAsString, "2%");
+  assert_equals(length.value, 2);
+  assert_equals(length.valueInSpecifiedUnits, 2);
+  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_PERCENTAGE);
+}, document.title + ", percentage");
+
+test(function() {
+  var length = svgElement.createSVGLength();
+  length.valueAsString = "2px";
+  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_EMS);
+  var referenceValue = 2 / fontSize;
+  assert_equals(length.valueAsString, referenceValue.toFixed(6) + "em");
+  assert_approx_equals(length.valueInSpecifiedUnits, referenceValue, 0.1);
+  assert_approx_equals(length.value, 2.0, 0.1);
+  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_EMS);
+}, document.title + ", ems");
+
+test(function() {
+  var length = svgElement.createSVGLength();
+  length.valueAsString = "2px";
+  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_EXS);
+  var referenceValue = 2 / xHeight;
+  // Don't check valueAsString here, it's unreliable across browsers.
+  assert_approx_equals(length.valueInSpecifiedUnits, referenceValue, 0.1);
+  assert_approx_equals(length.value, 2.0, 0.1);
+  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_EXS);
+}, document.title + ", exs");
+
+test(function() {
+  var length = svgElement.createSVGLength();
+  length.valueAsString = "48px";
+  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_CM);
+  var referenceValue = 48 * 2.54 / cssPixelsPerInch;
+  assert_equals(length.valueAsString, referenceValue.toFixed(2) + "cm");
+  assert_approx_equals(length.valueInSpecifiedUnits, referenceValue, 0.01);
+  assert_equals(length.value, 48);
+  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_CM);
+}, document.title + ", cm");
+
+test(function() {
+  var length = svgElement.createSVGLength();
+  length.valueAsString = "48px";
+  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_MM);
+  var referenceValue = 48 * 25.4 / cssPixelsPerInch;
+  assert_equals(length.valueAsString, referenceValue.toFixed(1) + "mm");
+  assert_approx_equals(length.valueInSpecifiedUnits, referenceValue, 0.01);
+  assert_equals(length.value, 48);
+  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_MM);
+}, document.title + ", mm");
+
+test(function() {
+  var length = svgElement.createSVGLength();
+  length.valueAsString = "48px";
+  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_IN);
+  var referenceValue = 48 / cssPixelsPerInch;
+  assert_equals(length.valueAsString, referenceValue + "in");
+  assert_equals(length.valueInSpecifiedUnits, referenceValue);
+  assert_equals(length.value, 48);
+  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_IN);
+}, document.title + ", in");
+
+test(function() {
+  var length = svgElement.createSVGLength();
+  length.valueAsString = "4px";
+  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PT);
+  var referenceValue = 4 / cssPixelsPerInch * 72;
+  assert_equals(length.valueAsString, referenceValue + "pt");
+  assert_equals(length.valueInSpecifiedUnits, referenceValue);
+  assert_equals(length.value, 4);
+  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_PT);
+}, document.title + ", pt");
+
+test(function() {
+  var length = svgElement.createSVGLength();
+  length.valueAsString = "16px";
+  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PC);
+  var referenceValue = 16 / cssPixelsPerInch * 6;
+  // Don't check valueAsString here, it's unreliable across browsers.
+  assert_equals(length.valueInSpecifiedUnits, referenceValue);
+  assert_equals(length.value, 16);
+  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_PC);
+}, document.title + ", pc");
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGLength.html b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLength.html
similarity index 97%
rename from third_party/WebKit/LayoutTests/svg/dom/SVGLength.html
rename to third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLength.html
index e215fa5..22256c05 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGLength.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLength.html
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML>
 <title>SVGLength interface</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <script>
 test(function() {
   var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGLengthList-appendItem.html b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLengthList-appendItem.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/svg/dom/SVGLengthList-appendItem.html
rename to third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLengthList-appendItem.html
index b9c98c6..5af8dbf 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGLengthList-appendItem.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLengthList-appendItem.html
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML>
 <title>SVGLengthList, appendItem()</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <script src="resources/SVGLengthList-helper.js"></script>
 <svg width="200" height="200">
     <text id="text1" x="500 50 100 900 1000" y="50">ABC</text>
@@ -47,7 +47,7 @@
   newLength2.value = 150;
   assert_equals(newLength2.value, 150);
   list1.clear();
-  
+
   // Shuffle around items in text1 and text2 list using appendItem, to get x=50,100,150,... in both lists.
   assert_equals(list1.appendItem(list2.getItem(0)).value, 50);
   assert_equals(list1.appendItem(list2.getItem(1)).value, 100);
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGLengthList-appendItemFromClearedList.html b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLengthList-appendItemFromClearedList.html
similarity index 79%
rename from third_party/WebKit/LayoutTests/svg/dom/SVGLengthList-appendItemFromClearedList.html
rename to third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLengthList-appendItemFromClearedList.html
index 2eede91c..e76491ec 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGLengthList-appendItemFromClearedList.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLengthList-appendItemFromClearedList.html
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML>
 <title>SVGLengthList, appendItem() from cleared list</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <script src="resources/SVGLengthList-helper.js"></script>
 <svg width="200" height="200">
     <text id="text1" x="1 2 3">ABC</text>
@@ -14,12 +14,12 @@
   var list1 = document.getElementById("text1").x.baseVal;
   var list2 = document.getElementById("text2").x.baseVal;
 
-  var itemFromClearedList = list2.getItem(0); 
+  var itemFromClearedList = list2.getItem(0);
   list2.clear();
   assert_equals(list2.numberOfItems, 0);
 
   list1.appendItem(itemFromClearedList);
-  
+
   assert_list(list1, [1, 2, 3, 10]);
   assert_equals(list2.numberOfItems, 0);
 });
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGLengthList-basics.html b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLengthList-basics.html
similarity index 98%
rename from third_party/WebKit/LayoutTests/svg/dom/SVGLengthList-basics.html
rename to third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLengthList-basics.html
index 2c1a5212..58d0e93 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGLengthList-basics.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLengthList-basics.html
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML>
 <title>SVGLengthList, basics</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
     <text x="500 1000 1500" y="50">   ABC  </text>
 </svg>
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGLengthList-getItem.html b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLengthList-getItem.html
similarity index 87%
rename from third_party/WebKit/LayoutTests/svg/dom/SVGLengthList-getItem.html
rename to third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLengthList-getItem.html
index 10a2c13f..c81a2339 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGLengthList-getItem.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/SVGLengthList-getItem.html
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML>
 <title>SVGLengthList, getItem()</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <svg width="200" height="200">
     <text x="50 100 150" y="50">ABC</text>
 </svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/resources/SVGLengthList-helper.js b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/resources/SVGLengthList-helper.js
new file mode 100644
index 0000000..3cf888b7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/types/scripted/resources/SVGLengthList-helper.js
@@ -0,0 +1,7 @@
+function assert_list(list, expectedValues) {
+  assert_equals(list.numberOfItems, expectedValues.length);
+  for (var index = 0; index < expectedValues.length; ++index)
+    assert_equals(list.getItem(index).value, expectedValues[index]);
+
+  assert_throws("IndexSizeError", function() { list.getItem(expectedValues.length); });
+}
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/contentscripts-navigator-multiple-frames.html b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/contentscripts-navigator-multiple-frames.html
index abdbb4d6..b518c4a7 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/contentscripts-navigator-multiple-frames.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/contentscripts-navigator-multiple-frames.html
@@ -1,5 +1,6 @@
 <head>
 <script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/debugger-test.js"></script>
 <script src="../../inspector/bindings/bindings-test.js"></script>
 
 <script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/dynamic-navigator-frame-attach-detach-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/dynamic-navigator-frame-attach-detach-expected.txt
index 3050c76..d7282dd0 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/dynamic-navigator-frame-attach-detach-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/dynamic-navigator-frame-attach-detach-expected.txt
@@ -9,6 +9,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
 
 Running: attachFrame
@@ -19,6 +20,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   frame (dynamic-frame.html)
     127.0.0.1:8000
@@ -36,5 +38,6 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/dynamic-navigator-frame-attach-detach.html b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/dynamic-navigator-frame-attach-detach.html
index e6432f65..9d19596 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/dynamic-navigator-frame-attach-detach.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/dynamic-navigator-frame-attach-detach.html
@@ -1,6 +1,7 @@
 <html>
 <head>
 <script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/debugger-test.js"></script>
 <script src="../../inspector/bindings/bindings-test.js"></script>
 
 <script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-attach-detach-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-attach-detach-expected.txt
index 7497c3af..0d67051 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-attach-detach-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-attach-detach-expected.txt
@@ -9,6 +9,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
 
 Running: attachFrame
@@ -19,6 +20,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   frame (magic-frame.html)
     127.0.0.1:8000
@@ -35,5 +37,6 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-attach-detach.html b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-attach-detach.html
index e08fc09..d17a6a9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-attach-detach.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-attach-detach.html
@@ -1,6 +1,7 @@
 <html>
 <head>
 <script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/debugger-test.js"></script>
 <script src="../../inspector/bindings/bindings-test.js"></script>
 
 <script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-navigate-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-navigate-expected.txt
index 33aaf14..5a4d3de 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-navigate-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-navigate-expected.txt
@@ -10,6 +10,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
 
 Running: attachFrame
@@ -20,6 +21,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   frame (magic-frame.html)
     127.0.0.1:8000
@@ -36,6 +38,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   frame (empty-frame.html)
     127.0.0.1:8000
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-navigate.html b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-navigate.html
index eab1f18..700e2ed 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-navigate.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-frame-navigate.html
@@ -1,6 +1,7 @@
 <html>
 <head>
 <script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/debugger-test.js"></script>
 <script src="../../inspector/bindings/bindings-test.js"></script>
 
 <script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-main-frame-navigated-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-main-frame-navigated-expected.txt
index f2ed157..62a47f6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-main-frame-navigated-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-main-frame-navigated-expected.txt
@@ -9,6 +9,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
 
 Running: attachFrame
@@ -19,6 +20,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   frame (sourcemap-frame.html)
     127.0.0.1:8000
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-main-frame-navigated.html b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-main-frame-navigated.html
index bc0fe32..2892c5e1 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-main-frame-navigated.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-main-frame-navigated.html
@@ -1,6 +1,7 @@
 <html>
 <head>
 <script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/debugger-test.js"></script>
 <script src="../../inspector/bindings/bindings-test.js"></script>
 
 <script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-multiple-frames-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-multiple-frames-expected.txt
index 57f5f7a..558c1f7d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-multiple-frames-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-multiple-frames-expected.txt
@@ -9,6 +9,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
 
 Running: createIframes
@@ -19,6 +20,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   frame1 (magic-frame.html)
     127.0.0.1:8000
@@ -41,6 +43,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   frame2 (magic-frame.html)
     127.0.0.1:8000
@@ -57,5 +60,6 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-multiple-frames.html b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-multiple-frames.html
index 219a6c3..f34573ca 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-multiple-frames.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/navigator-multiple-frames.html
@@ -1,5 +1,6 @@
 <head>
 <script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/debugger-test.js"></script>
 <script src="../../inspector/bindings/bindings-test.js"></script>
 
 <script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/shadowdom-navigator-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/shadowdom-navigator-expected.txt
index 6a53eef..fdefdb6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/shadowdom-navigator-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/shadowdom-navigator-expected.txt
@@ -9,6 +9,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
 
 Running: attachShadow1
@@ -22,6 +23,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   (no domain)
     sourcemap-script.js
@@ -38,6 +40,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   (no domain)
     sourcemap-script.js
@@ -54,6 +57,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   (no domain)
     sourcemap-script.js
@@ -69,6 +73,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   (no domain)
     sourcemap-script.js
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/shadowdom-navigator.html b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/shadowdom-navigator.html
index aff0bdc..f643b1b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/shadowdom-navigator.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/shadowdom-navigator.html
@@ -1,6 +1,7 @@
 <html>
 <head>
 <script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/debugger-test.js"></script>
 <script src="../../inspector/bindings/bindings-test.js"></script>
 
 <script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/sourcemap-navigator-multiple-frames-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/sourcemap-navigator-multiple-frames-expected.txt
index dfade61..31cd40d0 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/sourcemap-navigator-multiple-frames-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/sourcemap-navigator-multiple-frames-expected.txt
@@ -9,6 +9,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
 
 Running: attachFrame1
@@ -19,6 +20,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   (no domain)
     _test_create-iframe1.js
@@ -39,6 +41,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   (no domain)
     _test_create-iframe1.js
@@ -68,6 +71,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   (no domain)
     _test_create-iframe1.js
@@ -90,6 +94,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   (no domain)
     _test_create-iframe1.js
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/sourcemap-navigator-multiple-frames.html b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/sourcemap-navigator-multiple-frames.html
index 796c2545..643dde2 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/sourcemap-navigator-multiple-frames.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/sourcemap-navigator-multiple-frames.html
@@ -1,5 +1,6 @@
 <head>
 <script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/debugger-test.js"></script>
 <script src="../../inspector/bindings/bindings-test.js"></script>
 
 <script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/suspendtarget-navigator-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/suspendtarget-navigator-expected.txt
index 41360f0..0bce313f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/suspendtarget-navigator-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/suspendtarget-navigator-expected.txt
@@ -10,6 +10,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
 
 Running: attachFramesAndWaitForSourceMaps
@@ -20,6 +21,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   (no domain)
     _test_create-iframe1.js
@@ -73,6 +75,7 @@
     inspector
       bindings
         bindings-test.js
+      debugger-test.js
       inspector-test.js
   frame2 (sourcemap-frame.html)
     127.0.0.1:8000
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/suspendtarget-navigator.html b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/suspendtarget-navigator.html
index f075ba7..8c9358d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/suspendtarget-navigator.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/bindings/suspendtarget-navigator.html
@@ -1,5 +1,6 @@
 <head>
 <script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/debugger-test.js"></script>
 <script src="../../inspector/bindings/bindings-test.js"></script>
 
 <script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/event-listeners-framework-with-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/event-listeners-framework-with-service-worker-expected.txt
index 47f2976..5ab68993 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/event-listeners-framework-with-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/event-listeners-framework-with-service-worker-expected.txt
@@ -10,7 +10,7 @@
 
 ======== load ========
 == Raw
-[expanded] WindowRemoveevent-listeners-framework-with-service-worker.html:53
+[expanded] WindowRemoveevent-listeners-framework-with-service-worker.html:54
     useCapture: false
     passive: false
     once: false
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/event-listeners-framework-with-service-worker.html b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/event-listeners-framework-with-service-worker.html
index 18d1eca0..bf2ace9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/event-listeners-framework-with-service-worker.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/event-listeners-framework-with-service-worker.html
@@ -1,6 +1,7 @@
 <html>
 <head>
 <script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/elements-test.js"></script>
 <script src="../../inspector/debugger-test.js"></script>
 <script src="../../inspector/console-test.js"></script>
 <script src="../../inspector/service-workers/service-workers-test.js"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles/styles-do-not-add-inline-stylesheets-in-navigator-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles/styles-do-not-add-inline-stylesheets-in-navigator-expected.txt
index 6ac5cc6..adfb0970 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles/styles-do-not-add-inline-stylesheets-in-navigator-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles/styles-do-not-add-inline-stylesheets-in-navigator-expected.txt
@@ -5,6 +5,7 @@
     devtools/elements/styles
       styles-do-not-add-inline-stylesheets-in-navigator.html
     inspector
+      debugger-test.js
       elements-test.js
       inspector-test.js
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles/styles-do-not-add-inline-stylesheets-in-navigator.html b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles/styles-do-not-add-inline-stylesheets-in-navigator.html
index 30656d8..f26a1604 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles/styles-do-not-add-inline-stylesheets-in-navigator.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles/styles-do-not-add-inline-stylesheets-in-navigator.html
@@ -1,6 +1,7 @@
 <html>
 <head>
 <script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/debugger-test.js"></script>
 <script src="../../../inspector/elements-test.js"></script>
 <style>
 </style>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-add-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-add-expected.txt
index 68c226f..a3060af 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-add-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-add-expected.txt
@@ -7,6 +7,7 @@
 Resources:
 document http://127.0.0.1:8000/devtools/resource-tree/resource-tree-frame-add.html
 stylesheet http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial.css
+script http://127.0.0.1:8000/inspector/debugger-test.js
 script http://127.0.0.1:8000/inspector/inspector-test.js
 script http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js
 script http://127.0.0.1:8000/inspector/resources-test.js
@@ -14,6 +15,7 @@
 Resources URL Map:
 http://127.0.0.1:8000/devtools/resource-tree/resource-tree-frame-add.html == http://127.0.0.1:8000/devtools/resource-tree/resource-tree-frame-add.html
 http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial.css == http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial.css
+http://127.0.0.1:8000/inspector/debugger-test.js == http://127.0.0.1:8000/inspector/debugger-test.js
 http://127.0.0.1:8000/inspector/inspector-test.js == http://127.0.0.1:8000/inspector/inspector-test.js
 http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js == http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js
 http://127.0.0.1:8000/inspector/resources-test.js == http://127.0.0.1:8000/inspector/resources-test.js
@@ -22,6 +24,7 @@
 Frames
     top
         Scripts
+            debugger-test.js
             inspector-test.js
             resource-tree-test.js
             resources-test.js
@@ -32,6 +35,7 @@
 -------- Setting mode: [frame]
 top
   resource-tree-frame-add.html
+  debugger-test.js
   inspector-test.js
   resource-tree-test.js
   resources-test.js
@@ -41,6 +45,7 @@
 top
   127.0.0.1:8000
     resource-tree-frame-add.html
+    debugger-test.js
     inspector-test.js
     resource-tree-test.js
     resources-test.js
@@ -56,12 +61,14 @@
     inspector
       resource-tree
         resource-tree-test.js
+      debugger-test.js
       inspector-test.js
       resources-test.js
 Sources:
 -------- Setting mode: [domain]
 127.0.0.1:8000
   resource-tree-frame-add.html
+  debugger-test.js
   inspector-test.js
   resource-tree-test.js
   resources-test.js
@@ -76,6 +83,7 @@
   inspector
     resource-tree
       resource-tree-test.js
+    debugger-test.js
     inspector-test.js
     resources-test.js
 
@@ -87,6 +95,7 @@
 script http://127.0.0.1:8000/devtools/resource-tree/resources/script-navigated.js
 stylesheet http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial.css
 stylesheet http://127.0.0.1:8000/devtools/resource-tree/resources/styles-navigated.css
+script http://127.0.0.1:8000/inspector/debugger-test.js
 script http://127.0.0.1:8000/inspector/inspector-test.js
 script http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js
 script http://127.0.0.1:8000/inspector/resources-test.js
@@ -97,6 +106,7 @@
 http://127.0.0.1:8000/devtools/resource-tree/resources/script-navigated.js == http://127.0.0.1:8000/devtools/resource-tree/resources/script-navigated.js
 http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial.css == http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial.css
 http://127.0.0.1:8000/devtools/resource-tree/resources/styles-navigated.css == http://127.0.0.1:8000/devtools/resource-tree/resources/styles-navigated.css
+http://127.0.0.1:8000/inspector/debugger-test.js == http://127.0.0.1:8000/inspector/debugger-test.js
 http://127.0.0.1:8000/inspector/inspector-test.js == http://127.0.0.1:8000/inspector/inspector-test.js
 http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js == http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js
 http://127.0.0.1:8000/inspector/resources-test.js == http://127.0.0.1:8000/inspector/resources-test.js
@@ -111,6 +121,7 @@
                 styles-navigated.css
             resource-tree-frame-add-iframe.html
         Scripts
+            debugger-test.js
             inspector-test.js
             resource-tree-test.js
             resources-test.js
@@ -121,6 +132,7 @@
 -------- Setting mode: [frame]
 top
   resource-tree-frame-add.html
+  debugger-test.js
   inspector-test.js
   resource-tree-test.js
   resources-test.js
@@ -134,6 +146,7 @@
 top
   127.0.0.1:8000
     resource-tree-frame-add.html
+    debugger-test.js
     inspector-test.js
     resource-tree-test.js
     resources-test.js
@@ -154,6 +167,7 @@
     inspector
       resource-tree
         resource-tree-test.js
+      debugger-test.js
       inspector-test.js
       resources-test.js
   resource-tree-frame-add-iframe.html
@@ -167,6 +181,7 @@
 127.0.0.1:8000
   resource-tree-frame-add-iframe.html
   resource-tree-frame-add.html
+  debugger-test.js
   inspector-test.js
   resource-tree-test.js
   resources-test.js
@@ -186,6 +201,7 @@
   inspector
     resource-tree
       resource-tree-test.js
+    debugger-test.js
     inspector-test.js
     resources-test.js
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-add.html b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-add.html
index d161377..5256e04 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-add.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-add.html
@@ -1,6 +1,7 @@
 <html>
 <head>
 <script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/debugger-test.js"></script>
 <script src="../../inspector/resources-test.js"></script>
 <script src="../../inspector/resource-tree/resource-tree-test.js"></script>
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-navigate-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-navigate-expected.txt
index ef827ba..5be4b8b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-navigate-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-navigate-expected.txt
@@ -10,6 +10,7 @@
 script http://127.0.0.1:8000/devtools/resource-tree/resources/script-initial.js
 stylesheet http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial-2.css
 stylesheet http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial.css
+script http://127.0.0.1:8000/inspector/debugger-test.js
 script http://127.0.0.1:8000/inspector/inspector-test.js
 script http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js
 script http://127.0.0.1:8000/inspector/resources-test.js
@@ -20,6 +21,7 @@
 http://127.0.0.1:8000/devtools/resource-tree/resources/script-initial.js == http://127.0.0.1:8000/devtools/resource-tree/resources/script-initial.js
 http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial-2.css == http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial-2.css
 http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial.css == http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial.css
+http://127.0.0.1:8000/inspector/debugger-test.js == http://127.0.0.1:8000/inspector/debugger-test.js
 http://127.0.0.1:8000/inspector/inspector-test.js == http://127.0.0.1:8000/inspector/inspector-test.js
 http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js == http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js
 http://127.0.0.1:8000/inspector/resources-test.js == http://127.0.0.1:8000/inspector/resources-test.js
@@ -34,6 +36,7 @@
                 styles-initial-2.css
             resource-tree-frame-navigate-iframe-before.html
         Scripts
+            debugger-test.js
             inspector-test.js
             resource-tree-test.js
             resources-test.js
@@ -44,6 +47,7 @@
 -------- Setting mode: [frame]
 top
   resource-tree-frame-navigate.html
+  debugger-test.js
   inspector-test.js
   resource-tree-test.js
   resources-test.js
@@ -57,6 +61,7 @@
 top
   127.0.0.1:8000
     resource-tree-frame-navigate.html
+    debugger-test.js
     inspector-test.js
     resource-tree-test.js
     resources-test.js
@@ -77,6 +82,7 @@
     inspector
       resource-tree
         resource-tree-test.js
+      debugger-test.js
       inspector-test.js
       resources-test.js
   iframe (resource-tree-frame-navigate-iframe-before.html)
@@ -90,6 +96,7 @@
 127.0.0.1:8000
   resource-tree-frame-navigate-iframe-before.html
   resource-tree-frame-navigate.html
+  debugger-test.js
   inspector-test.js
   resource-tree-test.js
   resources-test.js
@@ -109,6 +116,7 @@
   inspector
     resource-tree
       resource-tree-test.js
+    debugger-test.js
     inspector-test.js
     resources-test.js
 
@@ -120,6 +128,7 @@
 script http://127.0.0.1:8000/devtools/resource-tree/resources/script-navigated.js
 stylesheet http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial.css
 stylesheet http://127.0.0.1:8000/devtools/resource-tree/resources/styles-navigated.css
+script http://127.0.0.1:8000/inspector/debugger-test.js
 script http://127.0.0.1:8000/inspector/inspector-test.js
 script http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js
 script http://127.0.0.1:8000/inspector/resources-test.js
@@ -130,6 +139,7 @@
 http://127.0.0.1:8000/devtools/resource-tree/resources/script-navigated.js == http://127.0.0.1:8000/devtools/resource-tree/resources/script-navigated.js
 http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial.css == http://127.0.0.1:8000/devtools/resource-tree/resources/styles-initial.css
 http://127.0.0.1:8000/devtools/resource-tree/resources/styles-navigated.css == http://127.0.0.1:8000/devtools/resource-tree/resources/styles-navigated.css
+http://127.0.0.1:8000/inspector/debugger-test.js == http://127.0.0.1:8000/inspector/debugger-test.js
 http://127.0.0.1:8000/inspector/inspector-test.js == http://127.0.0.1:8000/inspector/inspector-test.js
 http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js == http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js
 http://127.0.0.1:8000/inspector/resources-test.js == http://127.0.0.1:8000/inspector/resources-test.js
@@ -144,6 +154,7 @@
                 styles-navigated.css
             resource-tree-frame-navigate-iframe-after.html
         Scripts
+            debugger-test.js
             inspector-test.js
             resource-tree-test.js
             resources-test.js
@@ -154,6 +165,7 @@
 -------- Setting mode: [frame]
 top
   resource-tree-frame-navigate.html
+  debugger-test.js
   inspector-test.js
   resource-tree-test.js
   resources-test.js
@@ -167,6 +179,7 @@
 top
   127.0.0.1:8000
     resource-tree-frame-navigate.html
+    debugger-test.js
     inspector-test.js
     resource-tree-test.js
     resources-test.js
@@ -187,6 +200,7 @@
     inspector
       resource-tree
         resource-tree-test.js
+      debugger-test.js
       inspector-test.js
       resources-test.js
   iframe (resource-tree-frame-navigate-iframe-after.html)
@@ -200,6 +214,7 @@
 127.0.0.1:8000
   resource-tree-frame-navigate-iframe-after.html
   resource-tree-frame-navigate.html
+  debugger-test.js
   inspector-test.js
   resource-tree-test.js
   resources-test.js
@@ -219,6 +234,7 @@
   inspector
     resource-tree
       resource-tree-test.js
+    debugger-test.js
     inspector-test.js
     resources-test.js
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-navigate.html b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-navigate.html
index 33eaafd4..dc973b2d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-navigate.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-frame-navigate.html
@@ -1,6 +1,7 @@
 <html>
 <head>
 <script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/debugger-test.js"></script>
 <script src="../../inspector/resources-test.js"></script>
 <script src="../../inspector/resource-tree/resource-tree-test.js"></script>
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-htmlimports-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-htmlimports-expected.txt
index 0924bbf3..2be88e9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-htmlimports-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-htmlimports-expected.txt
@@ -5,6 +5,7 @@
 document http://127.0.0.1:8000/devtools/resource-tree/resources/import-child.html
 document http://127.0.0.1:8000/devtools/resource-tree/resources/import-hello.html
 script http://127.0.0.1:8000/devtools/resource-tree/resources/import-hello.js
+script http://127.0.0.1:8000/inspector/debugger-test.js
 script http://127.0.0.1:8000/inspector/inspector-test.js
 script http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js
 script http://127.0.0.1:8000/inspector/resources-test.js
@@ -14,6 +15,7 @@
 http://127.0.0.1:8000/devtools/resource-tree/resources/import-child.html == http://127.0.0.1:8000/devtools/resource-tree/resources/import-child.html
 http://127.0.0.1:8000/devtools/resource-tree/resources/import-hello.html == http://127.0.0.1:8000/devtools/resource-tree/resources/import-hello.html
 http://127.0.0.1:8000/devtools/resource-tree/resources/import-hello.js == http://127.0.0.1:8000/devtools/resource-tree/resources/import-hello.js
+http://127.0.0.1:8000/inspector/debugger-test.js == http://127.0.0.1:8000/inspector/debugger-test.js
 http://127.0.0.1:8000/inspector/inspector-test.js == http://127.0.0.1:8000/inspector/inspector-test.js
 http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js == http://127.0.0.1:8000/inspector/resource-tree/resource-tree-test.js
 http://127.0.0.1:8000/inspector/resources-test.js == http://127.0.0.1:8000/inspector/resources-test.js
@@ -22,6 +24,7 @@
 Frames
     top
         Scripts
+            debugger-test.js
             import-hello.js
             inspector-test.js
             resource-tree-test.js
@@ -35,6 +38,7 @@
   import-child.html
   import-hello.html
   resource-tree-htmlimports.html
+  debugger-test.js
   import-hello.js
   inspector-test.js
   resource-tree-test.js
@@ -46,6 +50,7 @@
     import-child.html
     import-hello.html
     resource-tree-htmlimports.html
+    debugger-test.js
     import-hello.js
     inspector-test.js
     resource-tree-test.js
@@ -63,6 +68,7 @@
     inspector
       resource-tree
         resource-tree-test.js
+      debugger-test.js
       inspector-test.js
       resources-test.js
 Sources:
@@ -71,6 +77,7 @@
   import-child.html
   import-hello.html
   resource-tree-htmlimports.html
+  debugger-test.js
   import-hello.js
   inspector-test.js
   resource-tree-test.js
@@ -87,6 +94,7 @@
   inspector
     resource-tree
       resource-tree-test.js
+    debugger-test.js
     inspector-test.js
     resources-test.js
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-htmlimports.html b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-htmlimports.html
index 91cbacc..e544fa8 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-htmlimports.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-htmlimports.html
@@ -5,6 +5,7 @@
 <!-- import-hello.html shouldn't be shown twice as it shares same resource as above -->
 <link rel="import" href="resources/import-hello.html">
 <script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/debugger-test.js"></script>
 <script src="../../inspector/resources-test.js"></script>
 <script src="../../inspector/resource-tree/resource-tree-test.js"></script>
 <script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-non-unique-url-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-non-unique-url-expected.txt
index 8874372d..c8d2ecc4 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-non-unique-url-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-non-unique-url-expected.txt
@@ -11,6 +11,7 @@
                 styles-non-unique-url.css
             resource-tree-non-unique-url-iframe.html
         Scripts
+            debugger-test.js
             inspector-test.js
             resource-tree-test.js
             resources-test.js
@@ -19,6 +20,7 @@
 -------- Setting mode: [frame]
 top
   resource-tree-non-unique-url.html
+  debugger-test.js
   inspector-test.js
   resource-tree-test.js
   resources-test.js
@@ -30,6 +32,7 @@
 top
   127.0.0.1:8000
     resource-tree-non-unique-url.html
+    debugger-test.js
     inspector-test.js
     resource-tree-test.js
     resources-test.js
@@ -46,6 +49,7 @@
     inspector
       resource-tree
         resource-tree-test.js
+      debugger-test.js
       inspector-test.js
       resources-test.js
   resource-tree-non-unique-url-iframe.html
@@ -58,6 +62,7 @@
 127.0.0.1:8000
   resource-tree-non-unique-url-iframe.html
   resource-tree-non-unique-url.html
+  debugger-test.js
   inspector-test.js
   resource-tree-test.js
   resources-test.js
@@ -73,6 +78,7 @@
   inspector
     resource-tree
       resource-tree-test.js
+    debugger-test.js
     inspector-test.js
     resources-test.js
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-non-unique-url.html b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-non-unique-url.html
index f188eb7..a0bbe10 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-non-unique-url.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/resource-tree/resource-tree-non-unique-url.html
@@ -1,6 +1,7 @@
 <html>
 <head>
 <script src="../../inspector/inspector-test.js"></script>
+<script src="../../inspector/debugger-test.js"></script>
 <script src="../../inspector/resources-test.js"></script>
 <script src="../../inspector/resource-tree/resource-tree-test.js"></script>
 <script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/sources/debugger-ui/ui-source-code-display-name.html b/third_party/WebKit/LayoutTests/http/tests/devtools/sources/debugger-ui/ui-source-code-display-name.html
index 1a5c1f4..d407e43 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/sources/debugger-ui/ui-source-code-display-name.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/sources/debugger-ui/ui-source-code-display-name.html
@@ -1,6 +1,7 @@
 <html>
 <head>
 <script src="../../../inspector/inspector-test.js"></script>
+<script src="../../../inspector/debugger-test.js"></script>
 <script>
 async function test() {
   async function dumpUISourceCodeDisplayName(url) {
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/console-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/console-test.js
index c7533259..7aa28191 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/console-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/console-test.js
@@ -451,4 +451,21 @@
     }
 }
 
+InspectorTest.wrapListener = function(func)
+{
+    function wrapper()
+    {
+        var wrapArgs = arguments;
+        var wrapThis = this;
+        // Give a chance to other listeners.
+        setTimeout(apply, 0);
+
+        function apply()
+        {
+            func.apply(wrapThis, wrapArgs);
+        }
+    }
+    return wrapper;
+}
+
 }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js
index 02dd2e8..cb58484 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js
@@ -425,6 +425,44 @@
     return UI.viewManager.showView("elements.eventListeners");
 }
 
+InspectorTest.expandAndDumpEventListeners = function(eventListenersView, callback, force)
+{
+    function listenersArrived()
+    {
+        var listenerTypes = eventListenersView._treeOutline.rootElement().children();
+        for (var i = 0; i < listenerTypes.length; ++i) {
+            listenerTypes[i].expand();
+            var listenerItems = listenerTypes[i].children();
+            for (var j = 0; j < listenerItems.length; ++j)
+                listenerItems[j].expand();
+        }
+        InspectorTest.deprecatedRunAfterPendingDispatches(objectsExpanded);
+    }
+
+    function objectsExpanded()
+    {
+        var listenerTypes = eventListenersView._treeOutline.rootElement().children();
+        for (var i = 0; i < listenerTypes.length; ++i) {
+            if (!listenerTypes[i].children().length)
+                continue;
+            var eventType = listenerTypes[i]._title;
+            InspectorTest.addResult("");
+            InspectorTest.addResult("======== " + eventType + " ========");
+            var listenerItems = listenerTypes[i].children();
+            for (var j = 0; j < listenerItems.length; ++j) {
+                InspectorTest.addResult("== " + listenerItems[j].eventListener().origin());
+                InspectorTest.dumpObjectPropertyTreeElement(listenerItems[j]);
+            }
+        }
+        callback();
+    }
+
+    if (force)
+        listenersArrived();
+    else
+        InspectorTest.addSniffer(EventListeners.EventListenersView.prototype, "_eventListenersArrivedForTest", listenersArrived);
+}
+
 InspectorTest.expandAndDumpSelectedElementEventListeners = function(callback, force)
 {
     InspectorTest.expandAndDumpEventListeners(InspectorTest.eventListenersWidget()._eventListenersView, callback, force);
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
index ad38b4b..d0ac1053 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
@@ -40,6 +40,9 @@
     results = [];
 }
 
+/**
+ * TestRunner.evaluateInPage inserts sourceURL by inspecting the call stack.
+ */
 InspectorTest.evaluateInPage = async function(code, callback)
 {
     var response = await InspectorTest.RuntimeAgent.invoke_evaluate({
@@ -50,19 +53,6 @@
         InspectorTest.safeWrap(callback)(InspectorTest.runtimeModel.createRemoteObject(response.result), response.exceptionDetails);
 }
 
-InspectorTest.addScriptUISourceCode = function(url, content, isContentScript, worldId) {
-    content += '\n//# sourceURL=' + url;
-    if (isContentScript)
-        content = `testRunner.evaluateScriptInIsolatedWorld(${worldId}, \`${content}\`)`;
-    InspectorTest.evaluateInPagePromise(content);
-    return InspectorTest.waitForUISourceCode(url);
-};
-
-InspectorTest.evaluateInPagePromise = function(code)
-{
-    return new Promise(succ => InspectorTest.evaluateInPage(code, succ));
-}
-
 InspectorTest.addResult = function(text)
 {
     results.push(String(text));
@@ -84,95 +74,6 @@
     return ".../" + value.substr(lastIndex);
 }
 
-InspectorTest.expandAndDumpEventListeners = function(eventListenersView, callback, force)
-{
-    function listenersArrived()
-    {
-        var listenerTypes = eventListenersView._treeOutline.rootElement().children();
-        for (var i = 0; i < listenerTypes.length; ++i) {
-            listenerTypes[i].expand();
-            var listenerItems = listenerTypes[i].children();
-            for (var j = 0; j < listenerItems.length; ++j)
-                listenerItems[j].expand();
-        }
-        InspectorTest.deprecatedRunAfterPendingDispatches(objectsExpanded);
-    }
-
-    function objectsExpanded()
-    {
-        var listenerTypes = eventListenersView._treeOutline.rootElement().children();
-        for (var i = 0; i < listenerTypes.length; ++i) {
-            if (!listenerTypes[i].children().length)
-                continue;
-            var eventType = listenerTypes[i]._title;
-            InspectorTest.addResult("");
-            InspectorTest.addResult("======== " + eventType + " ========");
-            var listenerItems = listenerTypes[i].children();
-            for (var j = 0; j < listenerItems.length; ++j) {
-                InspectorTest.addResult("== " + listenerItems[j].eventListener().origin());
-                InspectorTest.dumpObjectPropertyTreeElement(listenerItems[j]);
-            }
-        }
-        callback();
-    }
-
-    if (force)
-        listenersArrived();
-    else
-        InspectorTest.addSniffer(EventListeners.EventListenersView.prototype, "_eventListenersArrivedForTest", listenersArrived);
-};
-
-InspectorTest.dumpNavigatorView = function(navigatorView, dumpIcons)
-{
-    dumpNavigatorTreeOutline(navigatorView._scriptsTree);
-
-    function dumpNavigatorTreeElement(prefix, treeElement)
-    {
-        var titleText = '';
-        if (treeElement._leadingIconsElement && dumpIcons) {
-            var icons = treeElement._leadingIconsElement.querySelectorAll('[is=ui-icon]');
-            icons = Array.prototype.slice.call(icons);
-            var iconTypes = icons.map(icon => icon._iconType);
-            if (iconTypes.length)
-                titleText = titleText + "[" + iconTypes.join(", ") + "] ";
-        }
-        titleText += treeElement.title;
-        if (treeElement._nodeType === Sources.NavigatorView.Types.FileSystem || treeElement._nodeType === Sources.NavigatorView.Types.FileSystemFolder) {
-            var hasMappedFiles = treeElement.listItemElement.classList.contains("has-mapped-files");
-            if (!hasMappedFiles)
-                titleText += " [dimmed]";
-        }
-        InspectorTest.addResult(prefix + titleText);
-        treeElement.expand();
-        var children = treeElement.children();
-        for (var i = 0; i < children.length; ++i)
-            dumpNavigatorTreeElement(prefix + "  ", children[i]);
-    }
-
-    function dumpNavigatorTreeOutline(treeOutline)
-    {
-        var children = treeOutline.rootElement().children();
-        for (var i = 0; i < children.length; ++i)
-            dumpNavigatorTreeElement("", children[i]);
-    }
-}
-
-InspectorTest.dumpNavigatorViewInAllModes = function(view)
-{
-    ["frame", "frame/domain", "frame/domain/folder", "domain", "domain/folder"].forEach(InspectorTest.dumpNavigatorViewInMode.bind(InspectorTest, view));
-}
-
-InspectorTest.dumpNavigatorViewInMode = function(view, mode)
-{
-    InspectorTest.addResult(view instanceof Sources.SourcesNavigatorView ? "Sources:" : "Content Scripts:");
-    view._groupByFrame = mode.includes("frame");
-    view._groupByDomain = mode.includes("domain");
-    view._groupByFolder = mode.includes("folder");
-    view._resetForTest();
-    InspectorTest.addResult("-------- Setting mode: [" + mode + "]");
-    InspectorTest.dumpNavigatorView(view);
-}
-
 InspectorTest.navigate = function(url, callback)
 {
     InspectorTest._pageLoadedCallback = InspectorTest.safeWrap(callback);
@@ -254,23 +155,6 @@
     runner();
 }
 
-InspectorTest.wrapListener = function(func)
-{
-    function wrapper()
-    {
-        var wrapArgs = arguments;
-        var wrapThis = this;
-        // Give a chance to other listeners.
-        setTimeout(apply, 0);
-
-        function apply()
-        {
-            func.apply(wrapThis, wrapArgs);
-        }
-    }
-    return wrapper;
-}
-
 InspectorTest.addConsoleSniffer = function(override, opt_sticky)
 {
     InspectorTest.addSniffer(ConsoleModel.ConsoleModel.prototype, "addMessage", override, opt_sticky);
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 dbdafcb..a6fd1b776 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
@@ -12,13 +12,9 @@
       var message_id = 1;
       var ts = Date.now();
       while (!terminated) {
-        // Without this try/catch v8 will optimize the function and break will not work.
-        try {
-          if (Date.now() - ts > 1000) {
-            ts = Date.now();
-            console.error('Message #' + message_id++);
-          }
-        } catch (e) {
+        if (Date.now() - ts > 1000) {
+          ts = Date.now();
+          console.error('Message #' + message_id++);
         }
       }
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/raster-under-invalidation-checking.html b/third_party/WebKit/LayoutTests/paint/invalidation/raster-under-invalidation-checking.html
index fbe5b6c..b52a17c 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/raster-under-invalidation-checking.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/raster-under-invalidation-checking.html
@@ -1,4 +1,6 @@
 <!DOCTYPE html>
+<script src="../../resources/run-after-layout-and-paint.js"></script>
+<script src="resources/text-based-repaint.js"></script>
 <style>
 [id^="target"] {
   width: 60px;
@@ -16,8 +18,6 @@
   <div style="width: 4000px; height: 20000px"></div>
   <div id="target4" style="position: relative; top: -10000px; left: 30px"></div>
 </div>
-<script src="../../resources/run-after-layout-and-paint.js"></script>
-<script src="resources/text-based-repaint.js"></script>
 <script>
 window.testIsAsync = true;
 
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGLength-px.html b/third_party/WebKit/LayoutTests/svg/dom/SVGLength-px.html
deleted file mode 100644
index d1b1841..0000000
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGLength-px.html
+++ /dev/null
@@ -1,108 +0,0 @@
-<!DOCTYPE HTML>
-<title>SVGLength, converting from 'px' to other units (detached)</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script>
-var cssPixelsPerInch = 96;
-setup(function() {
-  window.svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
-});
-
-test(function() {
-  var length = svgElement.createSVGLength();
-  length.valueAsString = "2px";
-  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_NUMBER);
-  assert_equals(length.valueAsString, "2");
-  assert_equals(length.value, 2);
-  assert_equals(length.valueInSpecifiedUnits, 2);
-  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
-}, document.title + ", unitless");
-
-test(function() {
-  var length = svgElement.createSVGLength();
-  length.valueAsString = "2px";
-  // Try converting from px to percentage, should fail as the SVGLength is not associated with a SVGSVGElement, and thus no viewport information is available.
-  assert_throws("NotSupportedError", function() { length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PERCENTAGE); });
-  assert_equals(length.valueAsString, "2px");
-  assert_equals(length.value, 2);
-  assert_equals(length.valueInSpecifiedUnits, 2);
-  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_PX);
-}, document.title + ", percentage");
-
-test(function() {
-  var length = svgElement.createSVGLength();
-  length.valueAsString = "2px";
-  // Try converting from px to ems, should fail as the SVGLength is not associated with a SVGSVGElement, and thus no font-size information is available.
-  assert_throws("NotSupportedError", function() { length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_EMS); });
-  assert_equals(length.valueAsString, "2px");
-  assert_equals(length.value, 2);
-  assert_equals(length.valueInSpecifiedUnits, 2);
-  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_PX);
-}, document.title + ", ems");
-
-test(function() {
-  var length = svgElement.createSVGLength();
-  length.valueAsString = "2px";
-  // Try converting from px to exs, should fail as the SVGLength is not associated with a SVGSVGElement, and thus no font-size information is available.
-  assert_throws("NotSupportedError", function() { length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_EXS); });
-  assert_equals(length.valueAsString, "2px");
-  assert_equals(length.value, 2);
-  assert_equals(length.valueInSpecifiedUnits, 2);
-  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_PX);
-}, document.title + ", exs");
-
-test(function() {
-  var length = svgElement.createSVGLength();
-  length.valueAsString = "2px";
-  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_CM);
-  var referenceValue = Number(2 * 2.54 / cssPixelsPerInch).toFixed(7);
-  assert_equals(length.valueAsString, referenceValue + "cm");
-  assert_equals(length.valueInSpecifiedUnits.toFixed(7), referenceValue);
-  assert_equals(length.value.toFixed(1), "2.0");
-  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_CM);
-}, document.title + ", cm");
-
-test(function() {
-  var length = svgElement.createSVGLength();
-  length.valueAsString = "2px";
-  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_MM);
-  var referenceValue = Number(2 * 25.4 / cssPixelsPerInch).toFixed(6);
-  assert_equals(length.valueAsString, referenceValue + "mm");
-  assert_equals(length.valueInSpecifiedUnits.toFixed(6), referenceValue);
-  assert_equals(length.value.toFixed(1), "2.0");
-  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_MM);
-}, document.title + ", mm");
-
-test(function() {
-  var length = svgElement.createSVGLength();
-  length.valueAsString = "2px";
-  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_IN);
-  var referenceValue = Number(2 / cssPixelsPerInch).toFixed(7);
-  assert_equals(length.valueAsString, referenceValue + "in");
-  assert_equals(length.valueInSpecifiedUnits.toFixed(7), referenceValue);
-  assert_equals(length.value.toFixed(1), "2.0");
-  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_IN);
-}, document.title + ", in");
-
-test(function() {
-  var length = svgElement.createSVGLength();
-  length.valueAsString = "2px";
-  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PT);
-  var referenceValue = Number(2 / cssPixelsPerInch * 72);
-  assert_equals(length.valueAsString, referenceValue + "pt");
-  assert_equals(length.valueInSpecifiedUnits, referenceValue);
-  assert_equals(length.value.toFixed(1), "2.0");
-  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_PT);
-}, document.title + ", pt");
-
-test(function() {
-  var length = svgElement.createSVGLength();
-  length.valueAsString = "2px";
-  length.convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PC);
-  var referenceValue = Number(2 / cssPixelsPerInch * 6).toFixed(3);
-  // Don't check valueAsString here, it's unreliable across browsers.
-  assert_equals(length.valueInSpecifiedUnits.toFixed(3), referenceValue);
-  assert_equals(length.value.toFixed(1), "2.0");
-  assert_equals(length.unitType, SVGLength.SVG_LENGTHTYPE_PC);
-}, document.title + ", pc");
-</script>
\ No newline at end of file
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.cpp b/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.cpp
index 1cb9fb0..a5b6cd1 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.cpp
@@ -39,16 +39,6 @@
   return GetImage() && GetImage()->IsTextureBacked();
 }
 
-int CSSStyleImageValue::SourceHeight() {
-  bool not_used;
-  return intrinsicHeight(not_used);
-}
-
-int CSSStyleImageValue::SourceWidth() {
-  bool not_used;
-  return intrinsicWidth(not_used);
-}
-
 RefPtr<Image> CSSStyleImageValue::GetImage() const {
   if (IsCachePending())
     return nullptr;
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.h b/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.h
index 94142b6..f514c6a 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.h
+++ b/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.h
@@ -33,8 +33,6 @@
 
   // CanvasImageSource
   bool IsCSSImageValue() const final { return true; }
-  int SourceWidth() final;
-  int SourceHeight() final;
   bool WouldTaintOrigin(
       SecurityOrigin* destination_security_origin) const final {
     return true;
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
index 29348d42..0f76ca55 100644
--- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -980,7 +980,8 @@
 
     // skip position in non-laid out or invisible node
     const LayoutObject* const layout_object =
-        AssociatedLayoutObjectOf(*current_node, current_pos.OffsetInLeafNode());
+        AssociatedLayoutObjectOf(*current_node, current_pos.OffsetInLeafNode(),
+                                 LayoutObjectSide::kFirstLetterIfOnBoundary);
     if (!layout_object ||
         layout_object->Style()->Visibility() != EVisibility::kVisible)
       continue;
@@ -1070,26 +1071,9 @@
   return true;
 }
 
-// Returns true if |text_layout_object| has visible first-letter.
-bool HasVisibleFirstLetter(const LayoutText& text_layout_object) {
-  if (!text_layout_object.IsTextFragment())
-    return false;
-  const LayoutTextFragment& layout_text_fragment =
-      ToLayoutTextFragment(text_layout_object);
-  if (!layout_text_fragment.IsRemainingTextLayoutObject())
-    return false;
-  const LayoutObject* first_letter_layout_object =
-      layout_text_fragment.GetFirstLetterPseudoElement()->GetLayoutObject();
-  if (!first_letter_layout_object)
-    return false;
-  return first_letter_layout_object->Style()->Visibility() ==
-         EVisibility::kVisible;
-}
-
 // Returns true when both of the following hold:
 // (i)  |offset_in_node| is not the first offset in |text_layout_object|
 // (ii) |offset_in_node| and |offset_in_node - 1| are different caret positions
-// TODO(editing-dev): Document the behavior when there is ::first-letter.
 static bool CanBeBackwardCaretPosition(const LayoutText* text_layout_object,
                                        int offset_in_node) {
   const unsigned text_start_offset = text_layout_object->TextStartOffset();
@@ -1097,15 +1081,8 @@
   const unsigned text_offset = offset_in_node - text_start_offset;
   InlineTextBox* const last_text_box = text_layout_object->LastTextBox();
   for (InlineTextBox* box : InlineTextBoxesOf(*text_layout_object)) {
-    if (text_offset == box->Start()) {
-      if (HasVisibleFirstLetter(*text_layout_object)) {
-        // |offset_in_node| is at start of remaining text of
-        // |Text| node with :first-letter.
-        DCHECK_GE(offset_in_node, 1);
-        return true;
-      }
+    if (text_offset == box->Start())
       continue;
-    }
     if (text_offset <= box->Start() + box->Len()) {
       if (text_offset > box->Start())
         return true;
diff --git a/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.cpp b/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.cpp
index 24e549fe..8ab110a9 100644
--- a/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.cpp
@@ -736,17 +736,15 @@
                          "more information."));
   } else if (!web_frame_->Client()->OverrideLegacySymantecCertConsoleMessage(
                  url, cert_validity_start, &console_message)) {
-    String port = url.Port() == 443 ? "" : String::Format(":%d", url.Port());
-    console_message = WebString(String::Format(
-        "The SSL certificate used to load resources from %s://%s%s"
-        " will be "
-        "distrusted in the future. "
-        "Once distrusted, users will be prevented from "
-        "loading these resources. See "
-        "https://g.co/chrome/symantecpkicerts for "
-        "more information.",
-        url.Protocol().Utf8().data(), url.Host().Utf8().data(),
-        port.Utf8().data()));
+    console_message = WebString(
+        String::Format("The SSL certificate used to load resources from %s"
+                       " will be "
+                       "distrusted in the future. "
+                       "Once distrusted, users will be prevented from "
+                       "loading these resources. See "
+                       "https://g.co/chrome/symantecpkicerts for "
+                       "more information.",
+                       SecurityOrigin::Create(url)->ToString().Utf8().data()));
   }
   num_certificate_warning_messages_++;
   certificate_warning_hosts_.insert(url.Host());
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
index bba6b9f0..d2e24ff 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -198,8 +198,6 @@
   bool IsCanvasElement() const override { return true; }
   bool IsOpaque() const override;
   bool IsAccelerated() const override;
-  int SourceWidth() override { return size_.Width(); }
-  int SourceHeight() override { return size_.Height(); }
 
   // SurfaceLayerBridgeObserver implementation
   void OnWebLayerReplaced() override;
diff --git a/third_party/WebKit/Source/core/html/TextMetrics.h b/third_party/WebKit/Source/core/html/TextMetrics.h
index b6dea140..d0bc91b 100644
--- a/third_party/WebKit/Source/core/html/TextMetrics.h
+++ b/third_party/WebKit/Source/core/html/TextMetrics.h
@@ -39,63 +39,63 @@
  public:
   static TextMetrics* Create() { return new TextMetrics; }
 
-  float width() const { return width_; }
-  void SetWidth(float w) { width_ = w; }
+  double width() const { return width_; }
+  void SetWidth(double w) { width_ = w; }
 
-  float actualBoundingBoxLeft() const { return actual_bounding_box_left_; }
-  void SetActualBoundingBoxLeft(float actual_bounding_box_left) {
+  double actualBoundingBoxLeft() const { return actual_bounding_box_left_; }
+  void SetActualBoundingBoxLeft(double actual_bounding_box_left) {
     actual_bounding_box_left_ = actual_bounding_box_left;
   }
 
-  float actualBoundingBoxRight() const { return actual_bounding_box_right_; }
-  void SetActualBoundingBoxRight(float actual_bounding_box_right) {
+  double actualBoundingBoxRight() const { return actual_bounding_box_right_; }
+  void SetActualBoundingBoxRight(double actual_bounding_box_right) {
     actual_bounding_box_right_ = actual_bounding_box_right;
   }
 
-  float fontBoundingBoxAscent() const { return font_bounding_box_ascent_; }
-  void SetFontBoundingBoxAscent(float font_bounding_box_ascent) {
+  double fontBoundingBoxAscent() const { return font_bounding_box_ascent_; }
+  void SetFontBoundingBoxAscent(double font_bounding_box_ascent) {
     font_bounding_box_ascent_ = font_bounding_box_ascent;
   }
 
-  float fontBoundingBoxDescent() const { return font_bounding_box_descent_; }
-  void SetFontBoundingBoxDescent(float font_bounding_box_descent) {
+  double fontBoundingBoxDescent() const { return font_bounding_box_descent_; }
+  void SetFontBoundingBoxDescent(double font_bounding_box_descent) {
     font_bounding_box_descent_ = font_bounding_box_descent;
   }
 
-  float actualBoundingBoxAscent() const { return actual_bounding_box_ascent_; }
-  void SetActualBoundingBoxAscent(float actual_bounding_box_ascent) {
+  double actualBoundingBoxAscent() const { return actual_bounding_box_ascent_; }
+  void SetActualBoundingBoxAscent(double actual_bounding_box_ascent) {
     actual_bounding_box_ascent_ = actual_bounding_box_ascent;
   }
 
-  float actualBoundingBoxDescent() const {
+  double actualBoundingBoxDescent() const {
     return actual_bounding_box_descent_;
   }
-  void SetActualBoundingBoxDescent(float actual_bounding_box_descent) {
+  void SetActualBoundingBoxDescent(double actual_bounding_box_descent) {
     actual_bounding_box_descent_ = actual_bounding_box_descent;
   }
 
-  float emHeightAscent() const { return em_height_ascent_; }
-  void SetEmHeightAscent(float em_height_ascent) {
+  double emHeightAscent() const { return em_height_ascent_; }
+  void SetEmHeightAscent(double em_height_ascent) {
     em_height_ascent_ = em_height_ascent;
   }
 
-  float emHeightDescent() const { return em_height_descent_; }
-  void SetEmHeightDescent(float em_height_descent) {
+  double emHeightDescent() const { return em_height_descent_; }
+  void SetEmHeightDescent(double em_height_descent) {
     em_height_descent_ = em_height_descent;
   }
 
-  float hangingBaseline() const { return hanging_baseline_; }
-  void SetHangingBaseline(float hanging_baseline) {
+  double hangingBaseline() const { return hanging_baseline_; }
+  void SetHangingBaseline(double hanging_baseline) {
     hanging_baseline_ = hanging_baseline;
   }
 
-  float alphabeticBaseline() const { return alphabetic_baseline_; }
-  void SetAlphabeticBaseline(float alphabetic_baseline) {
+  double alphabeticBaseline() const { return alphabetic_baseline_; }
+  void SetAlphabeticBaseline(double alphabetic_baseline) {
     alphabetic_baseline_ = alphabetic_baseline;
   }
 
-  float ideographicBaseline() const { return ideographic_baseline_; }
-  void SetIdeographicBaseline(float ideographic_baseline) {
+  double ideographicBaseline() const { return ideographic_baseline_; }
+  void SetIdeographicBaseline(double ideographic_baseline) {
     ideographic_baseline_ = ideographic_baseline;
   }
 
@@ -117,20 +117,20 @@
         ideographic_baseline_(0) {}
 
   // x-direction
-  float width_;
-  float actual_bounding_box_left_;
-  float actual_bounding_box_right_;
+  double width_;
+  double actual_bounding_box_left_;
+  double actual_bounding_box_right_;
 
   // y-direction
-  float font_bounding_box_ascent_;
-  float font_bounding_box_descent_;
-  float actual_bounding_box_ascent_;
-  float actual_bounding_box_descent_;
-  float em_height_ascent_;
-  float em_height_descent_;
-  float hanging_baseline_;
-  float alphabetic_baseline_;
-  float ideographic_baseline_;
+  double font_bounding_box_ascent_;
+  double font_bounding_box_descent_;
+  double actual_bounding_box_ascent_;
+  double actual_bounding_box_descent_;
+  double em_height_ascent_;
+  double em_height_descent_;
+  double hanging_baseline_;
+  double alphabetic_baseline_;
+  double ideographic_baseline_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/TextMetrics.idl b/third_party/WebKit/Source/core/html/TextMetrics.idl
index 68b0ee4..5ee4a071 100644
--- a/third_party/WebKit/Source/core/html/TextMetrics.idl
+++ b/third_party/WebKit/Source/core/html/TextMetrics.idl
@@ -25,22 +25,21 @@
 
 // https://html.spec.whatwg.org/#textmetrics
 
-// TODO(foolip): All float types in this interface should be double.
 // TODO(foolip): Exposed=(Window,Worker)
 interface TextMetrics {
     // x-direction
     readonly attribute float width; // advance width
-    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute float actualBoundingBoxLeft;
-    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute float actualBoundingBoxRight;
+    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute double actualBoundingBoxLeft;
+    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute double actualBoundingBoxRight;
 
     // y-direction
-    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute float fontBoundingBoxAscent;
-    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute float fontBoundingBoxDescent;
-    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute float actualBoundingBoxAscent;
-    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute float actualBoundingBoxDescent;
-    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute float emHeightAscent;
-    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute float emHeightDescent;
-    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute float hangingBaseline;
-    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute float alphabeticBaseline;
-    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute float ideographicBaseline;
+    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute double fontBoundingBoxAscent;
+    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute double fontBoundingBoxDescent;
+    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute double actualBoundingBoxAscent;
+    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute double actualBoundingBoxDescent;
+    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute double emHeightAscent;
+    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute double emHeightDescent;
+    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute double hangingBaseline;
+    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute double alphabeticBaseline;
+    [RuntimeEnabled=ExperimentalCanvasFeatures] readonly attribute double ideographicBaseline;
 };
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasImageSource.h b/third_party/WebKit/Source/core/html/canvas/CanvasImageSource.h
index c6a83c8..08b4cfd6 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasImageSource.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasImageSource.h
@@ -84,9 +84,6 @@
   virtual bool IsOpaque() const { return false; }
   virtual bool IsAccelerated() const = 0;
 
-  virtual int SourceWidth() = 0;
-  virtual int SourceHeight() = 0;
-
  protected:
   virtual ~CanvasImageSource() {}
 };
diff --git a/third_party/WebKit/Source/core/html/canvas/ImageElementBase.cpp b/third_party/WebKit/Source/core/html/canvas/ImageElementBase.cpp
index 0cffe51..1cf51db5 100644
--- a/third_party/WebKit/Source/core/html/canvas/ImageElementBase.cpp
+++ b/third_party/WebKit/Source/core/html/canvas/ImageElementBase.cpp
@@ -120,22 +120,6 @@
   return CachedImage()->GetResponse().Url();
 }
 
-int ImageElementBase::SourceWidth() {
-  SourceImageStatus status;
-  RefPtr<Image> image = GetSourceImageForCanvas(&status, kPreferNoAcceleration,
-                                                kSnapshotReasonUnknown,
-                                                SourceDefaultObjectSize());
-  return image->width();
-}
-
-int ImageElementBase::SourceHeight() {
-  SourceImageStatus status;
-  RefPtr<Image> image = GetSourceImageForCanvas(&status, kPreferNoAcceleration,
-                                                kSnapshotReasonUnknown,
-                                                SourceDefaultObjectSize());
-  return image->height();
-}
-
 bool ImageElementBase::IsOpaque() const {
   Image* image = const_cast<Element&>(GetElement()).ImageContents();
   return image && image->CurrentFrameKnownToBeOpaque();
diff --git a/third_party/WebKit/Source/core/html/canvas/ImageElementBase.h b/third_party/WebKit/Source/core/html/canvas/ImageElementBase.h
index 27eae2e..20a0299 100644
--- a/third_party/WebKit/Source/core/html/canvas/ImageElementBase.h
+++ b/third_party/WebKit/Source/core/html/canvas/ImageElementBase.h
@@ -47,9 +47,6 @@
 
   bool IsAccelerated() const override;
 
-  int SourceWidth() override;
-  int SourceHeight() override;
-
   bool IsSVGSource() const override;
 
   bool IsOpaque() const override;
diff --git a/third_party/WebKit/Source/core/html/media/HTMLVideoElement.h b/third_party/WebKit/Source/core/html/media/HTMLVideoElement.h
index 6b96b94..ec4886f 100644
--- a/third_party/WebKit/Source/core/html/media/HTMLVideoElement.h
+++ b/third_party/WebKit/Source/core/html/media/HTMLVideoElement.h
@@ -128,8 +128,6 @@
   FloatSize ElementSize(const FloatSize&) const override;
   const KURL& SourceURL() const override { return currentSrc(); }
   bool IsHTMLVideoElement() const override { return true; }
-  int SourceWidth() override { return videoWidth(); }
-  int SourceHeight() override { return videoHeight(); }
   // Video elements currently always go through RAM when used as a canvas image
   // source.
   bool IsAccelerated() const override { return false; }
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.h b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.h
index aad917e..8d4726e 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.h
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.h
@@ -125,8 +125,6 @@
   void AdjustDrawRects(FloatRect* src_rect, FloatRect* dst_rect) const override;
   FloatSize ElementSize(const FloatSize&) const override;
   bool IsImageBitmap() const override { return true; }
-  int SourceWidth() override { return image_ ? image_->width() : 0; }
-  int SourceHeight() override { return image_ ? image_->height() : 0; }
   bool IsAccelerated() const override;
 
   // ImageBitmapSource implementation
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
index 788763c..5007861 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -3559,7 +3559,8 @@
 //  Punctuation characters are considered as first-letter. For "(1)ab",
 //  "(1)" are first-letter part and "ab" are remaining part.
 const LayoutObject* AssociatedLayoutObjectOf(const Node& node,
-                                             int offset_in_node) {
+                                             int offset_in_node,
+                                             LayoutObjectSide object_side) {
   DCHECK_GE(offset_in_node, 0);
   LayoutObject* layout_object = node.GetLayoutObject();
   if (!node.IsTextNode() || !layout_object ||
@@ -3573,9 +3574,14 @@
         layout_text_fragment->Start() + layout_text_fragment->FragmentLength());
     return layout_text_fragment;
   }
-  if (layout_text_fragment->FragmentLength() &&
-      static_cast<unsigned>(offset_in_node) >= layout_text_fragment->Start())
-    return layout_object;
+  if (layout_text_fragment->FragmentLength()) {
+    const unsigned threshold =
+        object_side == LayoutObjectSide::kRemainingTextIfOnBoundary
+            ? layout_text_fragment->Start()
+            : layout_text_fragment->Start() + 1;
+    if (static_cast<unsigned>(offset_in_node) >= threshold)
+      return layout_object;
+  }
   LayoutObject* first_letter_layout_object =
       layout_text_fragment->GetFirstLetterPseudoElement()->GetLayoutObject();
   // TODO(yosin): We're not sure when |firstLetterLayoutObject| has
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h
index 888be2a..1642869 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -2790,8 +2790,14 @@
   return AdjustScrollForAbsoluteZoom(value, layout_object.StyleRef());
 }
 
-CORE_EXPORT const LayoutObject* AssociatedLayoutObjectOf(const Node&,
-                                                         int offset_in_node);
+enum class LayoutObjectSide {
+  kRemainingTextIfOnBoundary,
+  kFirstLetterIfOnBoundary
+};
+CORE_EXPORT const LayoutObject* AssociatedLayoutObjectOf(
+    const Node&,
+    int offset_in_node,
+    LayoutObjectSide = LayoutObjectSide::kRemainingTextIfOnBoundary);
 
 #define DEFINE_LAYOUT_OBJECT_TYPE_CASTS(thisType, predicate)           \
   DEFINE_TYPE_CASTS(thisType, LayoutObject, object, object->predicate, \
diff --git a/third_party/WebKit/Source/core/layout/LayoutTextTest.cpp b/third_party/WebKit/Source/core/layout/LayoutTextTest.cpp
index 9158a928..8c25a99 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTextTest.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTextTest.cpp
@@ -7,6 +7,7 @@
 #include "core/layout/LayoutTestHelper.h"
 #include "core/layout/line/InlineTextBox.h"
 #include "platform/runtime_enabled_features.h"
+#include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
@@ -96,8 +97,8 @@
 }
 
 TEST_F(LayoutTextTest, CaretMinMaxOffsetNG) {
-  RuntimeEnabledFeatures::SetLayoutNGEnabled(true);
-  RuntimeEnabledFeatures::SetLayoutNGPaintFragmentsEnabled(true);
+  ScopedLayoutNGForTest layout_ng(true);
+  ScopedLayoutNGPaintFragmentsForTest layout_ng_paint_fragments(true);
 
   SetBasicBody("foo");
   EXPECT_EQ(0, GetBasicText()->CaretMinOffset());
@@ -117,8 +118,8 @@
 }
 
 TEST_F(LayoutTextTest, ResolvedTextLengthNG) {
-  RuntimeEnabledFeatures::SetLayoutNGEnabled(true);
-  RuntimeEnabledFeatures::SetLayoutNGPaintFragmentsEnabled(true);
+  ScopedLayoutNGForTest layout_ng(true);
+  ScopedLayoutNGPaintFragmentsForTest layout_ng_paint_fragments(true);
 
   SetBasicBody("foo");
   EXPECT_EQ(3u, GetBasicText()->ResolvedTextLength());
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
index 4526261..932d6ba 100644
--- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
+++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
@@ -142,8 +142,6 @@
   }
   bool IsOpaque() const final;
   bool IsAccelerated() const final;
-  int SourceWidth() final { return width(); }
-  int SourceHeight() final { return height(); }
 
   DispatchEventResult HostDispatchEvent(Event* event) {
     return DispatchEvent(event);
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
index 5631afc..05d5c58c 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
@@ -771,9 +771,9 @@
 
   // y direction
   const FontMetrics& font_metrics = font_data->GetFontMetrics();
-  const float ascent = font_metrics.FloatAscent();
-  const float descent = font_metrics.FloatDescent();
-  const float baseline_y = GetFontBaseline(font_metrics);
+  const double ascent = font_metrics.FloatAscent();
+  const double descent = font_metrics.FloatDescent();
+  const double baseline_y = GetFontBaseline(font_metrics);
 
   metrics->SetFontBoundingBoxAscent(ascent - baseline_y);
   metrics->SetFontBoundingBoxDescent(descent + baseline_y);
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
index 9419d995..0e96bf6 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
@@ -65,8 +65,6 @@
   }
   bool IsOpaque() const override { return is_opaque_; }
   bool IsAccelerated() const { return false; }
-  int SourceWidth() override { return size_.Width(); }
-  int SourceHeight() override { return size_.Height(); }
 
   ~FakeImageSource() override {}
 
diff --git a/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp b/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp
index 863d9b91..6b2bd538 100644
--- a/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp
+++ b/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp
@@ -88,8 +88,7 @@
   // there is a local WebCam associated, there might be sophisticated ways to
   // detect faces on it. Until then, treat as a normal <video> element.
 
-  const FloatSize size(canvas_image_source->SourceWidth(),
-                       canvas_image_source->SourceHeight());
+  const FloatSize size(canvas_image_source->ElementSize(FloatSize()));
 
   SourceImageStatus source_image_status = kInvalidSourceImageStatus;
   RefPtr<Image> image = canvas_image_source->GetSourceImageForCanvas(
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioParam.cpp b/third_party/WebKit/Source/modules/webaudio/AudioParam.cpp
index 536dbdb..36064fd 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioParam.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioParam.cpp
@@ -136,8 +136,8 @@
       return "AudioListener.upY";
     case kParamTypeAudioListenerUpZ:
       return "AudioListener.upZ";
-    case kParamTypeConstantSourceValue:
-      return "ConstantSource.sourceValue";
+    case kParamTypeConstantSourceOffset:
+      return "ConstantSource.offset";
     // TODO(hongchan): We can try to return the actual parameter name here if
     // possible.
     case kParamTypeAudioWorklet:
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioParam.h b/third_party/WebKit/Source/modules/webaudio/AudioParam.h
index 5f1deae..e6075ce 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioParam.h
+++ b/third_party/WebKit/Source/modules/webaudio/AudioParam.h
@@ -82,7 +82,7 @@
   kParamTypeAudioListenerUpX,
   kParamTypeAudioListenerUpY,
   kParamTypeAudioListenerUpZ,
-  kParamTypeConstantSourceValue,
+  kParamTypeConstantSourceOffset,
   kParamTypeAudioWorklet,
 };
 
diff --git a/third_party/WebKit/Source/modules/webaudio/ConstantSourceNode.cpp b/third_party/WebKit/Source/modules/webaudio/ConstantSourceNode.cpp
index e85d7f68..e6b9b78 100644
--- a/third_party/WebKit/Source/modules/webaudio/ConstantSourceNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/ConstantSourceNode.cpp
@@ -107,7 +107,7 @@
 // ----------------------------------------------------------------
 ConstantSourceNode::ConstantSourceNode(BaseAudioContext& context)
     : AudioScheduledSourceNode(context),
-      offset_(AudioParam::Create(context, kParamTypeConstantSourceValue, 1)) {
+      offset_(AudioParam::Create(context, kParamTypeConstantSourceOffset, 1)) {
   SetHandler(ConstantSourceHandler::Create(*this, context.sampleRate(),
                                            offset_->Handler()));
 }
diff --git a/third_party/WebKit/Source/platform/testing/RuntimeEnabledFeaturesTestHelpers.h b/third_party/WebKit/Source/platform/testing/RuntimeEnabledFeaturesTestHelpers.h
index 3da1e9e..9f614fd 100644
--- a/third_party/WebKit/Source/platform/testing/RuntimeEnabledFeaturesTestHelpers.h
+++ b/third_party/WebKit/Source/platform/testing/RuntimeEnabledFeaturesTestHelpers.h
@@ -153,6 +153,10 @@
     RuntimeEnabledFeatures::SetLayoutNGEnabled>
     ScopedLayoutNGForTest;
 typedef ScopedRuntimeEnabledFeatureForTest<
+    RuntimeEnabledFeatures::LayoutNGPaintFragmentsEnabled,
+    RuntimeEnabledFeatures::SetLayoutNGPaintFragmentsEnabled>
+    ScopedLayoutNGPaintFragmentsForTest;
+typedef ScopedRuntimeEnabledFeatureForTest<
     RuntimeEnabledFeatures::ClientPlaceholdersForServerLoFiEnabled,
     RuntimeEnabledFeatures::SetClientPlaceholdersForServerLoFiEnabled>
     ScopedClientPlaceholdersForServerLoFiForTest;
diff --git a/third_party/WebKit/Source/platform/text/BidiResolver.h b/third_party/WebKit/Source/platform/text/BidiResolver.h
index 5a38812..3ae9aa0c 100644
--- a/third_party/WebKit/Source/platform/text/BidiResolver.h
+++ b/third_party/WebKit/Source/platform/text/BidiResolver.h
@@ -434,60 +434,60 @@
   // Isolated spans compute base directionality during their own UBA run.
   // Do not insert fake embed characters once we enter an isolated span.
   DCHECK(!InIsolate());
-  using namespace WTF::Unicode;
 
-  DCHECK(dir == kPopDirectionalFormat || dir == kLeftToRightEmbedding ||
-         dir == kLeftToRightOverride || dir == kRightToLeftEmbedding ||
-         dir == kRightToLeftOverride);
+  DCHECK(dir == WTF::Unicode::kPopDirectionalFormat ||
+         dir == WTF::Unicode::kLeftToRightEmbedding ||
+         dir == WTF::Unicode::kLeftToRightOverride ||
+         dir == WTF::Unicode::kRightToLeftEmbedding ||
+         dir == WTF::Unicode::kRightToLeftOverride);
   current_explicit_embedding_sequence_.push_back(BidiEmbedding(dir, source));
 }
 
 template <class Iterator, class Run, class IsolatedRun>
 void BidiResolver<Iterator, Run, IsolatedRun>::
     CheckDirectionInLowerRaiseEmbeddingLevel() {
-  using namespace WTF::Unicode;
-
-  DCHECK(status_.eor != kOtherNeutral || eor_.AtEnd());
-  DCHECK_NE(status_.last, kNonSpacingMark);
-  DCHECK_NE(status_.last, kBoundaryNeutral);
-  DCHECK_NE(status_.last, kRightToLeftEmbedding);
-  DCHECK_NE(status_.last, kLeftToRightEmbedding);
-  DCHECK_NE(status_.last, kRightToLeftOverride);
-  DCHECK_NE(status_.last, kLeftToRightOverride);
-  DCHECK_NE(status_.last, kPopDirectionalFormat);
-  if (direction_ == kOtherNeutral)
-    direction_ =
-        status_.last_strong == kLeftToRight ? kLeftToRight : kRightToLeft;
+  DCHECK(status_.eor != WTF::Unicode::kOtherNeutral || eor_.AtEnd());
+  DCHECK_NE(status_.last, WTF::Unicode::kNonSpacingMark);
+  DCHECK_NE(status_.last, WTF::Unicode::kBoundaryNeutral);
+  DCHECK_NE(status_.last, WTF::Unicode::kRightToLeftEmbedding);
+  DCHECK_NE(status_.last, WTF::Unicode::kLeftToRightEmbedding);
+  DCHECK_NE(status_.last, WTF::Unicode::kRightToLeftOverride);
+  DCHECK_NE(status_.last, WTF::Unicode::kLeftToRightOverride);
+  DCHECK_NE(status_.last, WTF::Unicode::kPopDirectionalFormat);
+  if (direction_ == WTF::Unicode::kOtherNeutral) {
+    direction_ = status_.last_strong == WTF::Unicode::kLeftToRight
+                     ? WTF::Unicode::kLeftToRight
+                     : WTF::Unicode::kRightToLeft;
+  }
 }
 
 template <class Iterator, class Run, class IsolatedRun>
 void BidiResolver<Iterator, Run, IsolatedRun>::LowerExplicitEmbeddingLevel(
     BidiRunList<Run>& runs,
     WTF::Unicode::CharDirection from) {
-  using namespace WTF::Unicode;
-
   if (!empty_run_ && eor_ != last_) {
     CheckDirectionInLowerRaiseEmbeddingLevel();
     // bidi.sor ... bidi.eor ... bidi.last eor; need to append the
     // bidi.sor-bidi.eor run or extend it through bidi.last
-    if (from == kLeftToRight) {
+    if (from == WTF::Unicode::kLeftToRight) {
       // bidi.sor ... bidi.eor ... bidi.last L
-      if (status_.eor == kEuropeanNumber) {
-        if (status_.last_strong != kLeftToRight) {
-          direction_ = kEuropeanNumber;
+      if (status_.eor == WTF::Unicode::kEuropeanNumber) {
+        if (status_.last_strong != WTF::Unicode::kLeftToRight) {
+          direction_ = WTF::Unicode::kEuropeanNumber;
           AppendRun(runs);
         }
-      } else if (status_.eor == kArabicNumber) {
-        direction_ = kArabicNumber;
+      } else if (status_.eor == WTF::Unicode::kArabicNumber) {
+        direction_ = WTF::Unicode::kArabicNumber;
         AppendRun(runs);
-      } else if (status_.last_strong != kLeftToRight) {
+      } else if (status_.last_strong != WTF::Unicode::kLeftToRight) {
         AppendRun(runs);
-        direction_ = kLeftToRight;
+        direction_ = WTF::Unicode::kLeftToRight;
       }
-    } else if (status_.eor == kEuropeanNumber || status_.eor == kArabicNumber ||
-               status_.last_strong == kLeftToRight) {
+    } else if (status_.eor == WTF::Unicode::kEuropeanNumber ||
+               status_.eor == WTF::Unicode::kArabicNumber ||
+               status_.last_strong == WTF::Unicode::kLeftToRight) {
       AppendRun(runs);
-      direction_ = kRightToLeft;
+      direction_ = WTF::Unicode::kRightToLeft;
     }
     eor_ = last_;
   }
@@ -506,34 +506,34 @@
     BidiRunList<Run>& runs,
     WTF::Unicode::CharDirection from,
     WTF::Unicode::CharDirection to) {
-  using namespace WTF::Unicode;
-
   if (!empty_run_ && eor_ != last_) {
     CheckDirectionInLowerRaiseEmbeddingLevel();
     // bidi.sor ... bidi.eor ... bidi.last eor; need to append the
     // bidi.sor-bidi.eor run or extend it through bidi.last
-    if (to == kLeftToRight) {
+    if (to == WTF::Unicode::kLeftToRight) {
       // bidi.sor ... bidi.eor ... bidi.last L
-      if (status_.eor == kEuropeanNumber) {
-        if (status_.last_strong != kLeftToRight) {
-          direction_ = kEuropeanNumber;
+      if (status_.eor == WTF::Unicode::kEuropeanNumber) {
+        if (status_.last_strong != WTF::Unicode::kLeftToRight) {
+          direction_ = WTF::Unicode::kEuropeanNumber;
           AppendRun(runs);
         }
-      } else if (status_.eor == kArabicNumber) {
-        direction_ = kArabicNumber;
+      } else if (status_.eor == WTF::Unicode::kArabicNumber) {
+        direction_ = WTF::Unicode::kArabicNumber;
         AppendRun(runs);
-      } else if (status_.last_strong != kLeftToRight && from == kLeftToRight) {
+      } else if (status_.last_strong != WTF::Unicode::kLeftToRight &&
+                 from == WTF::Unicode::kLeftToRight) {
         AppendRun(runs);
-        direction_ = kLeftToRight;
+        direction_ = WTF::Unicode::kLeftToRight;
       }
-    } else if (status_.eor == kArabicNumber ||
-               (status_.eor == kEuropeanNumber &&
-                (status_.last_strong != kLeftToRight ||
-                 from == kRightToLeft)) ||
-               (status_.eor != kEuropeanNumber &&
-                status_.last_strong == kLeftToRight && from == kRightToLeft)) {
+    } else if (status_.eor == WTF::Unicode::kArabicNumber ||
+               (status_.eor == WTF::Unicode::kEuropeanNumber &&
+                (status_.last_strong != WTF::Unicode::kLeftToRight ||
+                 from == WTF::Unicode::kRightToLeft)) ||
+               (status_.eor != WTF::Unicode::kEuropeanNumber &&
+                status_.last_strong == WTF::Unicode::kLeftToRight &&
+                from == WTF::Unicode::kRightToLeft)) {
       AppendRun(runs);
-      direction_ = kRightToLeft;
+      direction_ = WTF::Unicode::kRightToLeft;
     }
     eor_ = last_;
   }
@@ -598,26 +598,25 @@
   // content.
   DCHECK(!InIsolate() || current_explicit_embedding_sequence_.IsEmpty());
 
-  using namespace WTF::Unicode;
-
   unsigned char from_level = Context()->Level();
   RefPtr<BidiContext> to_context = Context();
 
   for (size_t i = 0; i < current_explicit_embedding_sequence_.size(); ++i) {
     BidiEmbedding embedding = current_explicit_embedding_sequence_[i];
-    if (embedding.Direction() == kPopDirectionalFormat) {
+    if (embedding.Direction() == WTF::Unicode::kPopDirectionalFormat) {
       if (BidiContext* parent_context = to_context->Parent())
         to_context = parent_context;
     } else {
-      CharDirection direction =
-          (embedding.Direction() == kRightToLeftEmbedding ||
-           embedding.Direction() == kRightToLeftOverride)
-              ? kRightToLeft
-              : kLeftToRight;
-      bool override = embedding.Direction() == kLeftToRightOverride ||
-                      embedding.Direction() == kRightToLeftOverride;
+      WTF::Unicode::CharDirection direction =
+          (embedding.Direction() == WTF::Unicode::kRightToLeftEmbedding ||
+           embedding.Direction() == WTF::Unicode::kRightToLeftOverride)
+              ? WTF::Unicode::kRightToLeft
+              : WTF::Unicode::kLeftToRight;
+      bool override =
+          embedding.Direction() == WTF::Unicode::kLeftToRightOverride ||
+          embedding.Direction() == WTF::Unicode::kRightToLeftOverride;
       unsigned char level = to_context->Level();
-      if (direction == kRightToLeft)
+      if (direction == WTF::Unicode::kRightToLeft)
         level = NextGreaterOddLevel(level);
       else
         level = NextGreaterEvenLevel(level);
@@ -630,13 +629,17 @@
 
   unsigned char to_level = to_context->Level();
 
-  if (to_level > from_level)
-    RaiseExplicitEmbeddingLevel(runs,
-                                from_level % 2 ? kRightToLeft : kLeftToRight,
-                                to_level % 2 ? kRightToLeft : kLeftToRight);
-  else if (to_level < from_level)
-    LowerExplicitEmbeddingLevel(runs,
-                                from_level % 2 ? kRightToLeft : kLeftToRight);
+  if (to_level > from_level) {
+    RaiseExplicitEmbeddingLevel(
+        runs,
+        from_level % 2 ? WTF::Unicode::kRightToLeft
+                       : WTF::Unicode::kLeftToRight,
+        to_level % 2 ? WTF::Unicode::kRightToLeft : WTF::Unicode::kLeftToRight);
+  } else if (to_level < from_level) {
+    LowerExplicitEmbeddingLevel(runs, from_level % 2
+                                          ? WTF::Unicode::kRightToLeft
+                                          : WTF::Unicode::kLeftToRight);
+  }
 
   SetContext(to_context);
 
@@ -649,39 +652,38 @@
 inline void
 BidiResolver<Iterator, Run, IsolatedRun>::UpdateStatusLastFromCurrentDirection(
     WTF::Unicode::CharDirection dir_current) {
-  using namespace WTF::Unicode;
   switch (dir_current) {
-    case kEuropeanNumberTerminator:
-      if (status_.last != kEuropeanNumber)
-        status_.last = kEuropeanNumberTerminator;
+    case WTF::Unicode::kEuropeanNumberTerminator:
+      if (status_.last != WTF::Unicode::kEuropeanNumber)
+        status_.last = WTF::Unicode::kEuropeanNumberTerminator;
       break;
-    case kEuropeanNumberSeparator:
-    case kCommonNumberSeparator:
-    case kSegmentSeparator:
-    case kWhiteSpaceNeutral:
-    case kOtherNeutral:
+    case WTF::Unicode::kEuropeanNumberSeparator:
+    case WTF::Unicode::kCommonNumberSeparator:
+    case WTF::Unicode::kSegmentSeparator:
+    case WTF::Unicode::kWhiteSpaceNeutral:
+    case WTF::Unicode::kOtherNeutral:
       switch (status_.last) {
-        case kLeftToRight:
-        case kRightToLeft:
-        case kRightToLeftArabic:
-        case kEuropeanNumber:
-        case kArabicNumber:
+        case WTF::Unicode::kLeftToRight:
+        case WTF::Unicode::kRightToLeft:
+        case WTF::Unicode::kRightToLeftArabic:
+        case WTF::Unicode::kEuropeanNumber:
+        case WTF::Unicode::kArabicNumber:
           status_.last = dir_current;
           break;
         default:
-          status_.last = kOtherNeutral;
+          status_.last = WTF::Unicode::kOtherNeutral;
       }
       break;
-    case kNonSpacingMark:
-    case kBoundaryNeutral:
-    case kRightToLeftEmbedding:
-    case kLeftToRightEmbedding:
-    case kRightToLeftOverride:
-    case kLeftToRightOverride:
-    case kPopDirectionalFormat:
+    case WTF::Unicode::kNonSpacingMark:
+    case WTF::Unicode::kBoundaryNeutral:
+    case WTF::Unicode::kRightToLeftEmbedding:
+    case WTF::Unicode::kLeftToRightEmbedding:
+    case WTF::Unicode::kRightToLeftOverride:
+    case WTF::Unicode::kLeftToRightOverride:
+    case WTF::Unicode::kPopDirectionalFormat:
       // ignore these
       break;
-    case kEuropeanNumber:
+    case WTF::Unicode::kEuropeanNumber:
     // fall through
     default:
       status_.last = dir_current;
@@ -790,9 +792,7 @@
     VisualDirectionOverride override,
     bool hard_line_break,
     bool reorder_runs) {
-  using namespace WTF::Unicode;
-
-  DCHECK_EQ(direction_, kOtherNeutral);
+  DCHECK_EQ(direction_, WTF::Unicode::kOtherNeutral);
   trailing_space_run_ = 0;
 
   end_of_line_ = end;
@@ -805,8 +805,9 @@
       eor_ = current_;
       Increment();
     }
-    direction_ =
-        override == kVisualLeftToRightOverride ? kLeftToRight : kRightToLeft;
+    direction_ = override == kVisualLeftToRightOverride
+                     ? WTF::Unicode::kLeftToRight
+                     : WTF::Unicode::kRightToLeft;
     AppendRun(runs_);
     runs_.SetLogicallyLastRun(runs_.LastRun());
     if (override == kVisualRightToLeftOverride && runs_.RunCount())
@@ -842,7 +843,7 @@
       end_of_run_at_end_of_line_ = last_;
       last_line_ended = true;
     }
-    CharDirection dir_current;
+    WTF::Unicode::CharDirection dir_current;
     if (last_line_ended && (hard_line_break || current_.AtEnd())) {
       BidiContext* c = Context();
       if (hard_line_break) {
@@ -863,83 +864,84 @@
       }
     } else {
       dir_current = current_.Direction();
-      if (Context()->Override() && dir_current != kRightToLeftEmbedding &&
-          dir_current != kLeftToRightEmbedding &&
-          dir_current != kRightToLeftOverride &&
-          dir_current != kLeftToRightOverride &&
-          dir_current != kPopDirectionalFormat)
+      if (Context()->Override() &&
+          dir_current != WTF::Unicode::kRightToLeftEmbedding &&
+          dir_current != WTF::Unicode::kLeftToRightEmbedding &&
+          dir_current != WTF::Unicode::kRightToLeftOverride &&
+          dir_current != WTF::Unicode::kLeftToRightOverride &&
+          dir_current != WTF::Unicode::kPopDirectionalFormat)
         dir_current = Context()->Dir();
-      else if (dir_current == kNonSpacingMark)
+      else if (dir_current == WTF::Unicode::kNonSpacingMark)
         dir_current = status_.last;
     }
 
     // We ignore all character directionality while in unicode-bidi: isolate
     // spans.  We'll handle ordering the isolated characters in a second pass.
     if (InIsolate())
-      dir_current = kOtherNeutral;
+      dir_current = WTF::Unicode::kOtherNeutral;
 
-    DCHECK(status_.eor != kOtherNeutral || eor_.AtEnd());
+    DCHECK(status_.eor != WTF::Unicode::kOtherNeutral || eor_.AtEnd());
     switch (dir_current) {
       // embedding and overrides (X1-X9 in the Bidi specs)
-      case kRightToLeftEmbedding:
-      case kLeftToRightEmbedding:
-      case kRightToLeftOverride:
-      case kLeftToRightOverride:
-      case kPopDirectionalFormat:
+      case WTF::Unicode::kRightToLeftEmbedding:
+      case WTF::Unicode::kLeftToRightEmbedding:
+      case WTF::Unicode::kRightToLeftOverride:
+      case WTF::Unicode::kLeftToRightOverride:
+      case WTF::Unicode::kPopDirectionalFormat:
         Embed(dir_current, kFromUnicode);
         CommitExplicitEmbedding(runs_);
         break;
 
       // strong types
-      case kLeftToRight:
+      case WTF::Unicode::kLeftToRight:
         switch (status_.last) {
-          case kRightToLeft:
-          case kRightToLeftArabic:
-          case kEuropeanNumber:
-          case kArabicNumber:
-            if (status_.last != kEuropeanNumber ||
-                status_.last_strong != kLeftToRight)
+          case WTF::Unicode::kRightToLeft:
+          case WTF::Unicode::kRightToLeftArabic:
+          case WTF::Unicode::kEuropeanNumber:
+          case WTF::Unicode::kArabicNumber:
+            if (status_.last != WTF::Unicode::kEuropeanNumber ||
+                status_.last_strong != WTF::Unicode::kLeftToRight)
               AppendRun(runs_);
             break;
-          case kLeftToRight:
+          case WTF::Unicode::kLeftToRight:
             break;
-          case kEuropeanNumberSeparator:
-          case kEuropeanNumberTerminator:
-          case kCommonNumberSeparator:
-          case kBoundaryNeutral:
-          case kBlockSeparator:
-          case kSegmentSeparator:
-          case kWhiteSpaceNeutral:
-          case kOtherNeutral:
-            if (status_.eor == kEuropeanNumber) {
-              if (status_.last_strong != kLeftToRight) {
+          case WTF::Unicode::kEuropeanNumberSeparator:
+          case WTF::Unicode::kEuropeanNumberTerminator:
+          case WTF::Unicode::kCommonNumberSeparator:
+          case WTF::Unicode::kBoundaryNeutral:
+          case WTF::Unicode::kBlockSeparator:
+          case WTF::Unicode::kSegmentSeparator:
+          case WTF::Unicode::kWhiteSpaceNeutral:
+          case WTF::Unicode::kOtherNeutral:
+            if (status_.eor == WTF::Unicode::kEuropeanNumber) {
+              if (status_.last_strong != WTF::Unicode::kLeftToRight) {
                 // the numbers need to be on a higher embedding level, so let's
                 // close that run
-                direction_ = kEuropeanNumber;
+                direction_ = WTF::Unicode::kEuropeanNumber;
                 AppendRun(runs_);
-                if (Context()->Dir() != kLeftToRight) {
+                if (Context()->Dir() != WTF::Unicode::kLeftToRight) {
                   // the neutrals take the embedding direction, which is R
                   eor_ = last_;
-                  direction_ = kRightToLeft;
+                  direction_ = WTF::Unicode::kRightToLeft;
                   AppendRun(runs_);
                 }
               }
-            } else if (status_.eor == kArabicNumber) {
+            } else if (status_.eor == WTF::Unicode::kArabicNumber) {
               // Arabic numbers are always on a higher embedding level, so let's
               // close that run
-              direction_ = kArabicNumber;
+              direction_ = WTF::Unicode::kArabicNumber;
               AppendRun(runs_);
-              if (Context()->Dir() != kLeftToRight) {
+              if (Context()->Dir() != WTF::Unicode::kLeftToRight) {
                 // the neutrals take the embedding direction, which is R
                 eor_ = last_;
-                direction_ = kRightToLeft;
+                direction_ = WTF::Unicode::kRightToLeft;
                 AppendRun(runs_);
               }
-            } else if (status_.last_strong != kLeftToRight) {
+            } else if (status_.last_strong != WTF::Unicode::kLeftToRight) {
               // last stuff takes embedding dir
-              if (Context()->Dir() == kRightToLeft) {
+              if (Context()->Dir() == WTF::Unicode::kRightToLeft) {
                 eor_ = last_;
-                direction_ = kRightToLeft;
+                direction_ = WTF::Unicode::kRightToLeft;
               }
               AppendRun(runs_);
             }
@@ -947,37 +949,37 @@
             break;
         }
         eor_ = current_;
-        status_.eor = kLeftToRight;
-        status_.last_strong = kLeftToRight;
-        direction_ = kLeftToRight;
+        status_.eor = WTF::Unicode::kLeftToRight;
+        status_.last_strong = WTF::Unicode::kLeftToRight;
+        direction_ = WTF::Unicode::kLeftToRight;
         break;
-      case kRightToLeftArabic:
-      case kRightToLeft:
+      case WTF::Unicode::kRightToLeftArabic:
+      case WTF::Unicode::kRightToLeft:
         switch (status_.last) {
-          case kLeftToRight:
-          case kEuropeanNumber:
-          case kArabicNumber:
+          case WTF::Unicode::kLeftToRight:
+          case WTF::Unicode::kEuropeanNumber:
+          case WTF::Unicode::kArabicNumber:
             AppendRun(runs_);
-          case kRightToLeft:
-          case kRightToLeftArabic:
+          case WTF::Unicode::kRightToLeft:
+          case WTF::Unicode::kRightToLeftArabic:
             break;
-          case kEuropeanNumberSeparator:
-          case kEuropeanNumberTerminator:
-          case kCommonNumberSeparator:
-          case kBoundaryNeutral:
-          case kBlockSeparator:
-          case kSegmentSeparator:
-          case kWhiteSpaceNeutral:
-          case kOtherNeutral:
-            if (status_.eor == kEuropeanNumber) {
-              if (status_.last_strong == kLeftToRight &&
-                  Context()->Dir() == kLeftToRight)
+          case WTF::Unicode::kEuropeanNumberSeparator:
+          case WTF::Unicode::kEuropeanNumberTerminator:
+          case WTF::Unicode::kCommonNumberSeparator:
+          case WTF::Unicode::kBoundaryNeutral:
+          case WTF::Unicode::kBlockSeparator:
+          case WTF::Unicode::kSegmentSeparator:
+          case WTF::Unicode::kWhiteSpaceNeutral:
+          case WTF::Unicode::kOtherNeutral:
+            if (status_.eor == WTF::Unicode::kEuropeanNumber) {
+              if (status_.last_strong == WTF::Unicode::kLeftToRight &&
+                  Context()->Dir() == WTF::Unicode::kLeftToRight)
                 eor_ = last_;
               AppendRun(runs_);
-            } else if (status_.eor == kArabicNumber) {
+            } else if (status_.eor == WTF::Unicode::kArabicNumber) {
               AppendRun(runs_);
-            } else if (status_.last_strong == kLeftToRight) {
-              if (Context()->Dir() == kLeftToRight)
+            } else if (status_.last_strong == WTF::Unicode::kLeftToRight) {
+              if (Context()->Dir() == WTF::Unicode::kLeftToRight)
                 eor_ = last_;
               AppendRun(runs_);
             }
@@ -985,123 +987,124 @@
             break;
         }
         eor_ = current_;
-        status_.eor = kRightToLeft;
+        status_.eor = WTF::Unicode::kRightToLeft;
         status_.last_strong = dir_current;
-        direction_ = kRightToLeft;
+        direction_ = WTF::Unicode::kRightToLeft;
         break;
 
       // weak types:
 
-      case kEuropeanNumber:
-        if (status_.last_strong != kRightToLeftArabic) {
+      case WTF::Unicode::kEuropeanNumber:
+        if (status_.last_strong != WTF::Unicode::kRightToLeftArabic) {
           // if last strong was AL change EN to AN
           switch (status_.last) {
-            case kEuropeanNumber:
-            case kLeftToRight:
+            case WTF::Unicode::kEuropeanNumber:
+            case WTF::Unicode::kLeftToRight:
               break;
-            case kRightToLeft:
-            case kRightToLeftArabic:
-            case kArabicNumber:
+            case WTF::Unicode::kRightToLeft:
+            case WTF::Unicode::kRightToLeftArabic:
+            case WTF::Unicode::kArabicNumber:
               eor_ = last_;
               AppendRun(runs_);
-              direction_ = kEuropeanNumber;
+              direction_ = WTF::Unicode::kEuropeanNumber;
               break;
-            case kEuropeanNumberSeparator:
-            case kCommonNumberSeparator:
-              if (status_.eor == kEuropeanNumber)
+            case WTF::Unicode::kEuropeanNumberSeparator:
+            case WTF::Unicode::kCommonNumberSeparator:
+              if (status_.eor == WTF::Unicode::kEuropeanNumber)
                 break;
-            case kEuropeanNumberTerminator:
-            case kBoundaryNeutral:
-            case kBlockSeparator:
-            case kSegmentSeparator:
-            case kWhiteSpaceNeutral:
-            case kOtherNeutral:
-              if (status_.eor == kEuropeanNumber) {
-                if (status_.last_strong == kRightToLeft) {
+            case WTF::Unicode::kEuropeanNumberTerminator:
+            case WTF::Unicode::kBoundaryNeutral:
+            case WTF::Unicode::kBlockSeparator:
+            case WTF::Unicode::kSegmentSeparator:
+            case WTF::Unicode::kWhiteSpaceNeutral:
+            case WTF::Unicode::kOtherNeutral:
+              if (status_.eor == WTF::Unicode::kEuropeanNumber) {
+                if (status_.last_strong == WTF::Unicode::kRightToLeft) {
                   // ENs on both sides behave like Rs, so the neutrals should be
                   // R.  Terminate the EN run.
                   AppendRun(runs_);
                   // Make an R run.
-                  eor_ = status_.last == kEuropeanNumberTerminator
+                  eor_ = status_.last == WTF::Unicode::kEuropeanNumberTerminator
                              ? last_before_et_
                              : last_;
-                  direction_ = kRightToLeft;
+                  direction_ = WTF::Unicode::kRightToLeft;
                   AppendRun(runs_);
                   // Begin a new EN run.
-                  direction_ = kEuropeanNumber;
+                  direction_ = WTF::Unicode::kEuropeanNumber;
                 }
-              } else if (status_.eor == kArabicNumber) {
+              } else if (status_.eor == WTF::Unicode::kArabicNumber) {
                 // Terminate the AN run.
                 AppendRun(runs_);
-                if (status_.last_strong == kRightToLeft ||
-                    Context()->Dir() == kRightToLeft) {
+                if (status_.last_strong == WTF::Unicode::kRightToLeft ||
+                    Context()->Dir() == WTF::Unicode::kRightToLeft) {
                   // Make an R run.
-                  eor_ = status_.last == kEuropeanNumberTerminator
+                  eor_ = status_.last == WTF::Unicode::kEuropeanNumberTerminator
                              ? last_before_et_
                              : last_;
-                  direction_ = kRightToLeft;
+                  direction_ = WTF::Unicode::kRightToLeft;
                   AppendRun(runs_);
                   // Begin a new EN run.
-                  direction_ = kEuropeanNumber;
+                  direction_ = WTF::Unicode::kEuropeanNumber;
                 }
-              } else if (status_.last_strong == kRightToLeft) {
+              } else if (status_.last_strong == WTF::Unicode::kRightToLeft) {
                 // Extend the R run to include the neutrals.
-                eor_ = status_.last == kEuropeanNumberTerminator
+                eor_ = status_.last == WTF::Unicode::kEuropeanNumberTerminator
                            ? last_before_et_
                            : last_;
-                direction_ = kRightToLeft;
+                direction_ = WTF::Unicode::kRightToLeft;
                 AppendRun(runs_);
                 // Begin a new EN run.
-                direction_ = kEuropeanNumber;
+                direction_ = WTF::Unicode::kEuropeanNumber;
               }
             default:
               break;
           }
           eor_ = current_;
-          status_.eor = kEuropeanNumber;
-          if (direction_ == kOtherNeutral)
-            direction_ = kLeftToRight;
+          status_.eor = WTF::Unicode::kEuropeanNumber;
+          if (direction_ == WTF::Unicode::kOtherNeutral)
+            direction_ = WTF::Unicode::kLeftToRight;
           break;
         }
-      case kArabicNumber:
-        dir_current = kArabicNumber;
+      case WTF::Unicode::kArabicNumber:
+        dir_current = WTF::Unicode::kArabicNumber;
         switch (status_.last) {
-          case kLeftToRight:
-            if (Context()->Dir() == kLeftToRight)
+          case WTF::Unicode::kLeftToRight:
+            if (Context()->Dir() == WTF::Unicode::kLeftToRight)
               AppendRun(runs_);
             break;
-          case kArabicNumber:
+          case WTF::Unicode::kArabicNumber:
             break;
-          case kRightToLeft:
-          case kRightToLeftArabic:
-          case kEuropeanNumber:
+          case WTF::Unicode::kRightToLeft:
+          case WTF::Unicode::kRightToLeftArabic:
+          case WTF::Unicode::kEuropeanNumber:
             eor_ = last_;
             AppendRun(runs_);
             break;
-          case kCommonNumberSeparator:
-            if (status_.eor == kArabicNumber)
+          case WTF::Unicode::kCommonNumberSeparator:
+            if (status_.eor == WTF::Unicode::kArabicNumber)
               break;
-          case kEuropeanNumberSeparator:
-          case kEuropeanNumberTerminator:
-          case kBoundaryNeutral:
-          case kBlockSeparator:
-          case kSegmentSeparator:
-          case kWhiteSpaceNeutral:
-          case kOtherNeutral:
-            if (status_.eor == kArabicNumber ||
-                (status_.eor == kEuropeanNumber &&
-                 (status_.last_strong == kRightToLeft ||
-                  Context()->Dir() == kRightToLeft)) ||
-                (status_.eor != kEuropeanNumber &&
-                 status_.last_strong == kLeftToRight &&
-                 Context()->Dir() == kRightToLeft)) {
+          case WTF::Unicode::kEuropeanNumberSeparator:
+          case WTF::Unicode::kEuropeanNumberTerminator:
+          case WTF::Unicode::kBoundaryNeutral:
+          case WTF::Unicode::kBlockSeparator:
+          case WTF::Unicode::kSegmentSeparator:
+          case WTF::Unicode::kWhiteSpaceNeutral:
+          case WTF::Unicode::kOtherNeutral:
+            if (status_.eor == WTF::Unicode::kArabicNumber ||
+                (status_.eor == WTF::Unicode::kEuropeanNumber &&
+                 (status_.last_strong == WTF::Unicode::kRightToLeft ||
+                  Context()->Dir() == WTF::Unicode::kRightToLeft)) ||
+                (status_.eor != WTF::Unicode::kEuropeanNumber &&
+                 status_.last_strong == WTF::Unicode::kLeftToRight &&
+                 Context()->Dir() == WTF::Unicode::kRightToLeft)) {
               // Terminate the run before the neutrals.
               AppendRun(runs_);
               // Begin an R run for the neutrals.
-              direction_ = kRightToLeft;
-            } else if (direction_ == kOtherNeutral) {
-              direction_ = status_.last_strong == kLeftToRight ? kLeftToRight
-                                                               : kRightToLeft;
+              direction_ = WTF::Unicode::kRightToLeft;
+            } else if (direction_ == WTF::Unicode::kOtherNeutral) {
+              direction_ = status_.last_strong == WTF::Unicode::kLeftToRight
+                               ? WTF::Unicode::kLeftToRight
+                               : WTF::Unicode::kRightToLeft;
             }
             eor_ = last_;
             AppendRun(runs_);
@@ -1109,39 +1112,39 @@
             break;
         }
         eor_ = current_;
-        status_.eor = kArabicNumber;
-        if (direction_ == kOtherNeutral)
-          direction_ = kArabicNumber;
+        status_.eor = WTF::Unicode::kArabicNumber;
+        if (direction_ == WTF::Unicode::kOtherNeutral)
+          direction_ = WTF::Unicode::kArabicNumber;
         break;
-      case kEuropeanNumberSeparator:
-      case kCommonNumberSeparator:
+      case WTF::Unicode::kEuropeanNumberSeparator:
+      case WTF::Unicode::kCommonNumberSeparator:
         break;
-      case kEuropeanNumberTerminator:
-        if (status_.last == kEuropeanNumber) {
-          dir_current = kEuropeanNumber;
+      case WTF::Unicode::kEuropeanNumberTerminator:
+        if (status_.last == WTF::Unicode::kEuropeanNumber) {
+          dir_current = WTF::Unicode::kEuropeanNumber;
           eor_ = current_;
           status_.eor = dir_current;
-        } else if (status_.last != kEuropeanNumberTerminator) {
+        } else if (status_.last != WTF::Unicode::kEuropeanNumberTerminator) {
           last_before_et_ = empty_run_ ? eor_ : last_;
         }
         break;
 
       // boundary neutrals should be ignored
-      case kBoundaryNeutral:
+      case WTF::Unicode::kBoundaryNeutral:
         if (eor_ == last_)
           eor_ = current_;
         break;
       // neutrals
-      case kBlockSeparator:
+      case WTF::Unicode::kBlockSeparator:
         // ### what do we do with newline and paragraph seperators that come to
         // here?
         break;
-      case kSegmentSeparator:
+      case WTF::Unicode::kSegmentSeparator:
         // ### implement rule L1
         break;
-      case kWhiteSpaceNeutral:
+      case WTF::Unicode::kWhiteSpaceNeutral:
         break;
-      case kOtherNeutral:
+      case WTF::Unicode::kOtherNeutral:
         break;
       default:
         break;
@@ -1151,14 +1154,15 @@
       if (!reached_end_of_line_) {
         eor_ = end_of_run_at_end_of_line_;
         switch (status_.eor) {
-          case kLeftToRight:
-          case kRightToLeft:
-          case kArabicNumber:
+          case WTF::Unicode::kLeftToRight:
+          case WTF::Unicode::kRightToLeft:
+          case WTF::Unicode::kArabicNumber:
             direction_ = status_.eor;
             break;
-          case kEuropeanNumber:
-            direction_ = status_.last_strong == kLeftToRight ? kLeftToRight
-                                                             : kEuropeanNumber;
+          case WTF::Unicode::kEuropeanNumber:
+            direction_ = status_.last_strong == WTF::Unicode::kLeftToRight
+                             ? WTF::Unicode::kLeftToRight
+                             : WTF::Unicode::kEuropeanNumber;
             break;
           default:
             NOTREACHED();
@@ -1173,7 +1177,7 @@
       reached_end_of_line_ = state_at_end.reached_end_of_line_;
       last_before_et_ = state_at_end.last_before_et_;
       empty_run_ = state_at_end.empty_run_;
-      direction_ = kOtherNeutral;
+      direction_ = WTF::Unicode::kOtherNeutral;
       break;
     }
 
@@ -1197,7 +1201,7 @@
         reached_end_of_line_ = state_at_end.reached_end_of_line_;
         last_before_et_ = state_at_end.last_before_et_;
         empty_run_ = state_at_end.empty_run_;
-        direction_ = kOtherNeutral;
+        direction_ = WTF::Unicode::kOtherNeutral;
         break;
       }
     }
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/try_flag.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/try_flag.py
index 93848c0..2f5fdd4 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/try_flag.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/try_flag.py
@@ -91,7 +91,7 @@
             self._host.print_('-- %s: %s/results.html' % (
                 BUILDERS[build.builder_name].version,
                 buildbot.results_url(build.builder_name, build.build_number)))
-            results = buildbot.fetch_results(build, full=True)
+            results = buildbot.fetch_results(build, True)
             results.for_each_test(
                 lambda result, b=build: self._process_result(b, result))
 
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium
index caf8190..c488a37 100644
--- a/third_party/libvpx/README.chromium
+++ b/third_party/libvpx/README.chromium
@@ -5,9 +5,9 @@
 License File: source/libvpx/LICENSE
 Security Critical: yes
 
-Date: Tuesday October 03 2017
+Date: Thursday October 12 2017
 Branch: master
-Commit: fe7b869104806752a26a262dc60923639d9a384f
+Commit: caa116c9be96508c18d533dedc95b2df4f8e3812
 
 Description:
 Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/libvpx_srcs.gni b/third_party/libvpx/libvpx_srcs.gni
index 9dcb34d..fd7814c 100644
--- a/third_party/libvpx/libvpx_srcs.gni
+++ b/third_party/libvpx/libvpx_srcs.gni
@@ -321,6 +321,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/bitdepth_conversion_avx2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/bitdepth_conversion_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/convolve.h",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/convolve_ssse3.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/fwd_dct32x32_impl_avx2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/fwd_dct32x32_impl_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/fwd_txfm_impl_sse2.h",
@@ -329,6 +330,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_inv_txfm_sse4.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/inv_txfm_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/inv_txfm_ssse3.h",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/mem_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/transpose_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/txfm_common_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/vpx_asm_stubs.c",
@@ -783,6 +785,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/bitdepth_conversion_avx2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/bitdepth_conversion_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/convolve.h",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/convolve_ssse3.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/fwd_dct32x32_impl_avx2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/fwd_dct32x32_impl_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/fwd_txfm_impl_sse2.h",
@@ -791,6 +794,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_inv_txfm_sse4.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/inv_txfm_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/inv_txfm_ssse3.h",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/mem_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/transpose_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/txfm_common_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/vpx_asm_stubs.c",
diff --git a/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
index 90edc5c..0835030 100644
--- a/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
@@ -135,6 +135,17 @@
                              int y_step_q4,
                              int w,
                              int h);
+void vpx_convolve8_avg_avx2(const uint8_t* src,
+                            ptrdiff_t src_stride,
+                            uint8_t* dst,
+                            ptrdiff_t dst_stride,
+                            const InterpKernel* filter,
+                            int x0_q4,
+                            int x_step_q4,
+                            int y0_q4,
+                            int y_step_q4,
+                            int w,
+                            int h);
 RTCD_EXTERN void (*vpx_convolve8_avg)(const uint8_t* src,
                                       ptrdiff_t src_stride,
                                       uint8_t* dst,
@@ -180,6 +191,17 @@
                                    int y_step_q4,
                                    int w,
                                    int h);
+void vpx_convolve8_avg_horiz_avx2(const uint8_t* src,
+                                  ptrdiff_t src_stride,
+                                  uint8_t* dst,
+                                  ptrdiff_t dst_stride,
+                                  const InterpKernel* filter,
+                                  int x0_q4,
+                                  int x_step_q4,
+                                  int y0_q4,
+                                  int y_step_q4,
+                                  int w,
+                                  int h);
 RTCD_EXTERN void (*vpx_convolve8_avg_horiz)(const uint8_t* src,
                                             ptrdiff_t src_stride,
                                             uint8_t* dst,
@@ -225,6 +247,17 @@
                                   int y_step_q4,
                                   int w,
                                   int h);
+void vpx_convolve8_avg_vert_avx2(const uint8_t* src,
+                                 ptrdiff_t src_stride,
+                                 uint8_t* dst,
+                                 ptrdiff_t dst_stride,
+                                 const InterpKernel* filter,
+                                 int x0_q4,
+                                 int x_step_q4,
+                                 int y0_q4,
+                                 int y_step_q4,
+                                 int w,
+                                 int h);
 RTCD_EXTERN void (*vpx_convolve8_avg_vert)(const uint8_t* src,
                                            ptrdiff_t src_stride,
                                            uint8_t* dst,
@@ -8794,16 +8827,22 @@
     vpx_convolve8_avg = vpx_convolve8_avg_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg = vpx_convolve8_avg_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg = vpx_convolve8_avg_avx2;
   vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_c;
   if (flags & HAS_SSE2)
     vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_avx2;
   vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_c;
   if (flags & HAS_SSE2)
     vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_avx2;
   vpx_convolve8_horiz = vpx_convolve8_horiz_c;
   if (flags & HAS_SSE2)
     vpx_convolve8_horiz = vpx_convolve8_horiz_sse2;
diff --git a/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
index 659206c5..6e8baa8 100644
--- a/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
@@ -130,6 +130,17 @@
                              int y_step_q4,
                              int w,
                              int h);
+void vpx_convolve8_avg_avx2(const uint8_t* src,
+                            ptrdiff_t src_stride,
+                            uint8_t* dst,
+                            ptrdiff_t dst_stride,
+                            const InterpKernel* filter,
+                            int x0_q4,
+                            int x_step_q4,
+                            int y0_q4,
+                            int y_step_q4,
+                            int w,
+                            int h);
 RTCD_EXTERN void (*vpx_convolve8_avg)(const uint8_t* src,
                                       ptrdiff_t src_stride,
                                       uint8_t* dst,
@@ -175,6 +186,17 @@
                                    int y_step_q4,
                                    int w,
                                    int h);
+void vpx_convolve8_avg_horiz_avx2(const uint8_t* src,
+                                  ptrdiff_t src_stride,
+                                  uint8_t* dst,
+                                  ptrdiff_t dst_stride,
+                                  const InterpKernel* filter,
+                                  int x0_q4,
+                                  int x_step_q4,
+                                  int y0_q4,
+                                  int y_step_q4,
+                                  int w,
+                                  int h);
 RTCD_EXTERN void (*vpx_convolve8_avg_horiz)(const uint8_t* src,
                                             ptrdiff_t src_stride,
                                             uint8_t* dst,
@@ -220,6 +242,17 @@
                                   int y_step_q4,
                                   int w,
                                   int h);
+void vpx_convolve8_avg_vert_avx2(const uint8_t* src,
+                                 ptrdiff_t src_stride,
+                                 uint8_t* dst,
+                                 ptrdiff_t dst_stride,
+                                 const InterpKernel* filter,
+                                 int x0_q4,
+                                 int x_step_q4,
+                                 int y0_q4,
+                                 int y_step_q4,
+                                 int w,
+                                 int h);
 RTCD_EXTERN void (*vpx_convolve8_avg_vert)(const uint8_t* src,
                                            ptrdiff_t src_stride,
                                            uint8_t* dst,
@@ -7507,12 +7540,18 @@
   vpx_convolve8_avg = vpx_convolve8_avg_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg = vpx_convolve8_avg_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg = vpx_convolve8_avg_avx2;
   vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_avx2;
   vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_avx2;
   vpx_convolve8_horiz = vpx_convolve8_horiz_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_horiz = vpx_convolve8_horiz_ssse3;
diff --git a/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
index 90edc5c..0835030 100644
--- a/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
@@ -135,6 +135,17 @@
                              int y_step_q4,
                              int w,
                              int h);
+void vpx_convolve8_avg_avx2(const uint8_t* src,
+                            ptrdiff_t src_stride,
+                            uint8_t* dst,
+                            ptrdiff_t dst_stride,
+                            const InterpKernel* filter,
+                            int x0_q4,
+                            int x_step_q4,
+                            int y0_q4,
+                            int y_step_q4,
+                            int w,
+                            int h);
 RTCD_EXTERN void (*vpx_convolve8_avg)(const uint8_t* src,
                                       ptrdiff_t src_stride,
                                       uint8_t* dst,
@@ -180,6 +191,17 @@
                                    int y_step_q4,
                                    int w,
                                    int h);
+void vpx_convolve8_avg_horiz_avx2(const uint8_t* src,
+                                  ptrdiff_t src_stride,
+                                  uint8_t* dst,
+                                  ptrdiff_t dst_stride,
+                                  const InterpKernel* filter,
+                                  int x0_q4,
+                                  int x_step_q4,
+                                  int y0_q4,
+                                  int y_step_q4,
+                                  int w,
+                                  int h);
 RTCD_EXTERN void (*vpx_convolve8_avg_horiz)(const uint8_t* src,
                                             ptrdiff_t src_stride,
                                             uint8_t* dst,
@@ -225,6 +247,17 @@
                                   int y_step_q4,
                                   int w,
                                   int h);
+void vpx_convolve8_avg_vert_avx2(const uint8_t* src,
+                                 ptrdiff_t src_stride,
+                                 uint8_t* dst,
+                                 ptrdiff_t dst_stride,
+                                 const InterpKernel* filter,
+                                 int x0_q4,
+                                 int x_step_q4,
+                                 int y0_q4,
+                                 int y_step_q4,
+                                 int w,
+                                 int h);
 RTCD_EXTERN void (*vpx_convolve8_avg_vert)(const uint8_t* src,
                                            ptrdiff_t src_stride,
                                            uint8_t* dst,
@@ -8794,16 +8827,22 @@
     vpx_convolve8_avg = vpx_convolve8_avg_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg = vpx_convolve8_avg_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg = vpx_convolve8_avg_avx2;
   vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_c;
   if (flags & HAS_SSE2)
     vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_avx2;
   vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_c;
   if (flags & HAS_SSE2)
     vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_avx2;
   vpx_convolve8_horiz = vpx_convolve8_horiz_c;
   if (flags & HAS_SSE2)
     vpx_convolve8_horiz = vpx_convolve8_horiz_sse2;
diff --git a/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
index 659206c5..6e8baa8 100644
--- a/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
@@ -130,6 +130,17 @@
                              int y_step_q4,
                              int w,
                              int h);
+void vpx_convolve8_avg_avx2(const uint8_t* src,
+                            ptrdiff_t src_stride,
+                            uint8_t* dst,
+                            ptrdiff_t dst_stride,
+                            const InterpKernel* filter,
+                            int x0_q4,
+                            int x_step_q4,
+                            int y0_q4,
+                            int y_step_q4,
+                            int w,
+                            int h);
 RTCD_EXTERN void (*vpx_convolve8_avg)(const uint8_t* src,
                                       ptrdiff_t src_stride,
                                       uint8_t* dst,
@@ -175,6 +186,17 @@
                                    int y_step_q4,
                                    int w,
                                    int h);
+void vpx_convolve8_avg_horiz_avx2(const uint8_t* src,
+                                  ptrdiff_t src_stride,
+                                  uint8_t* dst,
+                                  ptrdiff_t dst_stride,
+                                  const InterpKernel* filter,
+                                  int x0_q4,
+                                  int x_step_q4,
+                                  int y0_q4,
+                                  int y_step_q4,
+                                  int w,
+                                  int h);
 RTCD_EXTERN void (*vpx_convolve8_avg_horiz)(const uint8_t* src,
                                             ptrdiff_t src_stride,
                                             uint8_t* dst,
@@ -220,6 +242,17 @@
                                   int y_step_q4,
                                   int w,
                                   int h);
+void vpx_convolve8_avg_vert_avx2(const uint8_t* src,
+                                 ptrdiff_t src_stride,
+                                 uint8_t* dst,
+                                 ptrdiff_t dst_stride,
+                                 const InterpKernel* filter,
+                                 int x0_q4,
+                                 int x_step_q4,
+                                 int y0_q4,
+                                 int y_step_q4,
+                                 int w,
+                                 int h);
 RTCD_EXTERN void (*vpx_convolve8_avg_vert)(const uint8_t* src,
                                            ptrdiff_t src_stride,
                                            uint8_t* dst,
@@ -7507,12 +7540,18 @@
   vpx_convolve8_avg = vpx_convolve8_avg_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg = vpx_convolve8_avg_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg = vpx_convolve8_avg_avx2;
   vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_avx2;
   vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_avx2;
   vpx_convolve8_horiz = vpx_convolve8_horiz_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_horiz = vpx_convolve8_horiz_ssse3;
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h
index 2f71e77..e2f8bf70 100644
--- a/third_party/libvpx/source/config/vpx_version.h
+++ b/third_party/libvpx/source/config/vpx_version.h
@@ -1,7 +1,7 @@
 #define VERSION_MAJOR  1
 #define VERSION_MINOR  6
 #define VERSION_PATCH  1
-#define VERSION_EXTRA  "1264-gfe7b86910"
+#define VERSION_EXTRA  "1306-gcaa116c9b"
 #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.6.1-1264-gfe7b86910"
-#define VERSION_STRING      " v1.6.1-1264-gfe7b86910"
+#define VERSION_STRING_NOSP "v1.6.1-1306-gcaa116c9b"
+#define VERSION_STRING      " v1.6.1-1306-gcaa116c9b"
diff --git a/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
index 90edc5c..0835030 100644
--- a/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
@@ -135,6 +135,17 @@
                              int y_step_q4,
                              int w,
                              int h);
+void vpx_convolve8_avg_avx2(const uint8_t* src,
+                            ptrdiff_t src_stride,
+                            uint8_t* dst,
+                            ptrdiff_t dst_stride,
+                            const InterpKernel* filter,
+                            int x0_q4,
+                            int x_step_q4,
+                            int y0_q4,
+                            int y_step_q4,
+                            int w,
+                            int h);
 RTCD_EXTERN void (*vpx_convolve8_avg)(const uint8_t* src,
                                       ptrdiff_t src_stride,
                                       uint8_t* dst,
@@ -180,6 +191,17 @@
                                    int y_step_q4,
                                    int w,
                                    int h);
+void vpx_convolve8_avg_horiz_avx2(const uint8_t* src,
+                                  ptrdiff_t src_stride,
+                                  uint8_t* dst,
+                                  ptrdiff_t dst_stride,
+                                  const InterpKernel* filter,
+                                  int x0_q4,
+                                  int x_step_q4,
+                                  int y0_q4,
+                                  int y_step_q4,
+                                  int w,
+                                  int h);
 RTCD_EXTERN void (*vpx_convolve8_avg_horiz)(const uint8_t* src,
                                             ptrdiff_t src_stride,
                                             uint8_t* dst,
@@ -225,6 +247,17 @@
                                   int y_step_q4,
                                   int w,
                                   int h);
+void vpx_convolve8_avg_vert_avx2(const uint8_t* src,
+                                 ptrdiff_t src_stride,
+                                 uint8_t* dst,
+                                 ptrdiff_t dst_stride,
+                                 const InterpKernel* filter,
+                                 int x0_q4,
+                                 int x_step_q4,
+                                 int y0_q4,
+                                 int y_step_q4,
+                                 int w,
+                                 int h);
 RTCD_EXTERN void (*vpx_convolve8_avg_vert)(const uint8_t* src,
                                            ptrdiff_t src_stride,
                                            uint8_t* dst,
@@ -8794,16 +8827,22 @@
     vpx_convolve8_avg = vpx_convolve8_avg_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg = vpx_convolve8_avg_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg = vpx_convolve8_avg_avx2;
   vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_c;
   if (flags & HAS_SSE2)
     vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_avx2;
   vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_c;
   if (flags & HAS_SSE2)
     vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_avx2;
   vpx_convolve8_horiz = vpx_convolve8_horiz_c;
   if (flags & HAS_SSE2)
     vpx_convolve8_horiz = vpx_convolve8_horiz_sse2;
diff --git a/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
index 659206c5..6e8baa8 100644
--- a/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
@@ -130,6 +130,17 @@
                              int y_step_q4,
                              int w,
                              int h);
+void vpx_convolve8_avg_avx2(const uint8_t* src,
+                            ptrdiff_t src_stride,
+                            uint8_t* dst,
+                            ptrdiff_t dst_stride,
+                            const InterpKernel* filter,
+                            int x0_q4,
+                            int x_step_q4,
+                            int y0_q4,
+                            int y_step_q4,
+                            int w,
+                            int h);
 RTCD_EXTERN void (*vpx_convolve8_avg)(const uint8_t* src,
                                       ptrdiff_t src_stride,
                                       uint8_t* dst,
@@ -175,6 +186,17 @@
                                    int y_step_q4,
                                    int w,
                                    int h);
+void vpx_convolve8_avg_horiz_avx2(const uint8_t* src,
+                                  ptrdiff_t src_stride,
+                                  uint8_t* dst,
+                                  ptrdiff_t dst_stride,
+                                  const InterpKernel* filter,
+                                  int x0_q4,
+                                  int x_step_q4,
+                                  int y0_q4,
+                                  int y_step_q4,
+                                  int w,
+                                  int h);
 RTCD_EXTERN void (*vpx_convolve8_avg_horiz)(const uint8_t* src,
                                             ptrdiff_t src_stride,
                                             uint8_t* dst,
@@ -220,6 +242,17 @@
                                   int y_step_q4,
                                   int w,
                                   int h);
+void vpx_convolve8_avg_vert_avx2(const uint8_t* src,
+                                 ptrdiff_t src_stride,
+                                 uint8_t* dst,
+                                 ptrdiff_t dst_stride,
+                                 const InterpKernel* filter,
+                                 int x0_q4,
+                                 int x_step_q4,
+                                 int y0_q4,
+                                 int y_step_q4,
+                                 int w,
+                                 int h);
 RTCD_EXTERN void (*vpx_convolve8_avg_vert)(const uint8_t* src,
                                            ptrdiff_t src_stride,
                                            uint8_t* dst,
@@ -7507,12 +7540,18 @@
   vpx_convolve8_avg = vpx_convolve8_avg_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg = vpx_convolve8_avg_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg = vpx_convolve8_avg_avx2;
   vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg_horiz = vpx_convolve8_avg_horiz_avx2;
   vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_ssse3;
+  if (flags & HAS_AVX2)
+    vpx_convolve8_avg_vert = vpx_convolve8_avg_vert_avx2;
   vpx_convolve8_horiz = vpx_convolve8_horiz_sse2;
   if (flags & HAS_SSSE3)
     vpx_convolve8_horiz = vpx_convolve8_horiz_ssse3;
diff --git a/third_party/win_build_output/remc.bat b/third_party/win_build_output/remc.bat
new file mode 100755
index 0000000..3c057d2
--- /dev/null
+++ b/third_party/win_build_output/remc.bat
@@ -0,0 +1,8 @@
+@REM Copyright 2017 The Chromium Authors. All rights reserved.
+@REM Use of this source code is governed by a BSD-style license that can be
+@REM found in the LICENSE file.
+
+ninja -C out\gn ^
+    gen/base/trace_event/etw_manifest/chrome_events_win.h ^
+    gen/chrome/common/win/eventlog_messages.h ^
+    gen/remoting/host/win/remoting_host_messages.h
diff --git a/third_party/win_build_output/remidl.bat b/third_party/win_build_output/remidl.bat
new file mode 100755
index 0000000..1e2c39f5
--- /dev/null
+++ b/third_party/win_build_output/remidl.bat
@@ -0,0 +1,12 @@
+@REM Copyright 2017 The Chromium Authors. All rights reserved.
+@REM Use of this source code is governed by a BSD-style license that can be
+@REM found in the LICENSE file.
+
+@REM midl.exe output is arch-specific, remember to run this for both target_cpu.
+ninja -C out\gn ^
+    gen/google_update/google_update_idl.h ^
+    gen/remoting/host/win/chromoting_lib.h ^
+    gen/third_party/iaccessible2/ia2_api_all.h ^
+    gen/third_party/isimpledom/ISimpleDOMDocument.h ^
+    gen/third_party/isimpledom/ISimpleDOMNode.h ^
+    gen/third_party/isimpledom/ISimpleDOMText.h
diff --git a/third_party/zlib/google/zip.cc b/third_party/zlib/google/zip.cc
index f0183d3f..abdfcb1 100644
--- a/third_party/zlib/google/zip.cc
+++ b/third_party/zlib/google/zip.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/zlib/google/zip.h"
 
+#include <list>
 #include <string>
 #include <vector>
 
@@ -25,10 +26,13 @@
 #include "third_party/zlib/contrib/minizip/zip.h"
 #endif
 
+namespace zip {
 namespace {
 
-bool AddFileToZip(zipFile zip_file, const base::FilePath& src_dir) {
-  base::File file(src_dir, base::File::FLAG_OPEN | base::File::FLAG_READ);
+bool AddFileToZip(zipFile zip_file,
+                  const base::FilePath& src_dir,
+                  FileAccessor* file_accessor) {
+  base::File file = file_accessor->OpenFileForReading(src_dir);
   if (!file.IsValid()) {
     DLOG(ERROR) << "Could not open file for path " << src_dir.value();
     return false;
@@ -50,8 +54,10 @@
   return true;
 }
 
-bool AddEntryToZip(zipFile zip_file, const base::FilePath& path,
-                   const base::FilePath& root_path) {
+bool AddEntryToZip(zipFile zip_file,
+                   const base::FilePath& path,
+                   const base::FilePath& root_path,
+                   FileAccessor* file_accessor) {
   base::FilePath relative_path;
   bool result = root_path.AppendRelativePath(path, &relative_path);
   DCHECK(result);
@@ -60,17 +66,17 @@
   base::ReplaceSubstringsAfterOffset(&str_path, 0u, "\\", "/");
 #endif
 
-  bool is_directory = base::DirectoryExists(path);
+  bool is_directory = file_accessor->DirectoryExists(path);
   if (is_directory)
     str_path += "/";
 
-  zip_fileinfo file_info = zip::internal::GetFileInfoForZipping(path);
-  if (!zip::internal::ZipOpenNewFileInZip(zip_file, str_path, &file_info))
+  if (!zip::internal::ZipOpenNewFileInZip(
+          zip_file, str_path, file_accessor->GetLastModifiedTime(path)))
     return false;
 
   bool success = true;
   if (!is_directory) {
-    success = AddFileToZip(zip_file, path);
+    success = AddFileToZip(zip_file, path, file_accessor);
   }
 
   if (ZIP_OK != zipCloseFileInZip(zip_file)) {
@@ -81,17 +87,151 @@
   return success;
 }
 
+bool IsHiddenFile(const base::FilePath& file_path) {
+  return file_path.BaseName().value()[0] == '.';
+}
+
 bool ExcludeNoFilesFilter(const base::FilePath& file_path) {
   return true;
 }
 
 bool ExcludeHiddenFilesFilter(const base::FilePath& file_path) {
-  return file_path.BaseName().value()[0] != '.';
+  return !IsHiddenFile(file_path);
 }
 
+class DirectFileAccessor : public FileAccessor {
+ public:
+  ~DirectFileAccessor() override = default;
+
+  base::File OpenFileForReading(const base::FilePath& file) override {
+    return base::File(file, base::File::FLAG_OPEN | base::File::FLAG_READ);
+  }
+
+  bool DirectoryExists(const base::FilePath& file) override {
+    return base::DirectoryExists(file);
+  }
+
+  std::vector<DirectoryContentEntry> ListDirectoryContent(
+      const base::FilePath& dir) {
+    std::vector<DirectoryContentEntry> files;
+    base::FileEnumerator file_enumerator(
+        dir, false /* recursive */,
+        base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
+    for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
+         path = file_enumerator.Next()) {
+      files.push_back(DirectoryContentEntry(path, base::DirectoryExists(path)));
+    }
+    return files;
+  }
+
+  base::Time GetLastModifiedTime(const base::FilePath& path) override {
+    base::File::Info file_info;
+    if (!base::GetFileInfo(path, &file_info)) {
+      LOG(ERROR) << "Failed to retrieve file modification time for "
+                 << path.value();
+    }
+    return file_info.last_modified;
+  }
+};
+
 }  // namespace
 
-namespace zip {
+ZipParams::ZipParams(const base::FilePath& src_dir,
+                     const base::FilePath& dest_file)
+    : src_dir_(src_dir),
+      dest_file_(dest_file),
+      file_accessor_(new DirectFileAccessor()) {}
+
+#if defined(OS_POSIX)
+// Does not take ownership of |fd|.
+ZipParams::ZipParams(const base::FilePath& src_dir, int dest_fd)
+    : src_dir_(src_dir),
+      dest_fd_(dest_fd),
+      file_accessor_(new DirectFileAccessor()) {}
+#endif
+
+bool Zip(const ZipParams& params) {
+  DCHECK(params.file_accessor()->DirectoryExists(params.src_dir()));
+
+  zipFile zip_file = nullptr;
+#if defined(OS_POSIX)
+  int dest_fd = params.dest_fd();
+  if (dest_fd != base::kInvalidPlatformFile) {
+    DCHECK(params.dest_file().empty());
+    zip_file = internal::OpenFdForZipping(dest_fd, APPEND_STATUS_CREATE);
+    if (!zip_file) {
+      DLOG(ERROR) << "Couldn't create ZIP file for FD " << dest_fd;
+      return false;
+    }
+  }
+#endif
+  if (!zip_file) {
+    const base::FilePath& dest_file = params.dest_file();
+    DCHECK(!dest_file.empty());
+    zip_file = internal::OpenForZipping(dest_file.AsUTF8Unsafe(),
+                                        APPEND_STATUS_CREATE);
+    if (!zip_file) {
+      DLOG(WARNING) << "Couldn't create ZIP file at path " << dest_file;
+      return false;
+    }
+  }
+
+  // Using a pointer to avoid copies of a potentially large array.
+  const std::vector<base::FilePath>* files_to_add = &params.files_to_zip();
+  std::vector<base::FilePath> all_files;
+  if (files_to_add->empty()) {
+    // Include all files from the src_dir (modulo the src_dir itself and
+    // filtered and hidden files).
+
+    files_to_add = &all_files;
+    // Using a list so we can call push_back while iterating.
+    std::list<FileAccessor::DirectoryContentEntry> entries;
+    entries.push_back(FileAccessor::DirectoryContentEntry(
+        params.src_dir(), true /* is directory*/));
+    const FilterCallback& filter_callback = params.filter_callback();
+    for (auto iter = entries.begin(); iter != entries.end(); ++iter) {
+      const base::FilePath& entry_path = iter->path;
+      if (iter != entries.begin() &&  // Don't filter the root dir.
+          ((!params.include_hidden_files() && IsHiddenFile(entry_path)) ||
+           (filter_callback && !filter_callback.Run(entry_path)))) {
+        continue;
+      }
+
+      if (iter != entries.begin()) {  // Exclude the root dir from the ZIP file.
+        // Make the path relative for AddEntryToZip.
+        base::FilePath relative_path;
+        bool success =
+            params.src_dir().AppendRelativePath(entry_path, &relative_path);
+        DCHECK(success);
+        all_files.push_back(relative_path);
+      }
+
+      if (iter->is_directory) {
+        std::vector<FileAccessor::DirectoryContentEntry> subentries =
+            params.file_accessor()->ListDirectoryContent(entry_path);
+        entries.insert(entries.end(), subentries.begin(), subentries.end());
+      }
+    }
+  }
+
+  bool success = true;
+  for (auto iter = files_to_add->begin(); iter != files_to_add->end(); ++iter) {
+    const base::FilePath& path = params.src_dir().Append(*iter);
+    if (!AddEntryToZip(zip_file, path, params.src_dir(),
+                       params.file_accessor())) {
+      // TODO(hshi): clean up the partial zip file when error occurs.
+      success = false;
+      break;
+    }
+  }
+
+  if (ZIP_OK != zipClose(zip_file, NULL)) {
+    DLOG(ERROR) << "Error closing zip file " << params.dest_file().value();
+    return false;
+  }
+
+  return success;
+}
 
 bool Unzip(const base::FilePath& src_file, const base::FilePath& dest_dir) {
   return UnzipWithFilterCallback(src_file, dest_dir,
@@ -140,36 +280,9 @@
                            const base::FilePath& dest_file,
                            const FilterCallback& filter_cb) {
   DCHECK(base::DirectoryExists(src_dir));
-
-  zipFile zip_file = internal::OpenForZipping(dest_file.AsUTF8Unsafe(),
-                                              APPEND_STATUS_CREATE);
-
-  if (!zip_file) {
-    DLOG(WARNING) << "couldn't create file " << dest_file.value();
-    return false;
-  }
-
-  bool success = true;
-  base::FileEnumerator file_enumerator(src_dir, true /* recursive */,
-      base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
-  for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
-       path = file_enumerator.Next()) {
-    if (!filter_cb.Run(path)) {
-      continue;
-    }
-
-    if (!AddEntryToZip(zip_file, path, src_dir)) {
-      success = false;
-      break;
-    }
-  }
-
-  if (ZIP_OK != zipClose(zip_file, NULL)) {
-    DLOG(ERROR) << "Error closing zip file " << dest_file.value();
-    return false;
-  }
-
-  return success;
+  ZipParams params(src_dir, dest_file);
+  params.set_filter_callback(filter_cb);
+  return Zip(params);
 }
 
 bool Zip(const base::FilePath& src_dir, const base::FilePath& dest_file,
@@ -188,31 +301,9 @@
               const std::vector<base::FilePath>& src_relative_paths,
               int dest_fd) {
   DCHECK(base::DirectoryExists(src_dir));
-  zipFile zip_file = internal::OpenFdForZipping(dest_fd, APPEND_STATUS_CREATE);
-
-  if (!zip_file) {
-    DLOG(ERROR) << "couldn't create file for fd " << dest_fd;
-    return false;
-  }
-
-  bool success = true;
-  for (std::vector<base::FilePath>::const_iterator iter =
-           src_relative_paths.begin();
-      iter != src_relative_paths.end(); ++iter) {
-    const base::FilePath& path = src_dir.Append(*iter);
-    if (!AddEntryToZip(zip_file, path, src_dir)) {
-      // TODO(hshi): clean up the partial zip file when error occurs.
-      success = false;
-      break;
-    }
-  }
-
-  if (ZIP_OK != zipClose(zip_file, NULL)) {
-    DLOG(ERROR) << "Error closing zip file for fd " << dest_fd;
-    success = false;
-  }
-
-  return success;
+  ZipParams params(src_dir, dest_fd);
+  params.set_files_to_zip(src_relative_paths);
+  return Zip(params);
 }
 #endif  // defined(OS_POSIX)
 
diff --git a/third_party/zlib/google/zip.h b/third_party/zlib/google/zip.h
index 68bed0b..1884f4d 100644
--- a/third_party/zlib/google/zip.h
+++ b/third_party/zlib/google/zip.h
@@ -9,10 +9,110 @@
 
 #include "base/callback.h"
 #include "base/files/file_path.h"
+#include "base/files/platform_file.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 
+namespace base {
+class File;
+}
+
 namespace zip {
 
+// Abstraction for file access operation required by Zip().
+// Can be passed to the ZipParams for providing custom access to the files,
+// for example over IPC.
+// If none is provided, the files are accessed directly.
+class FileAccessor {
+ public:
+  virtual ~FileAccessor() = default;
+
+  struct DirectoryContentEntry {
+    DirectoryContentEntry(const base::FilePath& path, bool is_directory)
+        : path(path), is_directory(is_directory) {}
+    base::FilePath path;
+    bool is_directory = false;
+  };
+
+  virtual base::File OpenFileForReading(const base::FilePath& path) = 0;
+  virtual bool DirectoryExists(const base::FilePath& path) = 0;
+  virtual std::vector<DirectoryContentEntry> ListDirectoryContent(
+      const base::FilePath& dir_path) = 0;
+  virtual base::Time GetLastModifiedTime(const base::FilePath& path) = 0;
+};
+
+class ZipParams {
+ public:
+  ZipParams(const base::FilePath& src_dir, const base::FilePath& dest_file);
+#if defined(OS_POSIX)
+  // Does not take ownership of |dest_fd|.
+  ZipParams(const base::FilePath& src_dir, int dest_fd);
+
+  int dest_fd() const { return dest_fd_; }
+#endif
+
+  const base::FilePath& src_dir() const { return src_dir_; }
+
+  const base::FilePath& dest_file() const { return dest_file_; }
+
+  // Restricts the files actually zipped to the paths listed in
+  // |src_relative_paths|. They must be relative to the |src_dir| passed in the
+  // constructor and will be used as the file names in the created zip file. All
+  // source paths must be under |src_dir| in the file system hierarchy.
+  void set_files_to_zip(const std::vector<base::FilePath>& src_relative_paths) {
+    src_files_ = src_relative_paths;
+  }
+  const std::vector<base::FilePath>& files_to_zip() const { return src_files_; }
+
+  using FilterCallback = base::Callback<bool(const base::FilePath&)>;
+  void set_filter_callback(FilterCallback filter_callback) {
+    filter_callback_ = filter_callback;
+  }
+  const FilterCallback& filter_callback() const { return filter_callback_; }
+
+  void set_include_hidden_files(bool include_hidden_files) {
+    include_hidden_files_ = include_hidden_files;
+  }
+  bool include_hidden_files() const { return include_hidden_files_; }
+
+  // Sets a custom file accessor for file operations. Default is to directly
+  // access the files (with fopen and the rest).
+  // Useful in cases where running in a sandbox process and file access has to
+  // go through IPC, for example.
+  void set_file_accessor(std::unique_ptr<FileAccessor> file_accessor) {
+    file_accessor_ = std::move(file_accessor);
+  }
+  FileAccessor* file_accessor() const { return file_accessor_.get(); }
+
+ private:
+  base::FilePath src_dir_;
+
+  base::FilePath dest_file_;
+#if defined(OS_POSIX)
+  int dest_fd_ = base::kInvalidPlatformFile;
+#endif
+
+  // The relative paths to the files that should be included in the zip file. If
+  // this is empty, all files in |src_dir_| are included.
+  std::vector<base::FilePath> src_files_;
+
+  // Filter used to exclude files from the ZIP file. Only effective when
+  // |src_files_| is empty.
+  FilterCallback filter_callback_;
+
+  // Whether hidden files should be included in the ZIP file. Only effective
+  // when |src_files_| is empty.
+  bool include_hidden_files_ = true;
+
+  // Abstraction around file system access used to read files. An implementation
+  // that accesses files directly is provided by default.
+  std::unique_ptr<FileAccessor> file_accessor_;
+};
+
+// Zip files specified into a ZIP archives. The source files and ZIP destination
+// files (as well as other settings) are specified in |params|.
+bool Zip(const ZipParams& params);
+
 // Zip the contents of src_dir into dest_file. src_path must be a directory.
 // An entry will *not* be created in the zip for the root folder -- children
 // of src_dir will be at the root level of the created zip. For each file in
diff --git a/third_party/zlib/google/zip_internal.cc b/third_party/zlib/google/zip_internal.cc
index 77f2b17..314740f5 100644
--- a/third_party/zlib/google/zip_internal.cc
+++ b/third_party/zlib/google/zip_internal.cc
@@ -8,11 +8,8 @@
 
 #include <algorithm>
 
-#include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
 
 #if defined(USE_SYSTEM_MINIZIP)
 #include <minizip/ioapi.h>
@@ -346,40 +343,32 @@
 }
 #endif
 
-zip_fileinfo GetFileInfoForZipping(const base::FilePath& path) {
-  base::Time file_time;
-  base::File::Info file_info;
-  if (base::GetFileInfo(path, &file_info))
-    file_time = file_info.last_modified;
-  return TimeToZipFileInfo(file_time);
-}
-
 bool ZipOpenNewFileInZip(zipFile zip_file,
                          const std::string& str_path,
-                         const zip_fileinfo* file_info) {
+                         base::Time last_modified_time) {
   // Section 4.4.4 http://www.pkware.com/documents/casestudies/APPNOTE.TXT
   // Setting the Language encoding flag so the file is told to be in utf-8.
   const uLong LANGUAGE_ENCODING_FLAG = 0x1 << 11;
 
-  if (ZIP_OK != zipOpenNewFileInZip4(
-                    zip_file,  // file
-                    str_path.c_str(),  // filename
-                    file_info,  // zipfi
-                    NULL,  // extrafield_local,
-                    0u,  // size_extrafield_local
-                    NULL,  // extrafield_global
-                    0u,  // size_extrafield_global
-                    NULL,  // comment
-                    Z_DEFLATED,  // method
-                    Z_DEFAULT_COMPRESSION,  // level
-                    0,  // raw
-                    -MAX_WBITS,  // windowBits
-                    DEF_MEM_LEVEL,  // memLevel
-                    Z_DEFAULT_STRATEGY,  // strategy
-                    NULL,  // password
-                    0,  // crcForCrypting
-                    0,  // versionMadeBy
-                    LANGUAGE_ENCODING_FLAG)) {  // flagBase
+  zip_fileinfo file_info = TimeToZipFileInfo(last_modified_time);
+  if (ZIP_OK != zipOpenNewFileInZip4(zip_file,          // file
+                                     str_path.c_str(),  // filename
+                                     &file_info,        // zip_fileinfo
+                                     NULL,              // extrafield_local,
+                                     0u,                // size_extrafield_local
+                                     NULL,              // extrafield_global
+                                     0u,          // size_extrafield_global
+                                     NULL,        // comment
+                                     Z_DEFLATED,  // method
+                                     Z_DEFAULT_COMPRESSION,  // level
+                                     0,                      // raw
+                                     -MAX_WBITS,             // windowBits
+                                     DEF_MEM_LEVEL,          // memLevel
+                                     Z_DEFAULT_STRATEGY,     // strategy
+                                     NULL,                   // password
+                                     0,                      // crcForCrypting
+                                     0,                      // versionMadeBy
+                                     LANGUAGE_ENCODING_FLAG)) {  // flagBase
     DLOG(ERROR) << "Could not open zip file entry " << str_path;
     return false;
   }
diff --git a/third_party/zlib/google/zip_internal.h b/third_party/zlib/google/zip_internal.h
index 0ebf0c94..49fb902a 100644
--- a/third_party/zlib/google/zip_internal.h
+++ b/third_party/zlib/google/zip_internal.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/time/time.h"
 #include "build/build_config.h"
 
 #if defined(OS_WIN)
@@ -59,13 +60,10 @@
 zipFile OpenFdForZipping(int zip_fd, int append_flag);
 #endif
 
-// Returns a zip_fileinfo with the last modification date of |path| set.
-zip_fileinfo GetFileInfoForZipping(const base::FilePath& path);
-
 // Wrapper around zipOpenNewFileInZip4 which passes most common options.
 bool ZipOpenNewFileInZip(zipFile zip_file,
                          const std::string& str_path,
-                         const zip_fileinfo* file_info);
+                         base::Time last_modified_time);
 
 const int kZipMaxPath = 256;
 const int kZipBufSize = 8192;
diff --git a/third_party/zlib/google/zip_unittest.cc b/third_party/zlib/google/zip_unittest.cc
index 2d969d7..b6cf285 100644
--- a/third_party/zlib/google/zip_unittest.cc
+++ b/third_party/zlib/google/zip_unittest.cc
@@ -5,6 +5,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <map>
 #include <set>
 #include <string>
 #include <vector>
@@ -14,6 +15,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -25,6 +27,103 @@
 
 namespace {
 
+bool CreateFile(const std::string& content,
+                base::FilePath* file_path,
+                base::File* file) {
+  if (!base::CreateTemporaryFile(file_path))
+    return false;
+
+  if (base::WriteFile(*file_path, content.data(), content.size()) == -1)
+    return false;
+
+  *file = base::File(
+      *file_path, base::File::Flags::FLAG_OPEN | base::File::Flags::FLAG_READ);
+  return file->IsValid();
+}
+
+// A virtual file system containing:
+// /test
+// /test/foo.txt
+// /test/bar/bar1.txt
+// /test/bar/bar2.txt
+// Used to test providing a custom zip::FileAccessor when unzipping.
+class VirtualFileSystem : public zip::FileAccessor {
+ public:
+  static constexpr char kFooContent[] = "This is foo.";
+  static constexpr char kBar1Content[] = "This is bar.";
+  static constexpr char kBar2Content[] = "This is bar too.";
+
+  VirtualFileSystem() {
+    base::FilePath test_dir(FILE_PATH_LITERAL("/test"));
+    base::FilePath foo_txt_path = test_dir.Append(FILE_PATH_LITERAL("foo.txt"));
+
+    base::FilePath file_path;
+    base::File file;
+    bool success = CreateFile(kFooContent, &file_path, &file);
+    DCHECK(success);
+    files_[foo_txt_path] = std::move(file);
+
+    base::FilePath bar_dir = test_dir.Append(FILE_PATH_LITERAL("bar"));
+    base::FilePath bar1_txt_path =
+        bar_dir.Append(FILE_PATH_LITERAL("bar1.txt"));
+    success = CreateFile(kBar1Content, &file_path, &file);
+    DCHECK(success);
+    files_[bar1_txt_path] = std::move(file);
+
+    base::FilePath bar2_txt_path =
+        bar_dir.Append(FILE_PATH_LITERAL("bar2.txt"));
+    success = CreateFile(kBar2Content, &file_path, &file);
+    DCHECK(success);
+    files_[bar2_txt_path] = std::move(file);
+
+    file_tree_[test_dir] = std::vector<DirectoryContentEntry>{
+        DirectoryContentEntry(foo_txt_path, /*is_dir=*/false),
+        DirectoryContentEntry(bar_dir, /*is_dir=*/true)};
+    file_tree_[bar_dir] = std::vector<DirectoryContentEntry>{
+        DirectoryContentEntry(bar1_txt_path, /*is_dir=*/false),
+        DirectoryContentEntry(bar2_txt_path, /*is_dir=*/false)};
+  }
+  ~VirtualFileSystem() override = default;
+
+ private:
+  base::File OpenFileForReading(const base::FilePath& file) override {
+    auto iter = files_.find(file);
+    if (iter == files_.end()) {
+      NOTREACHED();
+      return base::File();
+    }
+    return std::move(iter->second);
+  }
+
+  bool DirectoryExists(const base::FilePath& file) override {
+    return file_tree_.count(file) == 1 && files_.count(file) == 0;
+  }
+
+  std::vector<DirectoryContentEntry> ListDirectoryContent(
+      const base::FilePath& dir) override {
+    auto iter = file_tree_.find(dir);
+    if (iter == file_tree_.end()) {
+      NOTREACHED();
+      return std::vector<DirectoryContentEntry>();
+    }
+    return iter->second;
+  }
+
+  base::Time GetLastModifiedTime(const base::FilePath& path) override {
+    return base::Time::FromDoubleT(172097977);  // Some random date.
+  }
+
+  std::map<base::FilePath, std::vector<DirectoryContentEntry>> file_tree_;
+  std::map<base::FilePath, base::File> files_;
+
+  DISALLOW_COPY_AND_ASSIGN(VirtualFileSystem);
+};
+
+// static
+constexpr char VirtualFileSystem::kFooContent[];
+constexpr char VirtualFileSystem::kBar1Content[];
+constexpr char VirtualFileSystem::kBar2Content[];
+
 // Make the test a PlatformTest to setup autorelease pools properly on Mac.
 class ZipTest : public PlatformTest {
  protected:
@@ -40,15 +139,15 @@
     test_dir_ = temp_dir_.GetPath();
 
     base::FilePath zip_path(test_dir_);
-    zip_contents_.insert(zip_path.AppendASCII("foo.txt"));
-    zip_path = zip_path.AppendASCII("foo");
+    zip_contents_.insert(zip_path.Append(FILE_PATH_LITERAL("foo.txt")));
+    zip_path = zip_path.Append(FILE_PATH_LITERAL("foo"));
     zip_contents_.insert(zip_path);
-    zip_contents_.insert(zip_path.AppendASCII("bar.txt"));
-    zip_path = zip_path.AppendASCII("bar");
+    zip_contents_.insert(zip_path.Append(FILE_PATH_LITERAL("bar.txt")));
+    zip_path = zip_path.Append(FILE_PATH_LITERAL("bar"));
     zip_contents_.insert(zip_path);
-    zip_contents_.insert(zip_path.AppendASCII("baz.txt"));
-    zip_contents_.insert(zip_path.AppendASCII("quux.txt"));
-    zip_contents_.insert(zip_path.AppendASCII(".hidden"));
+    zip_contents_.insert(zip_path.Append(FILE_PATH_LITERAL("baz.txt")));
+    zip_contents_.insert(zip_path.Append(FILE_PATH_LITERAL("quux.txt")));
+    zip_contents_.insert(zip_path.Append(FILE_PATH_LITERAL(".hidden")));
 
     // Include a subset of files in |zip_file_list_| to test ZipFiles().
     zip_file_list_.push_back(base::FilePath(FILE_PATH_LITERAL("foo.txt")));
@@ -86,18 +185,42 @@
     ASSERT_TRUE(base::PathExists(path)) << "no file " << path.value();
     ASSERT_TRUE(zip::Unzip(path, test_dir_));
 
+    base::FilePath original_dir;
+    ASSERT_TRUE(GetTestDataDirectory(&original_dir));
+    original_dir = original_dir.AppendASCII("test");
+
     base::FileEnumerator files(test_dir_, true,
         base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
-    base::FilePath next_path = files.Next();
+    base::FilePath unzipped_entry_path = files.Next();
     size_t count = 0;
-    while (!next_path.value().empty()) {
-      if (next_path.value().find(FILE_PATH_LITERAL(".svn")) ==
-          base::FilePath::StringType::npos) {
-        EXPECT_EQ(zip_contents_.count(next_path), 1U) <<
-            "Couldn't find " << next_path.value();
-        count++;
+    while (!unzipped_entry_path.value().empty()) {
+      EXPECT_EQ(zip_contents_.count(unzipped_entry_path), 1U)
+          << "Couldn't find " << unzipped_entry_path.value();
+      count++;
+
+      if (base::PathExists(unzipped_entry_path) &&
+          !base::DirectoryExists(unzipped_entry_path)) {
+        // It's a file, check its contents are what we zipped.
+        // TODO(774156): figure out why the commented out EXPECT_TRUE below
+        // fails on the build bots (but not on the try-bots).
+        base::FilePath relative_path;
+        bool append_relative_path_success =
+            test_dir_.AppendRelativePath(unzipped_entry_path, &relative_path);
+        if (!append_relative_path_success) {
+          LOG(ERROR) << "Append relative path failed, params: "
+                     << test_dir_.value() << " and "
+                     << unzipped_entry_path.value();
+        }
+        base::FilePath original_path = original_dir.Append(relative_path);
+        LOG(ERROR) << "Comparing original " << original_path.value()
+                   << " and unzipped file " << unzipped_entry_path.value()
+                   << " result: "
+                   << base::ContentsEqual(original_path, unzipped_entry_path);
+        // EXPECT_TRUE(base::ContentsEqual(original_path, unzipped_entry_path))
+        //    << "Contents differ between original " << original_path.value()
+        //    << " and unzipped file " << unzipped_entry_path.value();
       }
-      next_path = files.Next();
+      unzipped_entry_path = files.Next();
     }
 
     size_t expected_count = 0;
@@ -335,4 +458,29 @@
   }
 }
 
+TEST_F(ZipTest, ZipWithFileAccessor) {
+  base::FilePath zip_file;
+  ASSERT_TRUE(base::CreateTemporaryFile(&zip_file));
+  zip::ZipParams params(base::FilePath(FILE_PATH_LITERAL("/test")), zip_file);
+  params.set_file_accessor(std::make_unique<VirtualFileSystem>());
+  ASSERT_TRUE(zip::Zip(params));
+
+  base::ScopedTempDir scoped_temp_dir;
+  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+  const base::FilePath& temp_dir = scoped_temp_dir.GetPath();
+  ASSERT_TRUE(zip::Unzip(zip_file, temp_dir));
+  base::FilePath bar_dir = temp_dir.Append(FILE_PATH_LITERAL("bar"));
+  EXPECT_TRUE(base::DirectoryExists(bar_dir));
+  std::string file_content;
+  EXPECT_TRUE(base::ReadFileToString(
+      temp_dir.Append(FILE_PATH_LITERAL("foo.txt")), &file_content));
+  EXPECT_EQ(VirtualFileSystem::kFooContent, file_content);
+  EXPECT_TRUE(base::ReadFileToString(
+      bar_dir.Append(FILE_PATH_LITERAL("bar1.txt")), &file_content));
+  EXPECT_EQ(VirtualFileSystem::kBar1Content, file_content);
+  EXPECT_TRUE(base::ReadFileToString(
+      bar_dir.Append(FILE_PATH_LITERAL("bar2.txt")), &file_content));
+  EXPECT_EQ(VirtualFileSystem::kBar2Content, file_content);
+}
+
 }  // namespace
diff --git a/tools/android/eclipse/.classpath b/tools/android/eclipse/.classpath
index 6b91efc..92967f3 100644
--- a/tools/android/eclipse/.classpath
+++ b/tools/android/eclipse/.classpath
@@ -70,7 +70,6 @@
     <classpathentry kind="src" path="components/policy/android/junit/src"/>
     <classpathentry kind="src" path="components/precache/android/java/src"/>
     <classpathentry kind="src" path="components/precache/android/javatests/src"/>
-    <classpathentry kind="src" path="components/safe_json/android/java/src"/>
     <classpathentry kind="src" path="components/signin/core/browser/android/java/src"/>
     <classpathentry kind="src" path="components/signin/core/browser/android/javatests/src"/>
     <classpathentry kind="src" path="components/sync/android/java/src"/>
@@ -113,6 +112,7 @@
     <classpathentry kind="src" path="remoting/android/java/src"/>
     <classpathentry kind="src" path="remoting/android/javatests/src"/>
     <classpathentry kind="src" path="services/service_manager/public/java/src"/>
+    <classpathentry kind="src" path="services/data_decoder/public/cpp/android/src"/>
     <classpathentry kind="src" path="testing/android/appurify_support/java/src"/>
     <classpathentry kind="src" path="testing/android/broker/java/src"/>
     <classpathentry kind="src" path="testing/android/driver/java/src"/>
@@ -273,7 +273,6 @@
     <classpathentry kind="lib" path="out/Debug/lib.java/components/policy/android/policy_java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/components/payments/content/payment_request_java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/components/precache/android/precache_java.jar"/>
-    <classpathentry kind="lib" path="out/Debug/lib.java/components/safe_json/android/safe_json_java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/components/service_tab_launcher/service_tab_launcher_java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/components/signin/core/browser/android/java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/components/variations/android/variations_java.jar"/>
@@ -292,6 +291,7 @@
     <classpathentry kind="lib" path="out/Debug/lib.java/mojo/public/java/system.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/net/android/net_java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/printing/printing_java.jar"/>
+    <classpathentry kind="lib" path="out/Debug/lib.java/services/data_decoder/public/android/safe_json_java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/services/service_manager/public/interfaces/interfaces_java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/sync/android/sync_java.jar"/>
     <classpathentry kind="lib" path="out/Debug/lib.java/sync/test_support_proto_java.jar"/>
diff --git a/tools/gdb/gdb_chrome.py b/tools/gdb/gdb_chrome.py
index ef42a2c..6b956ed9 100644
--- a/tools/gdb/gdb_chrome.py
+++ b/tools/gdb/gdb_chrome.py
@@ -217,15 +217,6 @@
 pp_set.add_printer('base::Time', '^base::Time$', TimePrinter)
 
 
-class ManualConstructorPrinter(object):
-    def __init__(self, val):
-        self.val = val
-
-    def to_string(self):
-        return self.val['space_'].cast(self.val.type.template_argument(0))
-pp_set.add_printer('base::ManualConstructor', '^base::ManualConstructor<.*>$', ManualConstructorPrinter)
-
-
 class FlatTreePrinter(object):
     def __init__(self, val):
         self.val = val
diff --git a/tools/gn/value.h b/tools/gn/value.h
index 3103509b..13beb6fd 100644
--- a/tools/gn/value.h
+++ b/tools/gn/value.h
@@ -120,8 +120,8 @@
  private:
   // This are a lot of objects associated with every Value that need
   // initialization and tear down every time. It might be more efficient to
-  // create a union of ManualConstructor objects (see small_map) and only
-  // use the one we care about.
+  // create a union of objects (see small_map) and only use the one we care
+  // about.
   Type type_;
   std::string string_value_;
   bool boolean_value_;
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 1e460c6c..32408cf 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -605,13 +605,7 @@
       'linux_chromium_rel_ng': 'gpu_tests_release_trybot',
       'linux_chromium_tsan_rel_ng': 'tsan_disable_nacl_release_trybot',
       'linux_chromium_ubsan_rel_ng': 'ubsan_vptr_release_trybot',
-
-      # These are 'release_bot' rather than 'release_trybot' because
-      # 'release_trybot' includes 'dcheck_always_on', which might cause
-      # some layout test results to be different than for normal release
-      # builds (and we only store baselines for release builds).
-      'linux_layout_tests_layout_ng': 'release_bot',
-
+      'linux_layout_tests_layout_ng': 'release_trybot',
       'linux_mojo': 'release_trybot',
       'linux_mojo_chromeos': 'chromeos_with_codecs_release_trybot',
       'linux_nacl_sdk_build': 'release_bot',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index d4c4d919..095e7d09 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -4410,6 +4410,20 @@
   <int value="4" label="Browser Startup"/>
 </enum>
 
+<enum name="ChromeHomePromoResult">
+  <int value="0" label="Enabled Chome Home"/>
+  <int value="1" label="Disabled Chome Home"/>
+  <int value="2" label="Chrome Home remained enabled"/>
+  <int value="3" label="Chrome Home remained disabled"/>
+  <int value="4" label="No action"/>
+</enum>
+
+<enum name="ChromeHomePromoShowReason">
+  <int value="0" label="NTP"/>
+  <int value="1" label="Menu"/>
+  <int value="2" label="Startup"/>
+</enum>
+
 <enum name="ChromeNotifierServiceActionType">
   <int value="0" label="Unknown"/>
   <int value="1" label="First service enabled"/>
@@ -37463,6 +37477,14 @@
   <int value="1" label="Leave the current page"/>
 </enum>
 
+<enum name="StrongPopupBlockerAction">
+  <int value="0" label="Navigation commit"/>
+  <int value="1" label="Commit warn site"/>
+  <int value="2" label="Commit enforced site"/>
+  <int value="3" label="Popup considered"/>
+  <int value="4" label="Popup blocked"/>
+</enum>
+
 <enum name="StyleSheetCacheStatus">
   <int value="0" label="No usable cache found"/>
   <int value="1" label="DiskCache served the CSS source"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index af3f7d49..984eca5 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -688,6 +688,43 @@
   <summary>The reason the bottom sheet was opened.</summary>
 </histogram>
 
+<histogram name="Android.ChromeHome.Promo.Result.Menu"
+    enum="ChromeHomePromoResult">
+  <owner>mdjones@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    The result of showing the Chrome Home promo when launched from the overflow
+    menu. This action can only be performed if Chrome Home is enabled.
+  </summary>
+</histogram>
+
+<histogram name="Android.ChromeHome.Promo.Result.NTP"
+    enum="ChromeHomePromoResult">
+  <owner>mdjones@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    The result of showing the Chrome Home promo when launched from the NTP. This
+    action can only be performed if Chrome Home is disabled.
+  </summary>
+</histogram>
+
+<histogram name="Android.ChromeHome.Promo.Result.Startup"
+    enum="ChromeHomePromoResult">
+  <owner>mdjones@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    The result of showing the Chrome Home promo when launched from startup. This
+    action can only be performed if Chrome Home is disabled.
+  </summary>
+</histogram>
+
+<histogram name="Android.ChromeHome.Promo.ShowReason"
+    enum="ChromeHomePromoShowReason">
+  <owner>mdjones@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>The reason the Chrome Home promo was shown.</summary>
+</histogram>
+
 <histogram name="Android.ChromeHome.TimeBetweenCloseAndNextOpen" units="ms">
   <owner>mdjones@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
@@ -706,6 +743,18 @@
   </summary>
 </histogram>
 
+<histogram name="Android.ChromeHome.UserPreference.Enabled"
+    enum="BooleanEnabled">
+  <owner>mdjones@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    Records whether or not the user preference for Chrome Home is set to
+    enabled. This is recorded whenever the browser is restarted and the state of
+    Chrome Home is first checked. This metric is only recorded if the user's
+    preference is set.
+  </summary>
+</histogram>
+
 <histogram name="Android.CompressedResources.ExtractionBlockingTime" units="ms">
   <owner>estevenson@chromium.org</owner>
   <owner>agrieve@chromium.org</owner>
@@ -10537,6 +10586,15 @@
   </summary>
 </histogram>
 
+<histogram name="ContentSettings.Popups.StrongBlockerActions"
+    enum="StrongPopupBlockerAction">
+  <owner>csharrison@chromium.org</owner>
+  <summary>
+    Counts of various events related to the strong popup blocker (aka abusive
+    experience enforcement), that is triggered via safe browsing.
+  </summary>
+</histogram>
+
 <histogram name="ContentSuggestions.FetchPendingPlaceholder.VisibleDuration"
     units="ms">
   <obsolete>
@@ -85615,6 +85673,14 @@
   </summary>
 </histogram>
 
+<histogram name="ThirdPartyModules.InputMethodEditorsCount" units="counts">
+  <owner>pmonette@chromium.org</owner>
+  <summary>
+    The number of registered input method editors found on the user's machine.
+    This is emitted shortly after startup when the IME enumeration takes place.
+  </summary>
+</histogram>
+
 <histogram name="ThirdPartyModules.InstalledPrograms.DataSize" units="KB">
   <owner>pmonette@chromium.org</owner>
   <summary>
@@ -85686,7 +85752,9 @@
 <histogram name="ThirdPartyModules.ShellExtensionsCount" units="counts">
   <owner>pmonette@chromium.org</owner>
   <summary>
-    The number of registered shell extensions found on the user's machine.
+    The number of registered shell extensions found on the user's machine. This
+    is emitted shortly after startup when the shell extensions enumeration takes
+    place.
   </summary>
 </histogram>
 
diff --git a/ui/aura/mus/input_method_mus.cc b/ui/aura/mus/input_method_mus.cc
index d44addb..3659d86 100644
--- a/ui/aura/mus/input_method_mus.cc
+++ b/ui/aura/mus/input_method_mus.cc
@@ -115,7 +115,9 @@
 }
 
 bool InputMethodMus::IsCandidatePopupOpen() const {
-  return text_input_client_->is_candidate_window_visible();
+  // TODO(moshayedi): crbug.com/637416. Implement this properly when we have a
+  // mean for displaying candidate list popup.
+  return false;
 }
 
 ui::EventDispatchDetails InputMethodMus::SendKeyEventToInputMethod(
diff --git a/ui/aura/mus/text_input_client_impl.cc b/ui/aura/mus/text_input_client_impl.cc
index 1dffea77..9f926a77 100644
--- a/ui/aura/mus/text_input_client_impl.cc
+++ b/ui/aura/mus/text_input_client_impl.cc
@@ -58,8 +58,4 @@
   }
 }
 
-void TextInputClientImpl::SetCandidateWindowVisible(bool visible) {
-  is_candidate_window_visible_ = visible;
-}
-
 }  // namespace aura
diff --git a/ui/aura/mus/text_input_client_impl.h b/ui/aura/mus/text_input_client_impl.h
index 61dac78..46bf153 100644
--- a/ui/aura/mus/text_input_client_impl.h
+++ b/ui/aura/mus/text_input_client_impl.h
@@ -24,10 +24,6 @@
                       ui::internal::InputMethodDelegate* delegate);
   ~TextInputClientImpl() override;
 
-  bool is_candidate_window_visible() const {
-    return is_candidate_window_visible_;
-  }
-
   ui::mojom::TextInputClientPtr CreateInterfacePtrAndBind();
 
  private:
@@ -40,12 +36,10 @@
   void DispatchKeyEventPostIME(
       std::unique_ptr<ui::Event> event,
       DispatchKeyEventPostIMECallback callback) override;
-  void SetCandidateWindowVisible(bool visible) override;
 
   ui::TextInputClient* text_input_client_;
   mojo::Binding<ui::mojom::TextInputClient> binding_;
   ui::internal::InputMethodDelegate* delegate_;
-  bool is_candidate_window_visible_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(TextInputClientImpl);
 };
diff --git a/ui/aura/mus/window_tree_client.h b/ui/aura/mus/window_tree_client.h
index f650f8a..8a192401 100644
--- a/ui/aura/mus/window_tree_client.h
+++ b/ui/aura/mus/window_tree_client.h
@@ -121,7 +121,6 @@
   void DisableDragDropClient() { install_drag_drop_client_ = false; }
 
   service_manager::Connector* connector() { return connector_; }
-  ui::Gpu* gpu() { return gpu_.get(); }
   CaptureSynchronizer* capture_synchronizer() {
     return capture_synchronizer_.get();
   }
diff --git a/ui/base/ime/chromeos/ime_candidate_window_handler_interface.h b/ui/base/ime/chromeos/ime_candidate_window_handler_interface.h
index 86d8c06..3d4cb91 100644
--- a/ui/base/ime/chromeos/ime_candidate_window_handler_interface.h
+++ b/ui/base/ime/chromeos/ime_candidate_window_handler_interface.h
@@ -43,9 +43,6 @@
   // |is_focused| is true when the text field gains the focus.
   virtual void FocusStateChanged(bool is_focused) {}
 
-  // Called when candidate window changes visibility.
-  virtual void OnCandidateWindowVisibilityChanged(bool visible) {}
-
  protected:
   IMECandidateWindowHandlerInterface() {}
 };
diff --git a/ui/base/ime/chromeos/mock_ime_candidate_window_handler.cc b/ui/base/ime/chromeos/mock_ime_candidate_window_handler.cc
index 8d5e26b..9ea728c 100644
--- a/ui/base/ime/chromeos/mock_ime_candidate_window_handler.cc
+++ b/ui/base/ime/chromeos/mock_ime_candidate_window_handler.cc
@@ -4,14 +4,11 @@
 
 #include "ui/base/ime/chromeos/mock_ime_candidate_window_handler.h"
 
-#include "ui/base/ime/ime_bridge.h"
-
 namespace chromeos {
 
 MockIMECandidateWindowHandler::MockIMECandidateWindowHandler()
     : set_cursor_bounds_call_count_(0),
       update_lookup_table_call_count_(0) {
-  ui::IMEBridge::Get()->SetCandidateWindowHandler(this);
 }
 
 MockIMECandidateWindowHandler::~MockIMECandidateWindowHandler() {
@@ -37,11 +34,6 @@
   ++set_cursor_bounds_call_count_;
 }
 
-void MockIMECandidateWindowHandler::OnCandidateWindowVisibilityChanged(
-    bool visible) {
-  is_candidate_window_visible_ = visible;
-}
-
 void MockIMECandidateWindowHandler::Reset() {
   set_cursor_bounds_call_count_ = 0;
   update_lookup_table_call_count_ = 0;
diff --git a/ui/base/ime/chromeos/mock_ime_candidate_window_handler.h b/ui/base/ime/chromeos/mock_ime_candidate_window_handler.h
index 273fdcee..8250848 100644
--- a/ui/base/ime/chromeos/mock_ime_candidate_window_handler.h
+++ b/ui/base/ime/chromeos/mock_ime_candidate_window_handler.h
@@ -37,7 +37,6 @@
                          bool visible) override;
   void SetCursorBounds(const gfx::Rect& cursor_bounds,
                        const gfx::Rect& composition_head) override;
-  void OnCandidateWindowVisibilityChanged(bool visible) override;
 
   int set_cursor_bounds_call_count() const {
     return set_cursor_bounds_call_count_;
@@ -50,18 +49,12 @@
   const UpdateLookupTableArg& last_update_lookup_table_arg() {
     return last_update_lookup_table_arg_;
   }
-
-  int is_candidate_window_visible() const {
-    return is_candidate_window_visible_;
-  }
-
   // Resets all call count.
   void Reset();
 
  private:
   int set_cursor_bounds_call_count_;
   int update_lookup_table_call_count_;
-  bool is_candidate_window_visible_ = false;
   UpdateLookupTableArg last_update_lookup_table_arg_;
 };
 
diff --git a/ui/views/layout/grid_layout.cc b/ui/views/layout/grid_layout.cc
index 0775b73..e8df98e9 100644
--- a/ui/views/layout/grid_layout.cc
+++ b/ui/views/layout/grid_layout.cc
@@ -4,8 +4,8 @@
 
 #include "ui/views/layout/grid_layout.h"
 
-#include "base/logging.h"
-#include "base/macros.h"
+#include <cmath>
+
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
 #include "ui/views/border.h"
@@ -14,6 +14,23 @@
 #include "ui/views/window/dialog_delegate.h"
 
 namespace views {
+namespace {
+
+// Used when calculating the minimum size to build up how much each column is
+// shrunk.
+struct ColumnMinResizeData {
+  // The column being resized.
+  Column* column;
+
+  // The remaining amount of space available (the difference between the
+  // preferred and minimum).
+  int available = 0;
+
+  // How much to shrink the preferred by.
+  int delta = 0;
+};
+
+}  // namespace
 
 // LayoutElement ------------------------------------------------------
 
@@ -176,6 +193,7 @@
   GridLayout::Alignment h_align() { return h_align_; }
   GridLayout::Alignment v_align() { return v_align_; }
 
+  // LayoutElement:
   void ResetSize() override;
 
  private:
@@ -305,9 +323,16 @@
 // Identifies the location in the grid of a particular view, along with
 // placement information and size information.
 struct ViewState {
-  ViewState(ColumnSet* column_set, View* view, int start_col, int start_row,
-            int col_span, int row_span, GridLayout::Alignment h_align,
-            GridLayout::Alignment v_align, int pref_width, int pref_height)
+  ViewState(ColumnSet* column_set,
+            View* view,
+            int start_col,
+            int start_row,
+            int col_span,
+            int row_span,
+            GridLayout::Alignment h_align,
+            GridLayout::Alignment v_align,
+            int pref_width,
+            int pref_height)
       : column_set(column_set),
         view(view),
         start_col(start_col),
@@ -318,11 +343,8 @@
         v_align(v_align),
         pref_width_fixed(pref_width > 0),
         pref_height_fixed(pref_height > 0),
-        pref_width(pref_width),
-        pref_height(pref_height),
-        remaining_width(0),
-        remaining_height(0),
-        baseline(-1) {
+        width(pref_width),
+        height(pref_height) {
     DCHECK(view && start_col >= 0 && start_row >= 0 && col_span > 0 &&
            row_span > 0 && start_col < column_set->num_columns() &&
            (start_col + col_span) <= column_set->num_columns());
@@ -337,23 +359,29 @@
   const GridLayout::Alignment h_align;
   const GridLayout::Alignment v_align;
 
-  // If true, the pref_width/pref_height were explicitly set and the view's
-  // preferred size is ignored.
+  // If true, the height/width were explicitly set and the view's preferred and
+  // minimum size is ignored.
   const bool pref_width_fixed;
   const bool pref_height_fixed;
 
-  // The preferred width/height. These are reset during the layout process.
-  int pref_width;
-  int pref_height;
+  // The width/height. This is one of possible three values:
+  // . an explicitly set value (if pref_X_fixed is true). If an explicitly set
+  //   value was provided, then this value never changes.
+  // . the preferred width.
+  // . the minimum width.
+  // If the value wasn't explicitly set, then whether the value is the preferred
+  // or minimum depends upon the pass.
+  int width;
+  int height;
 
   // Used during layout. Gives how much width/height has not yet been
   // distributed to the columns/rows the view is in.
-  int remaining_width;
-  int remaining_height;
+  int remaining_width = 0;
+  int remaining_height = 0;
 
   // The baseline. Only used if the view is vertically aligned along the
   // baseline.
-  int baseline;
+  int baseline = -1;
 };
 
 static bool CompareByColumnSpan(const ViewState* v1, const ViewState* v2) {
@@ -579,22 +607,39 @@
   LayoutElement::CalculateLocationsFromSize(&columns_);
 }
 
-void ColumnSet::CalculateSize() {
-  gfx::Size pref;
-  // Reset the preferred and remaining sizes.
+void ColumnSet::CalculateSize(SizeCalculationType type) {
+#if DCHECK_IS_ON()
+  // SizeCalculationType::MINIMUM must be preceeded by a request for
+  // SizeCalculationType::PREFERRED.
+  DCHECK(type == SizeCalculationType::PREFERRED ||
+         last_calculation_type_ == PREFERRED);
+  last_calculation_type_ = type;
+#endif
+  // Reset the size and remaining sizes.
   for (auto* view_state : view_states_) {
     if (!view_state->pref_width_fixed || !view_state->pref_height_fixed) {
-      pref = view_state->view->GetPreferredSize();
+      gfx::Size size;
+      if (type == SizeCalculationType::MINIMUM && CanUseMinimum(*view_state)) {
+        // If the min size is bigger than the preferred, use the preferred.
+        // This relies on MINIMUM being calculated immediately after PREFERRED,
+        // which the rest of this code relies on as well.
+        size = view_state->view->GetMinimumSize();
+        if (size.width() > view_state->width)
+          size.set_width(view_state->width);
+        if (size.height() > view_state->height)
+          size.set_height(view_state->height);
+      } else {
+        size = view_state->view->GetPreferredSize();
+      }
       if (!view_state->pref_width_fixed)
-        view_state->pref_width = pref.width();
+        view_state->width = size.width();
       if (!view_state->pref_height_fixed)
-        view_state->pref_height = pref.height();
+        view_state->height = size.height();
     }
-    view_state->remaining_width = pref.width();
-    view_state->remaining_height = pref.height();
+    view_state->remaining_width = view_state->width;
+    view_state->remaining_height = view_state->height;
   }
 
-  // Let layout element reset the sizes for us.
   LayoutElement::ResetSizes(&columns_);
 
   // Distribute the size of each view with a col span == 1.
@@ -603,7 +648,7 @@
          (*view_state_iterator)->col_span == 1; ++view_state_iterator) {
     ViewState* view_state = *view_state_iterator;
     Column* column = columns_[view_state->start_col].get();
-    column->AdjustSize(view_state->pref_width);
+    column->AdjustSize(view_state->width);
     view_state->remaining_width -= column->Size();
   }
 
@@ -626,10 +671,103 @@
   }
 }
 
-void ColumnSet::Resize(int delta) {
+void ColumnSet::Resize(int delta, bool honors_min_width) {
+  if (delta < 0 && honors_min_width) {
+    // DistributeDelta() assumes resizable columns can equally be shrunk. That
+    // isn't desired when given a size smaller than the prefered. Instead the
+    // columns need to be resized but bounded by the minimum. ResizeUsingMin()
+    // does this.
+    ResizeUsingMin(delta);
+    return;
+  }
+
   LayoutElement::DistributeDelta(delta, &columns_);
 }
 
+void ColumnSet::ResizeUsingMin(int total_delta) {
+  DCHECK_LE(total_delta, 0);
+
+  // |total_delta| is negative, but easier to do operations when positive.
+  total_delta = std::abs(total_delta);
+
+  std::vector<int> preferred_column_sizes(columns_.size());
+  for (size_t i = 0; i < columns_.size(); ++i)
+    preferred_column_sizes[i] = columns_[i]->Size();
+
+  // Recalculate the sizes using the min.
+  CalculateSize(ColumnSet::SizeCalculationType::MINIMUM);
+
+  // Build up the set of columns that can be shrunk in |resize_data|, this
+  // iteration also resets the size of the column back to the preferred size.
+  std::vector<ColumnMinResizeData> resize_data;
+  float total_percent = 0;
+  for (size_t i = 0; i < columns_.size(); ++i) {
+    Column* column = columns_[i].get();
+    const int available =
+        std::max(0, preferred_column_sizes[i] -
+                        std::max(column->min_width_, column->Size()));
+    DCHECK_GE(available, 0);
+    // Set the size back to preferred. We'll reset the size if necessary later.
+    column->SetSize(preferred_column_sizes[i]);
+    if (column->ResizePercent() <= 0 || available == 0)
+      continue;
+    resize_data.push_back({column, available, 0});
+    total_percent += column->ResizePercent();
+  }
+  if (resize_data.empty())
+    return;
+
+  // Loop through the columns updating the amount available and the amount to
+  // resize. This may take multiple iterations if the column min is hit.
+  // Generally there are not that many columns in a GridLayout, so this code is
+  // not optimized. Any time the column hits the min it is removed from
+  // |resize_data|.
+  while (!resize_data.empty() && total_delta > 0) {
+    float next_iteration_total_percent = total_percent;
+    int next_iteration_delta = total_delta;
+#if DCHECK_IS_ON()
+    const int initial_delta = total_delta;
+#endif
+    for (size_t i = resize_data.size(); i > 0; --i) {
+      ColumnMinResizeData& data = resize_data[i - 1];
+      int delta =
+          std::min(data.available,
+                   static_cast<int>(total_delta * data.column->ResizePercent() /
+                                    total_percent));
+      // Make sure at least one column in resized (rounding errors may prevent
+      // that).
+      if (i == 1 && delta == 0 && next_iteration_delta == total_delta)
+        delta = 1;
+      next_iteration_delta -= delta;
+      data.delta += delta;
+      data.available -= delta;
+      if (data.available == 0) {
+        data.column->SetSize(data.column->Size() - data.delta);
+        next_iteration_total_percent -= data.column->ResizePercent();
+        resize_data.erase(resize_data.begin() + (i - 1));
+      }
+    }
+#if DCHECK_IS_ON()
+    DCHECK(next_iteration_delta < initial_delta);
+#endif
+    total_delta = next_iteration_delta;
+    total_percent = next_iteration_total_percent;
+  }
+
+  for (const ColumnMinResizeData& data : resize_data)
+    data.column->SetSize(data.column->Size() - data.delta);
+}
+
+bool ColumnSet::CanUseMinimum(const ViewState& view_state) const {
+  for (int i = 0; i < view_state.col_span; ++i) {
+    if (columns_[i + view_state.start_col]->ResizePercent() <= 0 ||
+        columns_[i + view_state.start_col]->size_type_ == GridLayout::FIXED) {
+      return false;
+    }
+  }
+  return true;
+}
+
 // GridLayout -------------------------------------------------------------
 
 // static
@@ -766,16 +904,15 @@
         column_set->columns_[view_state->start_col]->Location() + insets.left();
     int width = column_set->GetColumnWidth(view_state->start_col,
                                            view_state->col_span);
-    CalculateSize(view_state->pref_width, view_state->h_align,
-                  &x, &width);
+    CalculateSize(view_state->width, view_state->h_align, &x, &width);
     int y = rows_[view_state->start_row]->Location() + insets.top();
     int height = LayoutElement::TotalSize(view_state->start_row,
                                           view_state->row_span, &rows_);
     if (view_state->v_align == BASELINE && view_state->baseline != -1) {
       y += rows_[view_state->start_row]->max_ascent() - view_state->baseline;
-      height = view_state->pref_height;
+      height = view_state->height;
     } else {
-      CalculateSize(view_state->pref_height, view_state->v_align, &y, &height);
+      CalculateSize(view_state->height, view_state->v_align, &y, &height);
     }
     view->SetBounds(x, y, width, height);
   }
@@ -825,7 +962,7 @@
   // preferred heights are derived from their width, as such we need to
   // calculate the size of the columns first.
   for (const auto& column_set : column_sets_) {
-    column_set->CalculateSize();
+    column_set->CalculateSize(ColumnSet::SizeCalculationType::PREFERRED);
     pref->set_width(std::max(pref->width(), column_set->LayoutWidth()));
   }
   const gfx::Insets& insets = host_->GetInsets();
@@ -835,8 +972,8 @@
   width = width ? width : pref->width();
   for (const auto& column_set : column_sets_) {
     // We're doing a layout, divvy up any extra space.
-    column_set->Resize(width - column_set->LayoutWidth() - insets.left() -
-                       insets.right());
+    column_set->Resize(width - column_set->LayoutWidth() - insets.width(),
+                       honors_min_width_);
     // And reset the x coordinates.
     column_set->ResetColumnXCoordinates();
   }
@@ -851,7 +988,7 @@
   // . If the width the view will be given is different than it's pref, ask
   //   for the height given a particularly width.
   for (const auto& view_state : view_states_) {
-    view_state->remaining_height = view_state->pref_height;
+    view_state->remaining_height = view_state->height;
 
     if (view_state->v_align == BASELINE)
       view_state->baseline = view_state->view->GetBaseline();
@@ -862,13 +999,11 @@
       int actual_width =
           view_state->column_set->GetColumnWidth(view_state->start_col,
                                                  view_state->col_span);
-      if (actual_width != view_state->pref_width &&
-          !view_state->pref_height_fixed) {
+      if (actual_width != view_state->width && !view_state->pref_height_fixed) {
         // The width this view will get differs from its preferred. Some Views
         // pref height varies with its width; ask for the preferred again.
-        view_state->pref_height =
-            view_state->view->GetHeightForWidth(actual_width);
-        view_state->remaining_height = view_state->pref_height;
+        view_state->height = view_state->view->GetHeightForWidth(actual_width);
+        view_state->remaining_height = view_state->height;
       }
     }
   }
@@ -881,9 +1016,9 @@
     Row* row = rows_[view_state->start_row].get();
     row->AdjustSize(view_state->remaining_height);
     if (view_state->baseline != -1 &&
-        view_state->baseline <= view_state->pref_height) {
+        view_state->baseline <= view_state->height) {
       row->AdjustSizeForBaseline(view_state->baseline,
-          view_state->pref_height - view_state->baseline);
+                                 view_state->height - view_state->baseline);
     }
     view_state->remaining_height = 0;
   }
diff --git a/ui/views/layout/grid_layout.h b/ui/views/layout/grid_layout.h
index a2521d4..9028ed69 100644
--- a/ui/views/layout/grid_layout.h
+++ b/ui/views/layout/grid_layout.h
@@ -10,6 +10,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/logging.h"
 #include "base/macros.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/views/layout/layout_manager.h"
@@ -57,8 +58,14 @@
 // GridLayout allows you to force columns to have the same width. This is
 // done using the LinkColumnSizes method.
 //
-// AddView takes care of adding the View to the View the GridLayout was
+// AddView() takes care of adding the View to the View the GridLayout was
 // created with.
+//
+// If the host View is sized smaller than the preferred width and
+// set_honors_min_width(true) is called, GridLayout may use the minimum size.
+// The minimum size is considered only for Views whose preferred width was not
+// explicitly specified and the containing columns are resizable
+// (resize_percent > 0) and don't have a fixed width.
 namespace views {
 
 class Column;
@@ -105,6 +112,11 @@
 
   ~GridLayout() override;
 
+  // See class description for what this does.
+  // TODO(sky): investigate making this the default, problem is it has subtle
+  // effects on the layout and some code is relying on old behavior.
+  void set_honors_min_width(bool value) { honors_min_width_ = value; }
+
   // Creates a new column set with the specified id and returns it.
   // The id is later used when starting a new row.
   // GridLayout takes ownership of the ColumnSet and will delete it when
@@ -250,6 +262,8 @@
   // Minimum preferred size.
   gfx::Size minimum_size_;
 
+  bool honors_min_width_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(GridLayout);
 };
 
@@ -343,12 +357,26 @@
   // NOTE: this doesn't include the insets.
   void ResetColumnXCoordinates();
 
+  enum SizeCalculationType {
+    PREFERRED,
+    MINIMUM,
+  };
+
   // Calculate the preferred width of each view in this column set, as well
   // as updating the remaining_width.
-  void CalculateSize();
+  void CalculateSize(SizeCalculationType type);
 
-  // Distributes delta among the resizable columns.
-  void Resize(int delta);
+  // Distributes delta among the resizable columns. |honors_min_width| matches
+  // that of |GridLayout::honors_min_width_|.
+  void Resize(int delta, bool honors_min_width);
+
+  // Used when GridLayout is given a size smaller than the preferred width.
+  // |total_delta| is negative and the difference between the preferred width
+  // and the target width.
+  void ResizeUsingMin(int total_delta);
+
+  // Only use the minimum size if all the columns the view is in are resizable.
+  bool CanUseMinimum(const ViewState& view_state) const;
 
   // ID for this columnset.
   const int id_;
@@ -368,6 +396,10 @@
   // for a description of what the master column is.
   std::vector<Column*> master_columns_;
 
+#if DCHECK_IS_ON()
+  SizeCalculationType last_calculation_type_ = SizeCalculationType::PREFERRED;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(ColumnSet);
 };
 
diff --git a/ui/views/layout/grid_layout_unittest.cc b/ui/views/layout/grid_layout_unittest.cc
index 686eefb..31bc7c6 100644
--- a/ui/views/layout/grid_layout_unittest.cc
+++ b/ui/views/layout/grid_layout_unittest.cc
@@ -27,6 +27,27 @@
   return view;
 }
 
+// View that lets you set the minimum size.
+class MinSizeView : public View {
+ public:
+  explicit MinSizeView(const gfx::Size& min_size) : min_size_(min_size) {}
+  ~MinSizeView() override = default;
+
+  // View:
+  gfx::Size GetMinimumSize() const override { return min_size_; }
+
+ private:
+  const gfx::Size min_size_;
+
+  DISALLOW_COPY_AND_ASSIGN(MinSizeView);
+};
+
+View* CreateViewWithMinAndPref(const gfx::Size& min, const gfx::Size& pref) {
+  MinSizeView* view = new MinSizeView(min);
+  view->SetPreferredSize(pref);
+  return view;
+}
+
 // A test view that wants to alter its preferred size and re-layout when it gets
 // added to the View hierarchy.
 class LayoutOnAddView : public View {
@@ -825,4 +846,181 @@
   RemoveAll();
 }
 
+TEST_F(GridLayoutTest, ColumnMinForcesPreferredWidth) {
+  // Column's min width is greater than views preferred/min width. This should
+  // force the preferred width to the min width of the column.
+  ColumnSet* set = layout()->AddColumnSet(0);
+  set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5, GridLayout::USE_PREF, 0,
+                 100);
+  layout()->StartRow(0, 0);
+  View* view1 = CreateSizedView(gfx::Size(20, 10));
+  layout()->AddView(view1);
+
+  EXPECT_EQ(gfx::Size(100, 10), GetPreferredSize());
+}
+
+TEST_F(GridLayoutTest, HonorsColumnMin) {
+  layout()->set_honors_min_width(true);
+
+  // Verifies that a column with a min width is never shrunk smaller than the
+  // minw width.
+  ColumnSet* set = layout()->AddColumnSet(0);
+  set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5, GridLayout::USE_PREF, 0,
+                 100);
+  set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5, GridLayout::USE_PREF, 0,
+                 0);
+  layout()->StartRow(0, 0);
+  View* view1 = CreateViewWithMinAndPref(gfx::Size(10, 10), gfx::Size(125, 10));
+  layout()->AddView(view1);
+
+  View* view2 = CreateViewWithMinAndPref(gfx::Size(10, 10), gfx::Size(50, 10));
+  layout()->AddView(view2);
+
+  EXPECT_EQ(gfx::Size(175, 10), GetPreferredSize());
+
+  host().SetBounds(0, 0, 175, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 125, 10), view1->bounds());
+  EXPECT_EQ(gfx::Rect(125, 0, 50, 10), view2->bounds());
+
+  host().SetBounds(0, 0, 125, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 10), view1->bounds());
+  EXPECT_EQ(gfx::Rect(100, 0, 25, 10), view2->bounds());
+
+  host().SetBounds(0, 0, 120, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 10), view1->bounds());
+  EXPECT_EQ(gfx::Rect(100, 0, 20, 10), view2->bounds());
+}
+
+TEST_F(GridLayoutTest, TwoViewsOneSizeSmallerThanMinimum) {
+  layout()->set_honors_min_width(true);
+  // Two columns, equally resizable with two views. Only the first view is
+  // resizable.
+  ColumnSet* set = layout()->AddColumnSet(0);
+  set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5, GridLayout::USE_PREF, 0,
+                 0);
+  set->AddColumn(GridLayout::FILL, GridLayout::FILL, 5, GridLayout::USE_PREF, 0,
+                 0);
+  layout()->StartRow(0, 0);
+  View* view1 = CreateViewWithMinAndPref(gfx::Size(20, 10), gfx::Size(100, 10));
+  layout()->AddView(view1);
+
+  View* view2 =
+      CreateViewWithMinAndPref(gfx::Size(100, 10), gfx::Size(100, 10));
+  layout()->AddView(view2);
+
+  host().SetBounds(0, 0, 110, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 20, 10), view1->bounds());
+  EXPECT_EQ(gfx::Rect(20, 0, 100, 10), view2->bounds());
+}
+
+TEST_F(GridLayoutTest, TwoViewsBothSmallerThanMinimumDifferentResizeWeights) {
+  layout()->set_honors_min_width(true);
+  // Two columns, equally resizable with two views. Only the first view is
+  // resizable.
+  ColumnSet* set = layout()->AddColumnSet(0);
+  set->AddColumn(GridLayout::FILL, GridLayout::FILL, 8, GridLayout::USE_PREF, 0,
+                 0);
+  set->AddColumn(GridLayout::FILL, GridLayout::FILL, 2, GridLayout::USE_PREF, 0,
+                 0);
+  layout()->StartRow(0, 0);
+  View* view1 = CreateViewWithMinAndPref(gfx::Size(91, 10), gfx::Size(100, 10));
+  layout()->AddView(view1);
+
+  View* view2 = CreateViewWithMinAndPref(gfx::Size(10, 10), gfx::Size(100, 10));
+  layout()->AddView(view2);
+
+  // 200 is the preferred, each should get their preferred width.
+  host().SetBounds(0, 0, 200, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 10), view1->bounds());
+  EXPECT_EQ(gfx::Rect(100, 0, 100, 10), view2->bounds());
+
+  // 1 pixel smaller than pref.
+  host().SetBounds(0, 0, 199, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 99, 10), view1->bounds());
+  EXPECT_EQ(gfx::Rect(99, 0, 100, 10), view2->bounds());
+
+  // 10 pixels smaller than pref.
+  host().SetBounds(0, 0, 190, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 92, 10), view1->bounds());
+  EXPECT_EQ(gfx::Rect(92, 0, 98, 10), view2->bounds());
+
+  // 11 pixels smaller than pref.
+  host().SetBounds(0, 0, 189, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 91, 10), view1->bounds());
+  EXPECT_EQ(gfx::Rect(91, 0, 98, 10), view2->bounds());
+
+  // 12 pixels smaller than pref.
+  host().SetBounds(0, 0, 188, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 91, 10), view1->bounds());
+  EXPECT_EQ(gfx::Rect(91, 0, 97, 10), view2->bounds());
+
+  host().SetBounds(0, 0, 5, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 91, 10), view1->bounds());
+  EXPECT_EQ(gfx::Rect(91, 0, 10, 10), view2->bounds());
+}
+
+TEST_F(GridLayoutTest, TwoViewsOneColumnUsePrefOtherFixed) {
+  layout()->set_honors_min_width(true);
+  ColumnSet* set = layout()->AddColumnSet(0);
+  set->AddColumn(GridLayout::FILL, GridLayout::FILL, 8, GridLayout::USE_PREF, 0,
+                 0);
+  set->AddColumn(GridLayout::FILL, GridLayout::FILL, 2, GridLayout::FIXED, 100,
+                 0);
+  layout()->StartRow(0, 0);
+  View* view1 = CreateViewWithMinAndPref(gfx::Size(10, 10), gfx::Size(100, 10));
+  layout()->AddView(view1);
+  View* view2 = CreateViewWithMinAndPref(gfx::Size(10, 10), gfx::Size(100, 10));
+  layout()->AddView(view2);
+
+  host().SetBounds(0, 0, 120, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 20, 10), view1->bounds());
+  // Even though column 2 has a resize percent, it's FIXED, so it won't shrink.
+  EXPECT_EQ(gfx::Rect(20, 0, 100, 10), view2->bounds());
+
+  host().SetBounds(0, 0, 10, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 10, 10), view1->bounds());
+  EXPECT_EQ(gfx::Rect(10, 0, 100, 10), view2->bounds());
+}
+
+TEST_F(GridLayoutTest, TwoViewsBothColumnsResizableOneViewFixedWidthMin) {
+  layout()->set_honors_min_width(true);
+  ColumnSet* set = layout()->AddColumnSet(0);
+  set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, GridLayout::USE_PREF, 0,
+                 0);
+  set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, GridLayout::USE_PREF, 0,
+                 0);
+  layout()->StartRow(0, 0);
+  View* view1 = CreateViewWithMinAndPref(gfx::Size(10, 10), gfx::Size(100, 10));
+  layout()->AddView(view1);
+  View* view2 = CreateViewWithMinAndPref(gfx::Size(10, 10), gfx::Size(100, 10));
+  layout()->AddView(view2, 1, 1, GridLayout::FILL, GridLayout::FILL, 50, 10);
+
+  host().SetBounds(0, 0, 80, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 30, 10), view1->bounds());
+  EXPECT_EQ(gfx::Rect(30, 0, 50, 10), view2->bounds());
+
+  host().SetBounds(0, 0, 70, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 20, 10), view1->bounds());
+  EXPECT_EQ(gfx::Rect(20, 0, 50, 10), view2->bounds());
+
+  host().SetBounds(0, 0, 10, 0);
+  layout()->Layout(&host());
+  EXPECT_EQ(gfx::Rect(0, 0, 10, 10), view1->bounds());
+  EXPECT_EQ(gfx::Rect(10, 0, 50, 10), view2->bounds());
+}
+
 }  // namespace views
diff --git a/url/BUILD.gn b/url/BUILD.gn
index 82eb115a..d33801bc 100644
--- a/url/BUILD.gn
+++ b/url/BUILD.gn
@@ -25,6 +25,7 @@
     "scheme_host_port.h",
     "third_party/mozilla/url_parse.cc",
     "third_party/mozilla/url_parse.h",
+    "url_canon.cc",
     "url_canon.h",
     "url_canon_etc.cc",
     "url_canon_filesystemurl.cc",
diff --git a/url/url_canon.cc b/url/url_canon.cc
new file mode 100644
index 0000000..d51a317
--- /dev/null
+++ b/url/url_canon.cc
@@ -0,0 +1,12 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "url/url_canon.h"
+
+namespace url {
+
+template class EXPORT_TEMPLATE_DEFINE(URL_EXPORT) CanonOutputT<char>;
+template class EXPORT_TEMPLATE_DEFINE(URL_EXPORT) CanonOutputT<base::char16>;
+
+}  // namespace url
diff --git a/url/url_canon.h b/url/url_canon.h
index 887150b0..ede62d3 100644
--- a/url/url_canon.h
+++ b/url/url_canon.h
@@ -8,6 +8,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "base/export_template.h"
 #include "base/strings/string16.h"
 #include "url/third_party/mozilla/url_parse.h"
 #include "url/url_export.h"
@@ -174,6 +175,11 @@
   T fixed_buffer_[fixed_capacity];
 };
 
+// Explicitely instantiate commonly used instatiations.
+extern template class EXPORT_TEMPLATE_DECLARE(URL_EXPORT) CanonOutputT<char>;
+extern template class EXPORT_TEMPLATE_DECLARE(URL_EXPORT)
+    CanonOutputT<base::char16>;
+
 // Normally, all canonicalization output is in narrow characters. We support
 // the templates so it can also be used internally if a wide buffer is
 // required.